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