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