github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/ui/tests/unit/adapters/job-test.js (about)

     1  import { run } from '@ember/runloop';
     2  import { assign } from '@ember/polyfills';
     3  import { settled } from '@ember/test-helpers';
     4  import { setupTest } from 'ember-qunit';
     5  import { module, test } from 'qunit';
     6  import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
     7  import XHRToken from 'nomad-ui/utils/classes/xhr-token';
     8  
     9  module('Unit | Adapter | Job', function(hooks) {
    10    setupTest(hooks);
    11  
    12    hooks.beforeEach(async function() {
    13      this.store = this.owner.lookup('service:store');
    14      this.subject = () => this.store.adapterFor('job');
    15  
    16      window.sessionStorage.clear();
    17      window.localStorage.clear();
    18  
    19      this.server = startMirage();
    20  
    21      this.initializeUI = async () => {
    22        this.server.create('namespace');
    23        this.server.create('namespace', { id: 'some-namespace' });
    24        this.server.create('node');
    25        this.server.create('job', { id: 'job-1', namespaceId: 'default' });
    26        this.server.create('job', { id: 'job-2', namespaceId: 'some-namespace' });
    27  
    28        this.server.create('region', { id: 'region-1' });
    29        this.server.create('region', { id: 'region-2' });
    30  
    31        this.system = this.owner.lookup('service:system');
    32  
    33        // Namespace, default region, and all regions are requests that all
    34        // job requests depend on. Fetching them ahead of time means testing
    35        // job adapter behavior in isolation.
    36        await this.system.get('namespaces');
    37        this.system.get('shouldIncludeRegion');
    38        await this.system.get('defaultRegion');
    39  
    40        // Reset the handledRequests array to avoid accounting for this
    41        // namespaces request everywhere.
    42        this.server.pretender.handledRequests.length = 0;
    43      };
    44    });
    45  
    46    hooks.afterEach(function() {
    47      this.server.shutdown();
    48    });
    49  
    50    test('The job endpoint is the only required endpoint for fetching a job', async function(assert) {
    51      await this.initializeUI();
    52  
    53      const { pretender } = this.server;
    54      const jobName = 'job-1';
    55      const jobNamespace = 'default';
    56      const jobId = JSON.stringify([jobName, jobNamespace]);
    57  
    58      this.subject().findRecord(null, { modelName: 'job' }, jobId);
    59  
    60      await settled();
    61      assert.deepEqual(
    62        pretender.handledRequests.mapBy('url'),
    63        [`/v1/job/${jobName}`],
    64        'The only request made is /job/:id'
    65      );
    66    });
    67  
    68    test('When a namespace is set in localStorage but a job in the default namespace is requested, the namespace query param is not present', async function(assert) {
    69      window.localStorage.nomadActiveNamespace = 'some-namespace';
    70  
    71      await this.initializeUI();
    72  
    73      const { pretender } = this.server;
    74      const jobName = 'job-1';
    75      const jobNamespace = 'default';
    76      const jobId = JSON.stringify([jobName, jobNamespace]);
    77  
    78      this.subject().findRecord(null, { modelName: 'job' }, jobId);
    79      await settled();
    80  
    81      assert.deepEqual(
    82        pretender.handledRequests.mapBy('url'),
    83        [`/v1/job/${jobName}`],
    84        'The only request made is /job/:id with no namespace query param'
    85      );
    86    });
    87  
    88    test('When a namespace is in localStorage and the requested job is in the default namespace, the namespace query param is left out', async function(assert) {
    89      window.localStorage.nomadActiveNamespace = 'red-herring';
    90  
    91      await this.initializeUI();
    92  
    93      const { pretender } = this.server;
    94      const jobName = 'job-1';
    95      const jobNamespace = 'default';
    96      const jobId = JSON.stringify([jobName, jobNamespace]);
    97  
    98      this.subject().findRecord(null, { modelName: 'job' }, jobId);
    99      await settled();
   100  
   101      assert.deepEqual(
   102        pretender.handledRequests.mapBy('url'),
   103        [`/v1/job/${jobName}`],
   104        'The request made is /job/:id with no namespace query param'
   105      );
   106    });
   107  
   108    test('When the job has a namespace other than default, it is in the URL', async function(assert) {
   109      await this.initializeUI();
   110  
   111      const { pretender } = this.server;
   112      const jobName = 'job-2';
   113      const jobNamespace = 'some-namespace';
   114      const jobId = JSON.stringify([jobName, jobNamespace]);
   115  
   116      this.subject().findRecord(null, { modelName: 'job' }, jobId);
   117      await settled();
   118  
   119      assert.deepEqual(
   120        pretender.handledRequests.mapBy('url'),
   121        [`/v1/job/${jobName}?namespace=${jobNamespace}`],
   122        'The only request made is /job/:id?namespace=:namespace'
   123      );
   124    });
   125  
   126    test('When there is no token set in the token service, no x-nomad-token header is set', async function(assert) {
   127      await this.initializeUI();
   128  
   129      const { pretender } = this.server;
   130      const jobId = JSON.stringify(['job-1', 'default']);
   131  
   132      this.subject().findRecord(null, { modelName: 'job' }, jobId);
   133      await settled();
   134  
   135      assert.notOk(
   136        pretender.handledRequests.mapBy('requestHeaders').some(headers => headers['X-Nomad-Token']),
   137        'No token header present on either job request'
   138      );
   139    });
   140  
   141    test('When a token is set in the token service, then x-nomad-token header is set', async function(assert) {
   142      await this.initializeUI();
   143  
   144      const { pretender } = this.server;
   145      const jobId = JSON.stringify(['job-1', 'default']);
   146      const secret = 'here is the secret';
   147  
   148      this.subject().set('token.secret', secret);
   149      this.subject().findRecord(null, { modelName: 'job' }, jobId);
   150      await settled();
   151  
   152      assert.ok(
   153        pretender.handledRequests
   154          .mapBy('requestHeaders')
   155          .every(headers => headers['X-Nomad-Token'] === secret),
   156        'The token header is present on both job requests'
   157      );
   158    });
   159  
   160    test('findAll can be watched', async function(assert) {
   161      await this.initializeUI();
   162  
   163      const { pretender } = this.server;
   164  
   165      const request = () =>
   166        this.subject().findAll(null, { modelName: 'job' }, null, {
   167          reload: true,
   168          adapterOptions: { watch: true },
   169        });
   170  
   171      request();
   172      assert.equal(
   173        pretender.handledRequests[0].url,
   174        '/v1/jobs?index=1',
   175        'Second request is a blocking request for jobs'
   176      );
   177  
   178      await settled();
   179      request();
   180      assert.equal(
   181        pretender.handledRequests[1].url,
   182        '/v1/jobs?index=2',
   183        'Third request is a blocking request with an incremented index param'
   184      );
   185  
   186      await settled();
   187    });
   188  
   189    test('findRecord can be watched', async function(assert) {
   190      await this.initializeUI();
   191  
   192      const jobId = JSON.stringify(['job-1', 'default']);
   193      const { pretender } = this.server;
   194  
   195      const request = () =>
   196        this.subject().findRecord(null, { modelName: 'job' }, jobId, {
   197          reload: true,
   198          adapterOptions: { watch: true },
   199        });
   200  
   201      request();
   202      assert.equal(
   203        pretender.handledRequests[0].url,
   204        '/v1/job/job-1?index=1',
   205        'Second request is a blocking request for job-1'
   206      );
   207  
   208      await settled();
   209      request();
   210      assert.equal(
   211        pretender.handledRequests[1].url,
   212        '/v1/job/job-1?index=2',
   213        'Third request is a blocking request with an incremented index param'
   214      );
   215  
   216      await settled();
   217    });
   218  
   219    test('relationships can be reloaded', async function(assert) {
   220      await this.initializeUI();
   221  
   222      const { pretender } = this.server;
   223      const plainId = 'job-1';
   224      const mockModel = makeMockModel(plainId);
   225  
   226      this.subject().reloadRelationship(mockModel, 'summary');
   227      await settled();
   228      assert.equal(
   229        pretender.handledRequests[0].url,
   230        `/v1/job/${plainId}/summary`,
   231        'Relationship was reloaded'
   232      );
   233    });
   234  
   235    test('relationship reloads can be watched', async function(assert) {
   236      await this.initializeUI();
   237  
   238      const { pretender } = this.server;
   239      const plainId = 'job-1';
   240      const mockModel = makeMockModel(plainId);
   241  
   242      this.subject().reloadRelationship(mockModel, 'summary', { watch: true });
   243      assert.equal(
   244        pretender.handledRequests[0].url,
   245        '/v1/job/job-1/summary?index=1',
   246        'First request is a blocking request for job-1 summary relationship'
   247      );
   248  
   249      await settled();
   250      this.subject().reloadRelationship(mockModel, 'summary', { watch: true });
   251      await settled();
   252  
   253      assert.equal(
   254        pretender.handledRequests[1].url,
   255        '/v1/job/job-1/summary?index=2',
   256        'Second request is a blocking request with an incremented index param'
   257      );
   258    });
   259  
   260    test('findAll can be canceled', async function(assert) {
   261      await this.initializeUI();
   262  
   263      const { pretender } = this.server;
   264      const token = new XHRToken();
   265  
   266      pretender.get('/v1/jobs', () => [200, {}, '[]'], true);
   267  
   268      this.subject()
   269        .findAll(null, { modelName: 'job' }, null, {
   270          reload: true,
   271          adapterOptions: { watch: true, abortToken: token },
   272        })
   273        .catch(() => {});
   274  
   275      const { request: xhr } = pretender.requestReferences[0];
   276      assert.equal(xhr.status, 0, 'Request is still pending');
   277  
   278      // Schedule the cancelation before waiting
   279      run.next(() => {
   280        token.abort();
   281      });
   282  
   283      await settled();
   284      assert.ok(xhr.aborted, 'Request was aborted');
   285    });
   286  
   287    test('findRecord can be canceled', async function(assert) {
   288      await this.initializeUI();
   289  
   290      const { pretender } = this.server;
   291      const jobId = JSON.stringify(['job-1', 'default']);
   292      const token = new XHRToken();
   293  
   294      pretender.get('/v1/job/:id', () => [200, {}, '{}'], true);
   295  
   296      this.subject().findRecord(null, { modelName: 'job' }, jobId, {
   297        reload: true,
   298        adapterOptions: { watch: true, abortToken: token },
   299      });
   300  
   301      const { request: xhr } = pretender.requestReferences[0];
   302      assert.equal(xhr.status, 0, 'Request is still pending');
   303  
   304      // Schedule the cancelation before waiting
   305      run.next(() => {
   306        token.abort();
   307      });
   308  
   309      await settled();
   310      assert.ok(xhr.aborted, 'Request was aborted');
   311    });
   312  
   313    test('relationship reloads can be canceled', async function(assert) {
   314      await this.initializeUI();
   315  
   316      const { pretender } = this.server;
   317      const plainId = 'job-1';
   318      const token = new XHRToken();
   319      const mockModel = makeMockModel(plainId);
   320      pretender.get('/v1/job/:id/summary', () => [200, {}, '{}'], true);
   321  
   322      this.subject().reloadRelationship(mockModel, 'summary', { watch: true, abortToken: token });
   323  
   324      const { request: xhr } = pretender.requestReferences[0];
   325      assert.equal(xhr.status, 0, 'Request is still pending');
   326  
   327      // Schedule the cancelation before waiting
   328      run.next(() => {
   329        token.abort();
   330      });
   331  
   332      await settled();
   333      assert.ok(xhr.aborted, 'Request was aborted');
   334    });
   335  
   336    test('requests can be canceled even if multiple requests for the same URL were made', async function(assert) {
   337      await this.initializeUI();
   338  
   339      const { pretender } = this.server;
   340      const jobId = JSON.stringify(['job-1', 'default']);
   341      const token1 = new XHRToken();
   342      const token2 = new XHRToken();
   343  
   344      pretender.get('/v1/job/:id', () => [200, {}, '{}'], true);
   345  
   346      this.subject().findRecord(null, { modelName: 'job' }, jobId, {
   347        reload: true,
   348        adapterOptions: { watch: true, abortToken: token1 },
   349      });
   350  
   351      this.subject().findRecord(null, { modelName: 'job' }, jobId, {
   352        reload: true,
   353        adapterOptions: { watch: true, abortToken: token2 },
   354      });
   355  
   356      const { request: xhr } = pretender.requestReferences[0];
   357      const { request: xhr2 } = pretender.requestReferences[1];
   358      assert.equal(xhr.status, 0, 'Request is still pending');
   359      assert.equal(pretender.requestReferences.length, 2, 'Two findRecord requests were made');
   360      assert.equal(
   361        pretender.requestReferences.mapBy('url').uniq().length,
   362        1,
   363        'The two requests have the same URL'
   364      );
   365  
   366      // Schedule the cancelation and resolution before waiting
   367      run.next(() => {
   368        token1.abort();
   369        pretender.resolve(xhr2);
   370      });
   371  
   372      await settled();
   373      assert.ok(xhr.aborted, 'Request one was aborted');
   374      assert.notOk(xhr2.aborted, 'Request two was not aborted');
   375    });
   376  
   377    test('when there is no region set, requests are made without the region query param', async function(assert) {
   378      await this.initializeUI();
   379  
   380      const { pretender } = this.server;
   381      const jobName = 'job-1';
   382      const jobNamespace = 'default';
   383      const jobId = JSON.stringify([jobName, jobNamespace]);
   384  
   385      await settled();
   386      this.subject().findRecord(null, { modelName: 'job' }, jobId);
   387      this.subject().findAll(null, { modelName: 'job' }, null);
   388      await settled();
   389  
   390      assert.deepEqual(
   391        pretender.handledRequests.mapBy('url'),
   392        [`/v1/job/${jobName}`, '/v1/jobs'],
   393        'No requests include the region query param'
   394      );
   395    });
   396  
   397    test('when there is a region set, requests are made with the region query param', async function(assert) {
   398      const region = 'region-2';
   399      window.localStorage.nomadActiveRegion = region;
   400  
   401      await this.initializeUI();
   402  
   403      const { pretender } = this.server;
   404      const jobName = 'job-1';
   405      const jobNamespace = 'default';
   406      const jobId = JSON.stringify([jobName, jobNamespace]);
   407  
   408      await settled();
   409      this.subject().findRecord(null, { modelName: 'job' }, jobId);
   410      this.subject().findAll(null, { modelName: 'job' }, null);
   411      await settled();
   412  
   413      assert.deepEqual(
   414        pretender.handledRequests.mapBy('url'),
   415        [`/v1/job/${jobName}?region=${region}`, `/v1/jobs?region=${region}`],
   416        'Requests include the region query param'
   417      );
   418    });
   419  
   420    test('when the region is set to the default region, requests are made without the region query param', async function(assert) {
   421      window.localStorage.nomadActiveRegion = 'region-1';
   422  
   423      await this.initializeUI();
   424  
   425      const { pretender } = this.server;
   426      const jobName = 'job-1';
   427      const jobNamespace = 'default';
   428      const jobId = JSON.stringify([jobName, jobNamespace]);
   429  
   430      await settled();
   431      this.subject().findRecord(null, { modelName: 'job' }, jobId);
   432      this.subject().findAll(null, { modelName: 'job' }, null);
   433      await settled();
   434  
   435      assert.deepEqual(
   436        pretender.handledRequests.mapBy('url'),
   437        [`/v1/job/${jobName}`, '/v1/jobs'],
   438        'No requests include the region query param'
   439      );
   440    });
   441  });
   442  
   443  function makeMockModel(id, options) {
   444    return assign(
   445      {
   446        relationshipFor(name) {
   447          return {
   448            kind: 'belongsTo',
   449            type: 'job-summary',
   450            key: name,
   451          };
   452        },
   453        belongsTo(name) {
   454          return {
   455            link() {
   456              return `/v1/job/${id}/${name}`;
   457            },
   458          };
   459        },
   460      },
   461      options
   462    );
   463  }