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