github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/ui/tests/unit/components/topo-viz-test.js (about) 1 import { module, test } from 'qunit'; 2 import { setupTest } from 'ember-qunit'; 3 import setupGlimmerComponentFactory from 'nomad-ui/tests/helpers/glimmer-factory'; 4 5 module('Unit | Component | TopoViz', function(hooks) { 6 setupTest(hooks); 7 setupGlimmerComponentFactory(hooks, 'topo-viz'); 8 9 test('the topology object properly organizes a tree of datacenters > nodes > allocations', async function(assert) { 10 const nodes = [ 11 { datacenter: 'dc1', id: 'node0', resources: {} }, 12 { datacenter: 'dc2', id: 'node1', resources: {} }, 13 { datacenter: 'dc1', id: 'node2', resources: {} }, 14 ]; 15 16 const node0Allocs = [ 17 alloc({ nodeId: 'node0', jobId: 'job0', taskGroupName: 'group' }), 18 alloc({ nodeId: 'node0', jobId: 'job1', taskGroupName: 'group' }), 19 ]; 20 const node1Allocs = [ 21 alloc({ nodeId: 'node1', jobId: 'job0', taskGroupName: 'group' }), 22 alloc({ nodeId: 'node1', jobId: 'job1', taskGroupName: 'group' }), 23 ]; 24 const node2Allocs = [ 25 alloc({ nodeId: 'node2', jobId: 'job0', taskGroupName: 'group' }), 26 alloc({ nodeId: 'node2', jobId: 'job1', taskGroupName: 'group' }), 27 ]; 28 29 const allocations = [...node0Allocs, ...node1Allocs, ...node2Allocs]; 30 31 const topoViz = this.createComponent({ nodes, allocations }); 32 33 topoViz.buildTopology(); 34 35 assert.deepEqual(topoViz.topology.datacenters.mapBy('name'), ['dc1', 'dc2']); 36 assert.deepEqual(topoViz.topology.datacenters[0].nodes.mapBy('node'), [nodes[0], nodes[2]]); 37 assert.deepEqual(topoViz.topology.datacenters[1].nodes.mapBy('node'), [nodes[1]]); 38 assert.deepEqual( 39 topoViz.topology.datacenters[0].nodes[0].allocations.mapBy('allocation'), 40 node0Allocs 41 ); 42 assert.deepEqual( 43 topoViz.topology.datacenters[1].nodes[0].allocations.mapBy('allocation'), 44 node1Allocs 45 ); 46 assert.deepEqual( 47 topoViz.topology.datacenters[0].nodes[1].allocations.mapBy('allocation'), 48 node2Allocs 49 ); 50 }); 51 52 test('the topology object contains an allocation index keyed by jobId+taskGroupName', async function(assert) { 53 const allocations = [ 54 alloc({ nodeId: 'node0', jobId: 'job0', taskGroupName: 'one' }), 55 alloc({ nodeId: 'node0', jobId: 'job0', taskGroupName: 'one' }), 56 alloc({ nodeId: 'node0', jobId: 'job0', taskGroupName: 'two' }), 57 alloc({ nodeId: 'node0', jobId: 'job1', taskGroupName: 'one' }), 58 alloc({ nodeId: 'node0', jobId: 'job1', taskGroupName: 'two' }), 59 alloc({ nodeId: 'node0', jobId: 'job1', taskGroupName: 'three' }), 60 alloc({ nodeId: 'node0', jobId: 'job2', taskGroupName: 'one' }), 61 alloc({ nodeId: 'node0', jobId: 'job2', taskGroupName: 'one' }), 62 alloc({ nodeId: 'node0', jobId: 'job2', taskGroupName: 'one' }), 63 alloc({ nodeId: 'node0', jobId: 'job2', taskGroupName: 'one' }), 64 ]; 65 66 const nodes = [{ datacenter: 'dc1', id: 'node0', resources: {} }]; 67 const topoViz = this.createComponent({ nodes, allocations }); 68 69 topoViz.buildTopology(); 70 71 assert.deepEqual( 72 Object.keys(topoViz.topology.allocationIndex).sort(), 73 [ 74 JSON.stringify(['job0', 'one']), 75 JSON.stringify(['job0', 'two']), 76 77 JSON.stringify(['job1', 'one']), 78 JSON.stringify(['job1', 'two']), 79 JSON.stringify(['job1', 'three']), 80 81 JSON.stringify(['job2', 'one']), 82 ].sort() 83 ); 84 85 Object.keys(topoViz.topology.allocationIndex).forEach(key => { 86 const [jobId, group] = JSON.parse(key); 87 assert.deepEqual( 88 topoViz.topology.allocationIndex[key].mapBy('allocation'), 89 allocations.filter(alloc => alloc.jobId === jobId && alloc.taskGroupName === group) 90 ); 91 }); 92 }); 93 94 test('isSingleColumn is true when there is only one datacenter', async function(assert) { 95 const oneDc = [{ datacenter: 'dc1', id: 'node0', resources: {} }]; 96 const twoDc = [...oneDc, { datacenter: 'dc2', id: 'node1', resources: {} }]; 97 98 const topoViz1 = this.createComponent({ nodes: oneDc, allocations: [] }); 99 const topoViz2 = this.createComponent({ nodes: twoDc, allocations: [] }); 100 101 topoViz1.buildTopology(); 102 topoViz2.buildTopology(); 103 104 assert.ok(topoViz1.isSingleColumn); 105 assert.notOk(topoViz2.isSingleColumn); 106 }); 107 108 test('isSingleColumn is true when there are multiple datacenters with a high variance in node count', async function(assert) { 109 const uniformDcs = [ 110 { datacenter: 'dc1', id: 'node0', resources: {} }, 111 { datacenter: 'dc2', id: 'node1', resources: {} }, 112 ]; 113 const skewedDcs = [ 114 { datacenter: 'dc1', id: 'node0', resources: {} }, 115 { datacenter: 'dc2', id: 'node1', resources: {} }, 116 { datacenter: 'dc2', id: 'node2', resources: {} }, 117 { datacenter: 'dc2', id: 'node3', resources: {} }, 118 { datacenter: 'dc2', id: 'node4', resources: {} }, 119 ]; 120 121 const twoColumnViz = this.createComponent({ nodes: uniformDcs, allocations: [] }); 122 const oneColumViz = this.createComponent({ nodes: skewedDcs, allocations: [] }); 123 124 twoColumnViz.buildTopology(); 125 oneColumViz.buildTopology(); 126 127 assert.notOk(twoColumnViz.isSingleColumn); 128 assert.ok(oneColumViz.isSingleColumn); 129 }); 130 131 test('datacenterIsSingleColumn is only ever false when isSingleColumn is false and the total node count is high', async function(assert) { 132 const manyUniformNodes = Array(25) 133 .fill(null) 134 .map((_, index) => ({ 135 datacenter: index > 12 ? 'dc2' : 'dc1', 136 id: `node${index}`, 137 resources: {}, 138 })); 139 const manySkewedNodes = Array(25) 140 .fill(null) 141 .map((_, index) => ({ 142 datacenter: index > 5 ? 'dc2' : 'dc1', 143 id: `node${index}`, 144 resources: {}, 145 })); 146 147 const oneColumnViz = this.createComponent({ nodes: manyUniformNodes, allocations: [] }); 148 const twoColumnViz = this.createComponent({ nodes: manySkewedNodes, allocations: [] }); 149 150 oneColumnViz.buildTopology(); 151 twoColumnViz.buildTopology(); 152 153 assert.ok(oneColumnViz.datacenterIsSingleColumn); 154 assert.notOk(oneColumnViz.isSingleColumn); 155 156 assert.notOk(twoColumnViz.datacenterIsSingleColumn); 157 assert.ok(twoColumnViz.isSingleColumn); 158 }); 159 160 test('dataForAllocation correctly calculates proportion of node utilization and group key', async function(assert) { 161 const nodes = [{ datacenter: 'dc1', id: 'node0', resources: { cpu: 100, memory: 250 } }]; 162 const allocations = [ 163 alloc({ 164 nodeId: 'node0', 165 jobId: 'job0', 166 taskGroupName: 'group', 167 allocatedResources: { cpu: 50, memory: 25 }, 168 }), 169 ]; 170 171 const topoViz = this.createComponent({ nodes, allocations }); 172 topoViz.buildTopology(); 173 174 assert.equal(topoViz.topology.datacenters[0].nodes[0].allocations[0].cpuPercent, 0.5); 175 assert.equal(topoViz.topology.datacenters[0].nodes[0].allocations[0].memoryPercent, 0.1); 176 }); 177 178 test('allocations that reference nonexistent nodes are ignored', async function(assert) { 179 const nodes = [{ datacenter: 'dc1', id: 'node0', resources: {} }]; 180 181 const allocations = [ 182 alloc({ nodeId: 'node0', jobId: 'job0', taskGroupName: 'group' }), 183 alloc({ nodeId: 'node404', jobId: 'job1', taskGroupName: 'group' }), 184 ]; 185 186 const topoViz = this.createComponent({ nodes, allocations }); 187 188 topoViz.buildTopology(); 189 190 assert.deepEqual(topoViz.topology.datacenters[0].nodes.mapBy('node'), [nodes[0]]); 191 assert.deepEqual(topoViz.topology.datacenters[0].nodes[0].allocations.mapBy('allocation'), [ 192 allocations[0], 193 ]); 194 }); 195 }); 196 197 function alloc(props) { 198 return { 199 ...props, 200 allocatedResources: props.allocatedResources || {}, 201 belongsTo(type) { 202 return { 203 id() { 204 return type === 'job' ? props.jobId : props.nodeId; 205 }, 206 }; 207 }, 208 }; 209 }