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