github.com/hernad/nomad@v1.6.112/ui/tests/integration/components/topo-viz/datacenter-test.js (about) 1 /** 2 * Copyright (c) HashiCorp, Inc. 3 * SPDX-License-Identifier: MPL-2.0 4 */ 5 6 import { find, render } from '@ember/test-helpers'; 7 import { module, test } from 'qunit'; 8 import { setupRenderingTest } from 'ember-qunit'; 9 import hbs from 'htmlbars-inline-precompile'; 10 import { setupMirage } from 'ember-cli-mirage/test-support'; 11 import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; 12 import { create } from 'ember-cli-page-object'; 13 import sinon from 'sinon'; 14 import faker from 'nomad-ui/mirage/faker'; 15 import topoVizDatacenterPageObject from 'nomad-ui/tests/pages/components/topo-viz/datacenter'; 16 import { formatBytes, formatHertz } from 'nomad-ui/utils/units'; 17 18 const TopoVizDatacenter = create(topoVizDatacenterPageObject()); 19 20 const nodeGen = (name, datacenter, memory, cpu, allocations = []) => ({ 21 datacenter, 22 memory, 23 cpu, 24 node: { name }, 25 allocations: allocations.map((alloc) => ({ 26 memory: alloc.memory, 27 cpu: alloc.cpu, 28 memoryPercent: alloc.memory / memory, 29 cpuPercent: alloc.cpu / cpu, 30 allocation: { 31 id: faker.random.uuid(), 32 isScheduled: true, 33 }, 34 })), 35 }); 36 37 // Used in Array#reduce to sum by a property common to an array of objects 38 const sumBy = (prop) => (sum, obj) => (sum += obj[prop]); 39 40 module('Integration | Component | TopoViz::Datacenter', function (hooks) { 41 setupRenderingTest(hooks); 42 setupMirage(hooks); 43 44 const commonProps = (props) => ({ 45 isSingleColumn: true, 46 isDense: false, 47 heightScale: () => 50, 48 onAllocationSelect: sinon.spy(), 49 onNodeSelect: sinon.spy(), 50 ...props, 51 }); 52 53 const commonTemplate = hbs` 54 <TopoViz::Datacenter 55 @datacenter={{this.datacenter}} 56 @isSingleColumn={{this.isSingleColumn}} 57 @isDense={{this.isDense}} 58 @heightScale={{this.heightScale}} 59 @onAllocationSelect={{this.onAllocationSelect}} 60 @onNodeSelect={{this.onNodeSelect}} /> 61 `; 62 63 test('presents as a div with a label and a FlexMasonry with a collection of nodes', async function (assert) { 64 assert.expect(3); 65 66 this.setProperties( 67 commonProps({ 68 datacenter: { 69 name: 'dc1', 70 nodes: [nodeGen('node-1', 'dc1', 1000, 500)], 71 }, 72 }) 73 ); 74 75 await render(commonTemplate); 76 77 assert.ok(TopoVizDatacenter.isPresent); 78 assert.equal(TopoVizDatacenter.nodes.length, this.datacenter.nodes.length); 79 80 await componentA11yAudit(this.element, assert); 81 }); 82 83 test('datacenter stats are an aggregate of node stats', async function (assert) { 84 this.setProperties( 85 commonProps({ 86 datacenter: { 87 name: 'dc1', 88 nodes: [ 89 nodeGen('node-1', 'dc1', 1000, 500, [ 90 { memory: 100, cpu: 300 }, 91 { memory: 200, cpu: 50 }, 92 ]), 93 nodeGen('node-2', 'dc1', 1500, 100, [ 94 { memory: 50, cpu: 80 }, 95 { memory: 100, cpu: 20 }, 96 ]), 97 nodeGen('node-3', 'dc1', 2000, 300), 98 nodeGen('node-4', 'dc1', 3000, 200), 99 ], 100 }, 101 }) 102 ); 103 104 await render(commonTemplate); 105 106 const allocs = this.datacenter.nodes.reduce( 107 (allocs, node) => allocs.concat(node.allocations), 108 [] 109 ); 110 const memoryReserved = allocs.reduce(sumBy('memory'), 0); 111 const cpuReserved = allocs.reduce(sumBy('cpu'), 0); 112 const memoryTotal = this.datacenter.nodes.reduce(sumBy('memory'), 0); 113 const cpuTotal = this.datacenter.nodes.reduce(sumBy('cpu'), 0); 114 115 assert.ok(TopoVizDatacenter.label.includes(this.datacenter.name)); 116 assert.ok( 117 TopoVizDatacenter.label.includes(`${this.datacenter.nodes.length} Nodes`) 118 ); 119 assert.ok(TopoVizDatacenter.label.includes(`${allocs.length} Allocs`)); 120 assert.ok( 121 TopoVizDatacenter.label.includes( 122 `${formatBytes(memoryReserved, 'MiB')} / ${formatBytes( 123 memoryTotal, 124 'MiB' 125 )}` 126 ) 127 ); 128 assert.ok( 129 TopoVizDatacenter.label.includes( 130 `${formatHertz(cpuReserved, 'MHz')} / ${formatHertz(cpuTotal, 'MHz')}` 131 ) 132 ); 133 }); 134 135 test('when @isSingleColumn is true, the FlexMasonry layout gets one column, otherwise it gets two', async function (assert) { 136 this.setProperties( 137 commonProps({ 138 isSingleColumn: true, 139 datacenter: { 140 name: 'dc1', 141 nodes: [ 142 nodeGen('node-1', 'dc1', 1000, 500), 143 nodeGen('node-2', 'dc1', 1000, 500), 144 ], 145 }, 146 }) 147 ); 148 149 await render(commonTemplate); 150 151 assert.ok(find('[data-test-flex-masonry].flex-masonry-columns-1')); 152 153 this.set('isSingleColumn', false); 154 assert.ok(find('[data-test-flex-masonry].flex-masonry-columns-2')); 155 }); 156 157 test('args get passed down to the TopViz::Node children', async function (assert) { 158 assert.expect(4); 159 160 const heightSpy = sinon.spy(); 161 this.setProperties( 162 commonProps({ 163 isDense: true, 164 heightScale: (...args) => { 165 heightSpy(...args); 166 return 50; 167 }, 168 datacenter: { 169 name: 'dc1', 170 nodes: [ 171 nodeGen('node-1', 'dc1', 1000, 500, [{ memory: 100, cpu: 300 }]), 172 ], 173 }, 174 }) 175 ); 176 177 await render(commonTemplate); 178 179 TopoVizDatacenter.nodes[0].as(async (TopoVizNode) => { 180 assert.notOk(TopoVizNode.labelIsPresent); 181 assert.ok(heightSpy.calledWith(this.datacenter.nodes[0].memory)); 182 183 await TopoVizNode.selectNode(); 184 assert.ok(this.onNodeSelect.calledWith(this.datacenter.nodes[0])); 185 186 await TopoVizNode.memoryRects[0].select(); 187 assert.ok( 188 this.onAllocationSelect.calledWith( 189 this.datacenter.nodes[0].allocations[0] 190 ) 191 ); 192 }); 193 }); 194 });