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