github.com/anuvu/nomad@v0.8.7-atom1/ui/tests/acceptance/task-group-detail-test.js (about) 1 import { click, find, findAll, fillIn, currentURL, visit } from 'ember-native-dom-helpers'; 2 import { test } from 'qunit'; 3 import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance'; 4 import { formatBytes } from 'nomad-ui/helpers/format-bytes'; 5 import moment from 'moment'; 6 7 let job; 8 let taskGroup; 9 let tasks; 10 let allocations; 11 12 const sum = (total, n) => total + n; 13 14 moduleForAcceptance('Acceptance | task group detail', { 15 beforeEach() { 16 server.create('agent'); 17 server.create('node', 'forceIPv4'); 18 19 job = server.create('job', { 20 groupsCount: 2, 21 createAllocations: false, 22 }); 23 24 const taskGroups = server.db.taskGroups.where({ jobId: job.id }); 25 taskGroup = taskGroups[0]; 26 27 tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id)); 28 29 server.create('node', 'forceIPv4'); 30 31 allocations = server.createList('allocation', 2, { 32 jobId: job.id, 33 taskGroup: taskGroup.name, 34 }); 35 36 // Allocations associated to a different task group on the job to 37 // assert that they aren't showing up in on this page in error. 38 server.createList('allocation', 3, { 39 jobId: job.id, 40 taskGroup: taskGroups[1].name, 41 }); 42 43 // Set a static name to make the search test deterministic 44 server.db.allocations.forEach(alloc => { 45 alloc.name = 'aaaaa'; 46 }); 47 48 // Mark the first alloc as rescheduled 49 allocations[0].update({ 50 nextAllocation: allocations[1].id, 51 }); 52 allocations[1].update({ 53 previousAllocation: allocations[0].id, 54 }); 55 56 visit(`/jobs/${job.id}/${taskGroup.name}`); 57 }, 58 }); 59 60 test('/jobs/:id/:task-group should list high-level metrics for the allocation', function(assert) { 61 const totalCPU = tasks.mapBy('Resources.CPU').reduce(sum, 0); 62 const totalMemory = tasks.mapBy('Resources.MemoryMB').reduce(sum, 0); 63 const totalDisk = taskGroup.ephemeralDisk.SizeMB; 64 65 assert.equal( 66 find('[data-test-task-group-tasks]').textContent, 67 `# Tasks ${tasks.length}`, 68 '# Tasks' 69 ); 70 assert.equal( 71 find('[data-test-task-group-cpu]').textContent, 72 `Reserved CPU ${totalCPU} MHz`, 73 'Aggregated CPU reservation for all tasks' 74 ); 75 assert.equal( 76 find('[data-test-task-group-mem]').textContent, 77 `Reserved Memory ${totalMemory} MiB`, 78 'Aggregated Memory reservation for all tasks' 79 ); 80 assert.equal( 81 find('[data-test-task-group-disk]').textContent, 82 `Reserved Disk ${totalDisk} MiB`, 83 'Aggregated Disk reservation for all tasks' 84 ); 85 }); 86 87 test('/jobs/:id/:task-group should have breadcrumbs for job and jobs', function(assert) { 88 assert.equal( 89 find('[data-test-breadcrumb="Jobs"]').textContent.trim(), 90 'Jobs', 91 'First breadcrumb says jobs' 92 ); 93 assert.equal( 94 find(`[data-test-breadcrumb="${job.name}"]`).textContent.trim(), 95 job.name, 96 'Second breadcrumb says the job name' 97 ); 98 assert.equal( 99 find(`[data-test-breadcrumb="${taskGroup.name}"]`).textContent.trim(), 100 taskGroup.name, 101 'Third breadcrumb says the job name' 102 ); 103 }); 104 105 test('/jobs/:id/:task-group first breadcrumb should link to jobs', function(assert) { 106 click('[data-test-breadcrumb="Jobs"]'); 107 andThen(() => { 108 assert.equal(currentURL(), '/jobs', 'First breadcrumb links back to jobs'); 109 }); 110 }); 111 112 test('/jobs/:id/:task-group second breadcrumb should link to the job for the task group', function(assert) { 113 click(`[data-test-breadcrumb="${job.name}"]`); 114 andThen(() => { 115 assert.equal( 116 currentURL(), 117 `/jobs/${job.id}`, 118 'Second breadcrumb links back to the job for the task group' 119 ); 120 }); 121 }); 122 123 test('/jobs/:id/:task-group should list one page of allocations for the task group', function(assert) { 124 const pageSize = 10; 125 126 server.createList('allocation', 10, { 127 jobId: job.id, 128 taskGroup: taskGroup.name, 129 }); 130 131 visit('/jobs'); 132 visit(`/jobs/${job.id}/${taskGroup.name}`); 133 134 andThen(() => { 135 assert.ok( 136 server.db.allocations.where({ jobId: job.id }).length > pageSize, 137 'There are enough allocations to invoke pagination' 138 ); 139 140 assert.equal( 141 findAll('[data-test-allocation]').length, 142 pageSize, 143 'All allocations for the task group' 144 ); 145 }); 146 }); 147 148 test('each allocation should show basic information about the allocation', function(assert) { 149 const allocation = allocations.sortBy('modifyIndex').reverse()[0]; 150 const allocationRow = find('[data-test-allocation]'); 151 152 andThen(() => { 153 assert.equal( 154 allocationRow.querySelector('[data-test-short-id]').textContent.trim(), 155 allocation.id.split('-')[0], 156 'Allocation short id' 157 ); 158 assert.equal( 159 allocationRow.querySelector('[data-test-modify-time]').textContent.trim(), 160 moment(allocation.modifyTime / 1000000).format('MM/DD HH:mm:ss'), 161 'Allocation modify time' 162 ); 163 assert.equal( 164 allocationRow.querySelector('[data-test-name]').textContent.trim(), 165 allocation.name, 166 'Allocation name' 167 ); 168 assert.equal( 169 allocationRow.querySelector('[data-test-client-status]').textContent.trim(), 170 allocation.clientStatus, 171 'Client status' 172 ); 173 assert.equal( 174 allocationRow.querySelector('[data-test-job-version]').textContent.trim(), 175 allocation.jobVersion, 176 'Job Version' 177 ); 178 assert.equal( 179 allocationRow.querySelector('[data-test-client]').textContent.trim(), 180 server.db.nodes.find(allocation.nodeId).id.split('-')[0], 181 'Node ID' 182 ); 183 }); 184 185 click(allocationRow.querySelector('[data-test-client] a')); 186 187 andThen(() => { 188 assert.equal(currentURL(), `/clients/${allocation.nodeId}`, 'Node links to node page'); 189 }); 190 }); 191 192 test('each allocation should show stats about the allocation', function(assert) { 193 const allocation = allocations.sortBy('name')[0]; 194 const allocationRow = find('[data-test-allocation]'); 195 const allocStats = server.db.clientAllocationStats.find(allocation.id); 196 const tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id)); 197 198 const cpuUsed = tasks.reduce((sum, task) => sum + task.Resources.CPU, 0); 199 const memoryUsed = tasks.reduce((sum, task) => sum + task.Resources.MemoryMB, 0); 200 201 assert.equal( 202 allocationRow.querySelector('[data-test-cpu]').textContent.trim(), 203 Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks) / cpuUsed, 204 'CPU %' 205 ); 206 207 assert.equal( 208 allocationRow.querySelector('[data-test-cpu] .tooltip').getAttribute('aria-label'), 209 `${Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks)} / ${cpuUsed} MHz`, 210 'Detailed CPU information is in a tooltip' 211 ); 212 213 assert.equal( 214 allocationRow.querySelector('[data-test-mem]').textContent.trim(), 215 allocStats.resourceUsage.MemoryStats.RSS / 1024 / 1024 / memoryUsed, 216 'Memory used' 217 ); 218 219 assert.equal( 220 allocationRow.querySelector('[data-test-mem] .tooltip').getAttribute('aria-label'), 221 `${formatBytes([allocStats.resourceUsage.MemoryStats.RSS])} / ${memoryUsed} MiB`, 222 'Detailed memory information is in a tooltip' 223 ); 224 }); 225 226 test('when the allocation search has no matches, there is an empty message', function(assert) { 227 fillIn('.search-box input', 'zzzzzz'); 228 229 andThen(() => { 230 assert.ok(find('[data-test-empty-allocations-list]')); 231 assert.equal(find('[data-test-empty-allocations-list-headline]').textContent, 'No Matches'); 232 }); 233 }); 234 235 test('when the allocation has reschedule events, the allocation row is denoted with an icon', function(assert) { 236 const rescheduleRow = find(`[data-test-allocation="${allocations[0].id}"]`); 237 const normalRow = find(`[data-test-allocation="${allocations[1].id}"]`); 238 239 assert.ok( 240 rescheduleRow.querySelector('[data-test-indicators] [data-test-icon="reschedule"]'), 241 'Reschedule row has a reschedule icon' 242 ); 243 assert.notOk( 244 normalRow.querySelector('[data-test-indicators] [data-test-icon="reschedule"]'), 245 'Normal row has no reschedule icon' 246 ); 247 });