github.com/hernad/nomad@v1.6.112/ui/tests/integration/components/job-page/periodic-test.js (about)

     1  /**
     2   * Copyright (c) HashiCorp, Inc.
     3   * SPDX-License-Identifier: MPL-2.0
     4   */
     5  
     6  import { module, test } from 'qunit';
     7  import { setupRenderingTest } from 'ember-qunit';
     8  import { click, find, findAll, render } from '@ember/test-helpers';
     9  import hbs from 'htmlbars-inline-precompile';
    10  import moment from 'moment';
    11  import { create, collection } from 'ember-cli-page-object';
    12  import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
    13  import pageSizeSelect from 'nomad-ui/tests/acceptance/behaviors/page-size-select';
    14  import pageSizeSelectPageObject from 'nomad-ui/tests/pages/components/page-size-select';
    15  import {
    16    jobURL,
    17    stopJob,
    18    startJob,
    19    purgeJob,
    20    expectError,
    21    expectDeleteRequest,
    22    expectStartRequest,
    23    expectPurgeRequest,
    24  } from './helpers';
    25  import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit';
    26  
    27  // A minimum viable page object to use with the pageSizeSelect behavior
    28  const PeriodicJobPage = create({
    29    pageSize: 25,
    30    jobs: collection('[data-test-job-row]'),
    31    pageSizeSelect: pageSizeSelectPageObject(),
    32  });
    33  
    34  module('Integration | Component | job-page/periodic', function (hooks) {
    35    setupRenderingTest(hooks);
    36  
    37    hooks.beforeEach(function () {
    38      window.localStorage.clear();
    39      this.store = this.owner.lookup('service:store');
    40      this.server = startMirage();
    41      this.server.create('namespace');
    42      this.server.create('node-pool');
    43    });
    44  
    45    hooks.afterEach(function () {
    46      this.server.shutdown();
    47      window.localStorage.clear();
    48    });
    49  
    50    const commonTemplate = hbs`
    51      <JobPage::Periodic
    52        @job={{job}}
    53        @sortProperty={{sortProperty}}
    54        @sortDescending={{sortDescending}}
    55        @currentPage={{currentPage}}
    56      />
    57    `;
    58  
    59    const commonProperties = (job) => ({
    60      job,
    61      sortProperty: 'name',
    62      sortDescending: true,
    63      currentPage: 1,
    64    });
    65  
    66    test('Clicking Force Launch launches a new periodic child job', async function (assert) {
    67      const childrenCount = 3;
    68  
    69      this.server.create('job', 'periodic', {
    70        id: 'parent',
    71        childrenCount,
    72        createAllocations: false,
    73      });
    74  
    75      await this.store.findAll('job');
    76  
    77      const job = this.store.peekAll('job').findBy('plainId', 'parent');
    78  
    79      this.setProperties(commonProperties(job));
    80      await render(commonTemplate);
    81  
    82      const currentJobCount = server.db.jobs.length;
    83  
    84      assert.equal(
    85        findAll('[data-test-job-row] [data-test-job-name]').length,
    86        childrenCount,
    87        'The new periodic job launch is in the children list'
    88      );
    89  
    90      await click('[data-test-force-launch]');
    91  
    92      const expectedURL = jobURL(job, '/periodic/force');
    93  
    94      assert.ok(
    95        this.server.pretender.handledRequests
    96          .filterBy('method', 'POST')
    97          .find((req) => req.url === expectedURL),
    98        'POST URL was correct'
    99      );
   100  
   101      assert.equal(
   102        server.db.jobs.length,
   103        currentJobCount + 1,
   104        'POST request was made'
   105      );
   106    });
   107  
   108    test('Clicking force launch without proper permissions shows an error message', async function (assert) {
   109      this.server.pretender.post('/v1/job/:id/periodic/force', () => [
   110        403,
   111        {},
   112        '',
   113      ]);
   114  
   115      this.server.create('job', 'periodic', {
   116        id: 'parent',
   117        childrenCount: 1,
   118        createAllocations: false,
   119        status: 'running',
   120      });
   121  
   122      await this.store.findAll('job');
   123  
   124      const job = this.store.peekAll('job').findBy('plainId', 'parent');
   125  
   126      this.setProperties(commonProperties(job));
   127      await render(commonTemplate);
   128  
   129      assert.notOk(find('[data-test-job-error-title]'), 'No error message yet');
   130  
   131      await click('[data-test-force-launch]');
   132  
   133      assert.equal(
   134        find('[data-test-job-error-title]').textContent,
   135        'Could Not Force Launch',
   136        'Appropriate error is shown'
   137      );
   138      assert.ok(
   139        find('[data-test-job-error-body]').textContent.includes('ACL'),
   140        'The error message mentions ACLs'
   141      );
   142  
   143      await click('[data-test-job-error-close]');
   144  
   145      assert.notOk(
   146        find('[data-test-job-error-title]'),
   147        'Error message is dismissable'
   148      );
   149    });
   150  
   151    test('Stopping a job sends a delete request for the job', async function (assert) {
   152      assert.expect(1);
   153  
   154      const mirageJob = this.server.create('job', 'periodic', {
   155        childrenCount: 0,
   156        createAllocations: false,
   157        status: 'running',
   158      });
   159  
   160      let job;
   161      await this.store.findAll('job');
   162  
   163      job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   164  
   165      this.setProperties(commonProperties(job));
   166      await render(commonTemplate);
   167      await stopJob();
   168  
   169      expectDeleteRequest(assert, this.server, job);
   170    });
   171  
   172    test('Stopping a job without proper permissions shows an error message', async function (assert) {
   173      assert.expect(4);
   174  
   175      this.server.pretender.delete('/v1/job/:id', () => [403, {}, '']);
   176  
   177      const mirageJob = this.server.create('job', 'periodic', {
   178        childrenCount: 0,
   179        createAllocations: false,
   180        status: 'running',
   181      });
   182  
   183      await this.store.findAll('job');
   184  
   185      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   186  
   187      this.setProperties(commonProperties(job));
   188      await render(commonTemplate);
   189  
   190      await stopJob();
   191      expectError(assert, 'Could Not Stop Job');
   192  
   193      await componentA11yAudit(this.element, assert);
   194    });
   195  
   196    test('Starting a job sends a post request for the job using the current definition', async function (assert) {
   197      assert.expect(2);
   198  
   199      const mirageJob = this.server.create('job', 'periodic', {
   200        childrenCount: 0,
   201        createAllocations: false,
   202        status: 'dead',
   203      });
   204      await this.store.findAll('job');
   205  
   206      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   207  
   208      this.setProperties(commonProperties(job));
   209      await render(commonTemplate);
   210  
   211      await startJob();
   212      expectStartRequest(assert, this.server, job);
   213    });
   214  
   215    test('Starting a job without proper permissions shows an error message', async function (assert) {
   216      assert.expect(3);
   217  
   218      this.server.pretender.post('/v1/job/:id', () => [403, {}, '']);
   219  
   220      const mirageJob = this.server.create('job', 'periodic', {
   221        childrenCount: 0,
   222        createAllocations: false,
   223        status: 'dead',
   224      });
   225      await this.store.findAll('job');
   226  
   227      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   228  
   229      this.setProperties(commonProperties(job));
   230      await render(commonTemplate);
   231  
   232      await startJob();
   233  
   234      await expectError(assert, 'Could Not Start Job');
   235    });
   236  
   237    test('Purging a job sends a purge request for the job', async function (assert) {
   238      assert.expect(1);
   239  
   240      const mirageJob = this.server.create('job', 'periodic', {
   241        childrenCount: 0,
   242        createAllocations: false,
   243        status: 'dead',
   244      });
   245      await this.store.findAll('job');
   246  
   247      const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
   248  
   249      this.setProperties(commonProperties(job));
   250      await render(commonTemplate);
   251  
   252      await purgeJob();
   253      expectPurgeRequest(assert, this.server, job);
   254    });
   255  
   256    test('Each job row includes the submitted time', async function (assert) {
   257      this.server.create('job', 'periodic', {
   258        id: 'parent',
   259        childrenCount: 1,
   260        createAllocations: false,
   261      });
   262  
   263      await this.store.findAll('job');
   264  
   265      const job = this.store.peekAll('job').findBy('plainId', 'parent');
   266  
   267      this.setProperties(commonProperties(job));
   268      await render(commonTemplate);
   269  
   270      assert.equal(
   271        find('[data-test-job-submit-time]').textContent.trim(),
   272        moment(job.get('children.firstObject.submitTime')).format(
   273          'MMM DD HH:mm:ss ZZ'
   274        ),
   275        'The new periodic job launch is in the children list'
   276      );
   277    });
   278  
   279    pageSizeSelect({
   280      resourceName: 'job',
   281      pageObject: PeriodicJobPage,
   282      pageObjectList: PeriodicJobPage.jobs,
   283      async setup() {
   284        this.server.create('job', 'periodic', {
   285          id: 'parent',
   286          childrenCount: PeriodicJobPage.pageSize,
   287          createAllocations: false,
   288        });
   289  
   290        await this.store.findAll('job');
   291  
   292        const job = this.store.peekAll('job').findBy('plainId', 'parent');
   293  
   294        this.setProperties(commonProperties(job));
   295        await render(commonTemplate);
   296      },
   297    });
   298  });