open-nomad/ui/tests/unit/components/topo-viz-test.js
2020-12-17 11:18:43 -08:00

210 lines
7.6 KiB
JavaScript

import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import setupGlimmerComponentFactory from 'nomad-ui/tests/helpers/glimmer-factory';
module('Unit | Component | TopoViz', function(hooks) {
setupTest(hooks);
setupGlimmerComponentFactory(hooks, 'topo-viz');
test('the topology object properly organizes a tree of datacenters > nodes > allocations', async function(assert) {
const nodes = [
{ datacenter: 'dc1', id: 'node0', resources: {} },
{ datacenter: 'dc2', id: 'node1', resources: {} },
{ datacenter: 'dc1', id: 'node2', resources: {} },
];
const node0Allocs = [
alloc({ nodeId: 'node0', jobId: 'job0', taskGroupName: 'group' }),
alloc({ nodeId: 'node0', jobId: 'job1', taskGroupName: 'group' }),
];
const node1Allocs = [
alloc({ nodeId: 'node1', jobId: 'job0', taskGroupName: 'group' }),
alloc({ nodeId: 'node1', jobId: 'job1', taskGroupName: 'group' }),
];
const node2Allocs = [
alloc({ nodeId: 'node2', jobId: 'job0', taskGroupName: 'group' }),
alloc({ nodeId: 'node2', jobId: 'job1', taskGroupName: 'group' }),
];
const allocations = [...node0Allocs, ...node1Allocs, ...node2Allocs];
const topoViz = this.createComponent({ nodes, allocations });
topoViz.buildTopology();
assert.deepEqual(topoViz.topology.datacenters.mapBy('name'), ['dc1', 'dc2']);
assert.deepEqual(topoViz.topology.datacenters[0].nodes.mapBy('node'), [nodes[0], nodes[2]]);
assert.deepEqual(topoViz.topology.datacenters[1].nodes.mapBy('node'), [nodes[1]]);
assert.deepEqual(
topoViz.topology.datacenters[0].nodes[0].allocations.mapBy('allocation'),
node0Allocs
);
assert.deepEqual(
topoViz.topology.datacenters[1].nodes[0].allocations.mapBy('allocation'),
node1Allocs
);
assert.deepEqual(
topoViz.topology.datacenters[0].nodes[1].allocations.mapBy('allocation'),
node2Allocs
);
});
test('the topology object contains an allocation index keyed by jobId+taskGroupName', async function(assert) {
const allocations = [
alloc({ nodeId: 'node0', jobId: 'job0', taskGroupName: 'one' }),
alloc({ nodeId: 'node0', jobId: 'job0', taskGroupName: 'one' }),
alloc({ nodeId: 'node0', jobId: 'job0', taskGroupName: 'two' }),
alloc({ nodeId: 'node0', jobId: 'job1', taskGroupName: 'one' }),
alloc({ nodeId: 'node0', jobId: 'job1', taskGroupName: 'two' }),
alloc({ nodeId: 'node0', jobId: 'job1', taskGroupName: 'three' }),
alloc({ nodeId: 'node0', jobId: 'job2', taskGroupName: 'one' }),
alloc({ nodeId: 'node0', jobId: 'job2', taskGroupName: 'one' }),
alloc({ nodeId: 'node0', jobId: 'job2', taskGroupName: 'one' }),
alloc({ nodeId: 'node0', jobId: 'job2', taskGroupName: 'one' }),
];
const nodes = [{ datacenter: 'dc1', id: 'node0', resources: {} }];
const topoViz = this.createComponent({ nodes, allocations });
topoViz.buildTopology();
assert.deepEqual(
Object.keys(topoViz.topology.allocationIndex).sort(),
[
JSON.stringify(['job0', 'one']),
JSON.stringify(['job0', 'two']),
JSON.stringify(['job1', 'one']),
JSON.stringify(['job1', 'two']),
JSON.stringify(['job1', 'three']),
JSON.stringify(['job2', 'one']),
].sort()
);
Object.keys(topoViz.topology.allocationIndex).forEach(key => {
const [jobId, group] = JSON.parse(key);
assert.deepEqual(
topoViz.topology.allocationIndex[key].mapBy('allocation'),
allocations.filter(alloc => alloc.jobId === jobId && alloc.taskGroupName === group)
);
});
});
test('isSingleColumn is true when there is only one datacenter', async function(assert) {
const oneDc = [{ datacenter: 'dc1', id: 'node0', resources: {} }];
const twoDc = [...oneDc, { datacenter: 'dc2', id: 'node1', resources: {} }];
const topoViz1 = this.createComponent({ nodes: oneDc, allocations: [] });
const topoViz2 = this.createComponent({ nodes: twoDc, allocations: [] });
topoViz1.buildTopology();
topoViz2.buildTopology();
assert.ok(topoViz1.isSingleColumn);
assert.notOk(topoViz2.isSingleColumn);
});
test('isSingleColumn is true when there are multiple datacenters with a high variance in node count', async function(assert) {
const uniformDcs = [
{ datacenter: 'dc1', id: 'node0', resources: {} },
{ datacenter: 'dc2', id: 'node1', resources: {} },
];
const skewedDcs = [
{ datacenter: 'dc1', id: 'node0', resources: {} },
{ datacenter: 'dc2', id: 'node1', resources: {} },
{ datacenter: 'dc2', id: 'node2', resources: {} },
{ datacenter: 'dc2', id: 'node3', resources: {} },
{ datacenter: 'dc2', id: 'node4', resources: {} },
];
const twoColumnViz = this.createComponent({ nodes: uniformDcs, allocations: [] });
const oneColumViz = this.createComponent({ nodes: skewedDcs, allocations: [] });
twoColumnViz.buildTopology();
oneColumViz.buildTopology();
assert.notOk(twoColumnViz.isSingleColumn);
assert.ok(oneColumViz.isSingleColumn);
});
test('datacenterIsSingleColumn is only ever false when isSingleColumn is false and the total node count is high', async function(assert) {
const manyUniformNodes = Array(25)
.fill(null)
.map((_, index) => ({
datacenter: index > 12 ? 'dc2' : 'dc1',
id: `node${index}`,
resources: {},
}));
const manySkewedNodes = Array(25)
.fill(null)
.map((_, index) => ({
datacenter: index > 5 ? 'dc2' : 'dc1',
id: `node${index}`,
resources: {},
}));
const oneColumnViz = this.createComponent({ nodes: manyUniformNodes, allocations: [] });
const twoColumnViz = this.createComponent({ nodes: manySkewedNodes, allocations: [] });
oneColumnViz.buildTopology();
twoColumnViz.buildTopology();
assert.ok(oneColumnViz.datacenterIsSingleColumn);
assert.notOk(oneColumnViz.isSingleColumn);
assert.notOk(twoColumnViz.datacenterIsSingleColumn);
assert.ok(twoColumnViz.isSingleColumn);
});
test('dataForAllocation correctly calculates proportion of node utilization and group key', async function(assert) {
const nodes = [{ datacenter: 'dc1', id: 'node0', resources: { cpu: 100, memory: 250 } }];
const allocations = [
alloc({
nodeId: 'node0',
jobId: 'job0',
taskGroupName: 'group',
allocatedResources: { cpu: 50, memory: 25 },
}),
];
const topoViz = this.createComponent({ nodes, allocations });
topoViz.buildTopology();
assert.equal(topoViz.topology.datacenters[0].nodes[0].allocations[0].cpuPercent, 0.5);
assert.equal(topoViz.topology.datacenters[0].nodes[0].allocations[0].memoryPercent, 0.1);
});
test('allocations that reference nonexistent nodes are ignored', async function(assert) {
const nodes = [{ datacenter: 'dc1', id: 'node0', resources: {} }];
const allocations = [
alloc({ nodeId: 'node0', jobId: 'job0', taskGroupName: 'group' }),
alloc({ nodeId: 'node404', jobId: 'job1', taskGroupName: 'group' }),
];
const topoViz = this.createComponent({ nodes, allocations });
topoViz.buildTopology();
assert.deepEqual(topoViz.topology.datacenters[0].nodes.mapBy('node'), [nodes[0]]);
assert.deepEqual(topoViz.topology.datacenters[0].nodes[0].allocations.mapBy('allocation'), [
allocations[0],
]);
});
});
function alloc(props) {
return {
...props,
allocatedResources: props.allocatedResources || {},
belongsTo(type) {
return {
id() {
return type === 'job' ? props.jobId : props.nodeId;
},
};
},
};
}