github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/tests/integration/components/job-page/service-test.js (about)

     1  import { assign } from '@ember/polyfills';
     2  import { module, test } from 'qunit';
     3  import { setupRenderingTest } from 'ember-qunit';
     4  import { click, find, render } from '@ember/test-helpers';
     5  import hbs from 'htmlbars-inline-precompile';
     6  import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
     7  import {
     8    startJob,
     9    stopJob,
    10    purgeJob,
    11    expectError,
    12    expectDeleteRequest,
    13    expectStartRequest,
    14    expectPurgeRequest,
    15  } from './helpers';
    16  import Job from 'nomad-ui/tests/pages/jobs/detail';
    17  import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer';
    18  import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit';
    19  
    20  module('Integration | Component | job-page/service', function (hooks) {
    21    setupRenderingTest(hooks);
    22  
    23    hooks.beforeEach(function () {
    24      fragmentSerializerInitializer(this.owner);
    25      window.localStorage.clear();
    26      this.store = this.owner.lookup('service:store');
    27      this.server = startMirage();
    28      this.server.create('namespace');
    29    });
    30  
    31    hooks.afterEach(function () {
    32      this.server.shutdown();
    33      window.localStorage.clear();
    34    });
    35  
    36    const commonTemplate = hbs`
    37      <JobPage::Service
    38        @job={{job}}
    39        @sortProperty={{sortProperty}}
    40        @sortDescending={{sortDescending}}
    41        @currentPage={{currentPage}}
    42        @gotoJob={{gotoJob}} />
    43    `;
    44  
    45    const commonProperties = (job) => ({
    46      job,
    47      sortProperty: 'name',
    48      sortDescending: true,
    49      currentPage: 1,
    50      gotoJob() {},
    51    });
    52  
    53    const makeMirageJob = (server, props = {}) =>
    54      server.create(
    55        'job',
    56        assign(
    57          {
    58            type: 'service',
    59            createAllocations: false,
    60            status: 'running',
    61          },
    62          props
    63        )
    64      );
    65  
    66    test('Stopping a job sends a delete request for the job', async function (assert) {
    67      assert.expect(1);
    68  
    69      const mirageJob = makeMirageJob(this.server);
    70      await this.store.findAll('job');
    71  
    72      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
    73  
    74      this.setProperties(commonProperties(job));
    75      await render(commonTemplate);
    76  
    77      await stopJob();
    78      expectDeleteRequest(assert, this.server, job);
    79    });
    80  
    81    test('Stopping a job without proper permissions shows an error message', async function (assert) {
    82      assert.expect(4);
    83  
    84      this.server.pretender.delete('/v1/job/:id', () => [403, {}, '']);
    85  
    86      const mirageJob = makeMirageJob(this.server);
    87      await this.store.findAll('job');
    88  
    89      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
    90  
    91      this.setProperties(commonProperties(job));
    92      await render(commonTemplate);
    93  
    94      await stopJob();
    95      expectError(assert, 'Could Not Stop Job');
    96  
    97      await componentA11yAudit(this.element, assert);
    98    });
    99  
   100    test('Starting a job sends a post request for the job using the current definition', async function (assert) {
   101      assert.expect(2);
   102  
   103      const mirageJob = makeMirageJob(this.server, { status: 'dead' });
   104      await this.store.findAll('job');
   105  
   106      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   107  
   108      this.setProperties(commonProperties(job));
   109      await render(commonTemplate);
   110  
   111      await startJob();
   112      expectStartRequest(assert, this.server, job);
   113    });
   114  
   115    test('Starting a job without proper permissions shows an error message', async function (assert) {
   116      assert.expect(3);
   117  
   118      this.server.pretender.post('/v1/job/:id', () => [403, {}, '']);
   119  
   120      const mirageJob = makeMirageJob(this.server, { status: 'dead' });
   121      await this.store.findAll('job');
   122  
   123      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   124  
   125      this.setProperties(commonProperties(job));
   126      await render(commonTemplate);
   127  
   128      await startJob();
   129  
   130      await expectError(assert, 'Could Not Start Job');
   131    });
   132  
   133    test('Purging a job sends a purge request for the job', async function (assert) {
   134      assert.expect(1);
   135  
   136      const mirageJob = makeMirageJob(this.server, { status: 'dead' });
   137      await this.store.findAll('job');
   138  
   139      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   140  
   141      this.setProperties(commonProperties(job));
   142      await render(commonTemplate);
   143  
   144      await purgeJob();
   145      expectPurgeRequest(assert, this.server, job);
   146    });
   147  
   148    test('Recent allocations shows allocations in the job context', async function (assert) {
   149      assert.expect(3);
   150  
   151      this.server.create('node');
   152      const mirageJob = makeMirageJob(this.server, { createAllocations: true });
   153      await this.store.findAll('job');
   154  
   155      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   156  
   157      this.setProperties(commonProperties(job));
   158      await render(commonTemplate);
   159  
   160      const allocation = this.server.db.allocations
   161        .sortBy('modifyIndex')
   162        .reverse()[0];
   163      const allocationRow = Job.allocations.objectAt(0);
   164  
   165      assert.equal(allocationRow.shortId, allocation.id.split('-')[0], 'ID');
   166      assert.equal(
   167        allocationRow.taskGroup,
   168        allocation.taskGroup,
   169        'Task Group name'
   170      );
   171  
   172      await componentA11yAudit(this.element, assert);
   173    });
   174  
   175    test('Recent allocations caps out at five', async function (assert) {
   176      this.server.create('node');
   177      const mirageJob = makeMirageJob(this.server);
   178      this.server.createList('allocation', 10);
   179  
   180      await this.store.findAll('job');
   181  
   182      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   183  
   184      this.setProperties(commonProperties(job));
   185      await render(commonTemplate);
   186  
   187      assert.equal(Job.allocations.length, 5, 'Capped at 5 allocations');
   188      assert.ok(
   189        Job.viewAllAllocations.includes(job.get('allocations.length') + ''),
   190        `View link mentions ${job.get('allocations.length')} allocations`
   191      );
   192    });
   193  
   194    test('Recent allocations shows an empty message when the job has no allocations', async function (assert) {
   195      assert.expect(2);
   196  
   197      this.server.create('node');
   198      const mirageJob = makeMirageJob(this.server);
   199  
   200      await this.store.findAll('job');
   201  
   202      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   203  
   204      this.setProperties(commonProperties(job));
   205      await render(commonTemplate);
   206  
   207      assert.ok(
   208        Job.recentAllocationsEmptyState.headline.includes('No Allocations'),
   209        'No allocations empty message'
   210      );
   211  
   212      await componentA11yAudit(this.element, assert);
   213    });
   214  
   215    test('Active deployment can be promoted', async function (assert) {
   216      this.server.create('node');
   217      const mirageJob = makeMirageJob(this.server, { activeDeployment: true });
   218  
   219      await this.store.findAll('job');
   220  
   221      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   222      const deployment = await job.get('latestDeployment');
   223  
   224      this.setProperties(commonProperties(job));
   225      await render(commonTemplate);
   226  
   227      await click('[data-test-promote-canary]');
   228  
   229      const requests = this.server.pretender.handledRequests;
   230  
   231      assert.ok(
   232        requests
   233          .filterBy('method', 'POST')
   234          .findBy('url', `/v1/deployment/promote/${deployment.get('id')}`),
   235        'A promote POST request was made'
   236      );
   237    });
   238  
   239    test('When promoting the active deployment fails, an error is shown', async function (assert) {
   240      assert.expect(4);
   241  
   242      this.server.pretender.post('/v1/deployment/promote/:id', () => [
   243        403,
   244        {},
   245        '',
   246      ]);
   247  
   248      this.server.create('node');
   249      const mirageJob = makeMirageJob(this.server, { activeDeployment: true });
   250  
   251      await this.store.findAll('job');
   252  
   253      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   254  
   255      this.setProperties(commonProperties(job));
   256      await render(commonTemplate);
   257  
   258      await click('[data-test-promote-canary]');
   259  
   260      assert.equal(
   261        find('[data-test-job-error-title]').textContent,
   262        'Could Not Promote Deployment',
   263        'Appropriate error is shown'
   264      );
   265      assert.ok(
   266        find('[data-test-job-error-body]').textContent.includes('ACL'),
   267        'The error message mentions ACLs'
   268      );
   269  
   270      await componentA11yAudit(this.element, assert);
   271  
   272      await click('[data-test-job-error-close]');
   273  
   274      assert.notOk(
   275        find('[data-test-job-error-title]'),
   276        'Error message is dismissable'
   277      );
   278    });
   279  
   280    test('Active deployment can be failed', async function (assert) {
   281      this.server.create('node');
   282      const mirageJob = makeMirageJob(this.server, { activeDeployment: true });
   283  
   284      await this.store.findAll('job');
   285  
   286      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   287      const deployment = await job.get('latestDeployment');
   288  
   289      this.setProperties(commonProperties(job));
   290      await render(commonTemplate);
   291  
   292      await click('[data-test-active-deployment] [data-test-idle-button]');
   293      await click('[data-test-active-deployment] [data-test-confirm-button]');
   294  
   295      const requests = this.server.pretender.handledRequests;
   296  
   297      assert.ok(
   298        requests
   299          .filterBy('method', 'POST')
   300          .findBy('url', `/v1/deployment/fail/${deployment.get('id')}`),
   301        'A fail POST request was made'
   302      );
   303    });
   304  
   305    test('When failing the active deployment fails, an error is shown', async function (assert) {
   306      assert.expect(4);
   307  
   308      this.server.pretender.post('/v1/deployment/fail/:id', () => [403, {}, '']);
   309  
   310      this.server.create('node');
   311      const mirageJob = makeMirageJob(this.server, { activeDeployment: true });
   312  
   313      await this.store.findAll('job');
   314  
   315      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   316  
   317      this.setProperties(commonProperties(job));
   318      await render(commonTemplate);
   319  
   320      await click('[data-test-active-deployment] [data-test-idle-button]');
   321      await click('[data-test-active-deployment] [data-test-confirm-button]');
   322  
   323      assert.equal(
   324        find('[data-test-job-error-title]').textContent,
   325        'Could Not Fail Deployment',
   326        'Appropriate error is shown'
   327      );
   328      assert.ok(
   329        find('[data-test-job-error-body]').textContent.includes('ACL'),
   330        'The error message mentions ACLs'
   331      );
   332  
   333      await componentA11yAudit(this.element, assert);
   334  
   335      await click('[data-test-job-error-close]');
   336  
   337      assert.notOk(
   338        find('[data-test-job-error-title]'),
   339        'Error message is dismissable'
   340      );
   341    });
   342  });