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 });