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