3350f3fb11
Async tests should use in integrations tests. Acceptance tests are using Mirage and can't use since we can't know the number of assertions.
245 lines
7.8 KiB
JavaScript
245 lines
7.8 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) {
|
|
assert.expect(7);
|
|
|
|
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;
|
|
},
|
|
};
|
|
},
|
|
};
|
|
}
|