github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/ui/tests/acceptance/volume-detail-test.js (about) 1 import { module, test } from 'qunit'; 2 import { currentURL } from '@ember/test-helpers'; 3 import { setupApplicationTest } from 'ember-qunit'; 4 import { setupMirage } from 'ember-cli-mirage/test-support'; 5 import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit'; 6 import moment from 'moment'; 7 import { formatBytes } from 'nomad-ui/helpers/format-bytes'; 8 import VolumeDetail from 'nomad-ui/tests/pages/storage/volumes/detail'; 9 import Layout from 'nomad-ui/tests/pages/layout'; 10 11 const assignWriteAlloc = (volume, alloc) => { 12 volume.writeAllocs.add(alloc); 13 volume.allocations.add(alloc); 14 volume.save(); 15 }; 16 17 const assignReadAlloc = (volume, alloc) => { 18 volume.readAllocs.add(alloc); 19 volume.allocations.add(alloc); 20 volume.save(); 21 }; 22 23 module('Acceptance | volume detail', function(hooks) { 24 setupApplicationTest(hooks); 25 setupMirage(hooks); 26 27 let volume; 28 29 hooks.beforeEach(function() { 30 server.create('node'); 31 server.create('csi-plugin', { createVolumes: false }); 32 volume = server.create('csi-volume'); 33 }); 34 35 test('it passes an accessibility audit', async function(assert) { 36 await VolumeDetail.visit({ id: volume.id }); 37 await a11yAudit(assert); 38 }); 39 40 test('/csi/volumes/:id should have a breadcrumb trail linking back to Volumes and Storage', async function(assert) { 41 await VolumeDetail.visit({ id: volume.id }); 42 43 assert.equal(Layout.breadcrumbFor('csi.index').text, 'Storage'); 44 assert.equal(Layout.breadcrumbFor('csi.volumes').text, 'Volumes'); 45 assert.equal(Layout.breadcrumbFor('csi.volumes.volume').text, volume.name); 46 }); 47 48 test('/csi/volumes/:id should show the volume name in the title', async function(assert) { 49 await VolumeDetail.visit({ id: volume.id }); 50 51 assert.equal(document.title, `CSI Volume ${volume.name} - Nomad`); 52 assert.equal(VolumeDetail.title, volume.name); 53 }); 54 55 test('/csi/volumes/:id should list additional details for the volume below the title', async function(assert) { 56 await VolumeDetail.visit({ id: volume.id }); 57 58 assert.ok(VolumeDetail.health.includes(volume.schedulable ? 'Schedulable' : 'Unschedulable')); 59 assert.ok(VolumeDetail.provider.includes(volume.provider)); 60 assert.ok(VolumeDetail.externalId.includes(volume.externalId)); 61 assert.notOk( 62 VolumeDetail.hasNamespace, 63 'Namespace is omitted when there is only one namespace' 64 ); 65 }); 66 67 test('/csi/volumes/:id should list all write allocations the volume is attached to', async function(assert) { 68 const writeAllocations = server.createList('allocation', 2); 69 const readAllocations = server.createList('allocation', 3); 70 writeAllocations.forEach(alloc => assignWriteAlloc(volume, alloc)); 71 readAllocations.forEach(alloc => assignReadAlloc(volume, alloc)); 72 73 await VolumeDetail.visit({ id: volume.id }); 74 75 assert.equal(VolumeDetail.writeAllocations.length, writeAllocations.length); 76 writeAllocations 77 .sortBy('modifyIndex') 78 .reverse() 79 .forEach((allocation, idx) => { 80 assert.equal(allocation.id, VolumeDetail.writeAllocations.objectAt(idx).id); 81 }); 82 }); 83 84 test('/csi/volumes/:id should list all read allocations the volume is attached to', async function(assert) { 85 const writeAllocations = server.createList('allocation', 2); 86 const readAllocations = server.createList('allocation', 3); 87 writeAllocations.forEach(alloc => assignWriteAlloc(volume, alloc)); 88 readAllocations.forEach(alloc => assignReadAlloc(volume, alloc)); 89 90 await VolumeDetail.visit({ id: volume.id }); 91 92 assert.equal(VolumeDetail.readAllocations.length, readAllocations.length); 93 readAllocations 94 .sortBy('modifyIndex') 95 .reverse() 96 .forEach((allocation, idx) => { 97 assert.equal(allocation.id, VolumeDetail.readAllocations.objectAt(idx).id); 98 }); 99 }); 100 101 test('each allocation should have high-level details for the allocation', async function(assert) { 102 const allocation = server.create('allocation', { clientStatus: 'running' }); 103 assignWriteAlloc(volume, allocation); 104 105 const allocStats = server.db.clientAllocationStats.find(allocation.id); 106 const taskGroup = server.db.taskGroups.findBy({ 107 name: allocation.taskGroup, 108 jobId: allocation.jobId, 109 }); 110 111 const tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id)); 112 const cpuUsed = tasks.reduce((sum, task) => sum + task.resources.CPU, 0); 113 const memoryUsed = tasks.reduce((sum, task) => sum + task.resources.MemoryMB, 0); 114 115 await VolumeDetail.visit({ id: volume.id }); 116 117 VolumeDetail.writeAllocations.objectAt(0).as(allocationRow => { 118 assert.equal(allocationRow.shortId, allocation.id.split('-')[0], 'Allocation short ID'); 119 assert.equal( 120 allocationRow.createTime, 121 moment(allocation.createTime / 1000000).format('MMM DD HH:mm:ss ZZ'), 122 'Allocation create time' 123 ); 124 assert.equal( 125 allocationRow.modifyTime, 126 moment(allocation.modifyTime / 1000000).fromNow(), 127 'Allocation modify time' 128 ); 129 assert.equal(allocationRow.status, allocation.clientStatus, 'Client status'); 130 assert.equal(allocationRow.job, server.db.jobs.find(allocation.jobId).name, 'Job name'); 131 assert.ok(allocationRow.taskGroup, 'Task group name'); 132 assert.ok(allocationRow.jobVersion, 'Job Version'); 133 assert.equal( 134 allocationRow.client, 135 server.db.nodes.find(allocation.nodeId).id.split('-')[0], 136 'Node ID' 137 ); 138 assert.equal( 139 allocationRow.cpu, 140 Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks) / cpuUsed, 141 'CPU %' 142 ); 143 assert.equal( 144 allocationRow.cpuTooltip, 145 `${Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks)} / ${cpuUsed} MHz`, 146 'Detailed CPU information is in a tooltip' 147 ); 148 assert.equal( 149 allocationRow.mem, 150 allocStats.resourceUsage.MemoryStats.RSS / 1024 / 1024 / memoryUsed, 151 'Memory used' 152 ); 153 assert.equal( 154 allocationRow.memTooltip, 155 `${formatBytes([allocStats.resourceUsage.MemoryStats.RSS])} / ${memoryUsed} MiB`, 156 'Detailed memory information is in a tooltip' 157 ); 158 }); 159 }); 160 161 test('each allocation should link to the allocation detail page', async function(assert) { 162 const allocation = server.create('allocation'); 163 assignWriteAlloc(volume, allocation); 164 165 await VolumeDetail.visit({ id: volume.id }); 166 await VolumeDetail.writeAllocations.objectAt(0).visit(); 167 168 assert.equal(currentURL(), `/allocations/${allocation.id}`); 169 }); 170 171 test('when there are no write allocations, the table presents an empty state', async function(assert) { 172 await VolumeDetail.visit({ id: volume.id }); 173 174 assert.ok(VolumeDetail.writeTableIsEmpty); 175 assert.equal(VolumeDetail.writeEmptyState.headline, 'No Write Allocations'); 176 }); 177 178 test('when there are no read allocations, the table presents an empty state', async function(assert) { 179 await VolumeDetail.visit({ id: volume.id }); 180 181 assert.ok(VolumeDetail.readTableIsEmpty); 182 assert.equal(VolumeDetail.readEmptyState.headline, 'No Read Allocations'); 183 }); 184 185 test('the constraints table shows access mode and attachment mode', async function(assert) { 186 await VolumeDetail.visit({ id: volume.id }); 187 188 assert.equal(VolumeDetail.constraints.accessMode, volume.accessMode); 189 assert.equal(VolumeDetail.constraints.attachmentMode, volume.attachmentMode); 190 }); 191 }); 192 193 // Namespace test: details shows the namespace 194 module('Acceptance | volume detail (with namespaces)', function(hooks) { 195 setupApplicationTest(hooks); 196 setupMirage(hooks); 197 198 let volume; 199 200 hooks.beforeEach(function() { 201 server.createList('namespace', 2); 202 server.create('node'); 203 server.create('csi-plugin', { createVolumes: false }); 204 volume = server.create('csi-volume'); 205 }); 206 207 test('/csi/volumes/:id detail ribbon includes the namespace of the volume', async function(assert) { 208 await VolumeDetail.visit({ id: volume.id }); 209 210 assert.ok(VolumeDetail.hasNamespace); 211 assert.ok(VolumeDetail.namespace.includes(volume.namespaceId || 'default')); 212 }); 213 });