mirror of
https://github.com/kemko/nomad.git
synced 2026-01-05 09:55:44 +03:00
Test coverage for the topology info panel.
This fixes a couple bugs 1. Overreporting resources reserved due to counting terminal allocs 2. Overreporting unique client placements due to uniquing on object refs instead of on client ID.
This commit is contained in:
@@ -47,15 +47,17 @@ export default class TopologyControllers extends Controller {
|
||||
return reduceToLargestUnit(this.totalMemory)[1];
|
||||
}
|
||||
|
||||
@computed('model.allocations.@each.allocatedResources')
|
||||
@computed('scheduledAllocations.@each.allocatedResources')
|
||||
get totalReservedMemory() {
|
||||
const mibs = this.model.allocations.mapBy('allocatedResources.memory').reduce(sumAggregator, 0);
|
||||
const mibs = this.scheduledAllocations
|
||||
.mapBy('allocatedResources.memory')
|
||||
.reduce(sumAggregator, 0);
|
||||
return mibs * 1024 * 1024;
|
||||
}
|
||||
|
||||
@computed('model.allocations.@each.allocatedResources')
|
||||
@computed('scheduledAllocations.@each.allocatedResources')
|
||||
get totalReservedCPU() {
|
||||
return this.model.allocations.mapBy('allocatedResources.cpu').reduce(sumAggregator, 0);
|
||||
return this.scheduledAllocations.mapBy('allocatedResources.cpu').reduce(sumAggregator, 0);
|
||||
}
|
||||
|
||||
@computed('totalMemory', 'totalReservedMemory')
|
||||
@@ -70,13 +72,13 @@ export default class TopologyControllers extends Controller {
|
||||
return this.totalReservedCPU / this.totalCPU;
|
||||
}
|
||||
|
||||
@computed('activeAllocation', 'model.allocations.@each.{taskGroupName,job}')
|
||||
@computed('activeAllocation', 'scheduledAllocations.@each.{taskGroupName,job}')
|
||||
get siblingAllocations() {
|
||||
if (!this.activeAllocation) return [];
|
||||
const taskGroup = this.activeAllocation.taskGroupName;
|
||||
const jobId = this.activeAllocation.belongsTo('job').id();
|
||||
|
||||
return this.model.allocations.filter(allocation => {
|
||||
return this.scheduledAllocations.filter(allocation => {
|
||||
return allocation.taskGroupName === taskGroup && allocation.belongsTo('job').id() === jobId;
|
||||
});
|
||||
}
|
||||
@@ -104,7 +106,7 @@ export default class TopologyControllers extends Controller {
|
||||
|
||||
@computed('siblingAllocations.@each.node')
|
||||
get uniqueActiveAllocationNodes() {
|
||||
return this.siblingAllocations.mapBy('node').uniq();
|
||||
return this.siblingAllocations.mapBy('node.id').uniq();
|
||||
}
|
||||
|
||||
@action
|
||||
|
||||
@@ -60,29 +60,29 @@
|
||||
<div data-test-info-panel-title class="boxed-section-head">
|
||||
{{#if this.activeNode}}Client{{else if this.activeAllocation}}Allocation{{else}}Cluster{{/if}} Details
|
||||
</div>
|
||||
<div class="boxed-section-body">
|
||||
<div data-test-info-panel class="boxed-section-body">
|
||||
{{#if this.activeNode}}
|
||||
{{#let this.activeNode.node as |node|}}
|
||||
<div class="dashboard-metric">
|
||||
<p class="metric">{{this.activeNode.allocations.length}} <span class="metric-label">Allocations</span></p>
|
||||
<p data-test-allocations class="metric">{{this.activeNode.allocations.length}} <span class="metric-label">Allocations</span></p>
|
||||
</div>
|
||||
<div class="dashboard-metric">
|
||||
<h3 class="pair">
|
||||
<strong>Client:</strong>
|
||||
<LinkTo @route="clients.client" @model={{node}}>
|
||||
<LinkTo data-test-client-link @route="clients.client" @model={{node}}>
|
||||
{{node.shortId}}
|
||||
</LinkTo>
|
||||
</h3>
|
||||
<p class="minor-pair"><strong>Name:</strong> {{node.name}}</p>
|
||||
<p class="minor-pair"><strong>Address:</strong> {{node.httpAddr}}</p>
|
||||
<p class="minor-pair"><strong>Status:</strong> {{node.status}}</p>
|
||||
<p data-test-name class="minor-pair"><strong>Name:</strong> {{node.name}}</p>
|
||||
<p data-test-address class="minor-pair"><strong>Address:</strong> {{node.httpAddr}}</p>
|
||||
<p data-test-status class="minor-pair"><strong>Status:</strong> {{node.status}}</p>
|
||||
</div>
|
||||
<div class="dashboard-metric">
|
||||
<h3 class="pair">
|
||||
<strong>Draining?</strong> <span class="{{if node.isDraining "status-text is-info"}}">{{if node.isDraining "Yes" "No"}}</span>
|
||||
<strong>Draining?</strong> <span data-test-draining class="{{if node.isDraining "status-text is-info"}}">{{if node.isDraining "Yes" "No"}}</span>
|
||||
</h3>
|
||||
<h3 class="pair">
|
||||
<strong>Eligible?</strong> <span class="{{unless node.isEligible "status-text is-warning"}}">{{if node.isEligible "Yes" "No"}}</span>
|
||||
<strong>Eligible?</strong> <span data-test-eligible class="{{unless node.isEligible "status-text is-warning"}}">{{if node.isEligible "Yes" "No"}}</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="dashboard-metric with-divider">
|
||||
@@ -93,8 +93,9 @@
|
||||
</p>
|
||||
<div class="columns graphic">
|
||||
<div class="column">
|
||||
<div class="inline-chart" data-test-percentage-bar>
|
||||
<div class="inline-chart">
|
||||
<progress
|
||||
data-test-memory-progress-bar
|
||||
class="progress is-danger is-small"
|
||||
value="{{this.nodeUtilization.reservedMemoryPercent}}"
|
||||
max="1">
|
||||
@@ -106,7 +107,7 @@
|
||||
<span class="nowrap" data-test-percentage>{{format-percentage this.nodeUtilization.reservedMemoryPercent total=1}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="annotation" data-test-absolute-value>
|
||||
<div class="annotation" data-test-memory-absolute-value>
|
||||
<strong>{{format-bytes this.nodeUtilization.totalReservedMemory}}</strong> / {{format-bytes this.nodeUtilization.totalMemory}} reserved
|
||||
</div>
|
||||
</div>
|
||||
@@ -116,6 +117,7 @@
|
||||
<div class="column">
|
||||
<div class="inline-chart" data-test-percentage-bar>
|
||||
<progress
|
||||
data-test-cpu-progress-bar
|
||||
class="progress is-info is-small"
|
||||
value="{{this.nodeUtilization.reservedCPUPercent}}"
|
||||
max="1">
|
||||
@@ -127,7 +129,7 @@
|
||||
<span class="nowrap" data-test-percentage>{{format-percentage this.nodeUtilization.reservedCPUPercent total=1}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="annotation" data-test-absolute-value>
|
||||
<div class="annotation" data-test-cpu-absolute-value>
|
||||
<strong>{{this.nodeUtilization.totalReservedCPU}} Mhz</strong> / {{this.nodeUtilization.totalCPU}} Mhz reserved
|
||||
</div>
|
||||
</div>
|
||||
@@ -136,18 +138,19 @@
|
||||
<div class="dashboard-metric">
|
||||
<h3 class="pair">
|
||||
<strong>Allocation:</strong>
|
||||
<LinkTo @route="allocations.allocation" @model={{this.activeAllocation}} class="is-primary">{{this.activeAllocation.shortId}}</LinkTo>
|
||||
<LinkTo data-test-id @route="allocations.allocation" @model={{this.activeAllocation}} class="is-primary">{{this.activeAllocation.shortId}}</LinkTo>
|
||||
</h3>
|
||||
<p class="minor-pair"><strong>Sibling Allocations:</strong> {{this.siblingAllocations.length}}</p>
|
||||
<p class="minor-pair"><strong>Unique Client Placements:</strong> {{this.uniqueActiveAllocationNodes.length}}</p>
|
||||
<p data-test-sibling-allocs class="minor-pair"><strong>Sibling Allocations:</strong> {{this.siblingAllocations.length}}</p>
|
||||
<p data-test-unique-placements class="minor-pair"><strong>Unique Client Placements:</strong> {{this.uniqueActiveAllocationNodes.length}}</p>
|
||||
</div>
|
||||
<div class="dashboard-metric with-divider">
|
||||
<h3 class="pair">
|
||||
<strong>Job:</strong>
|
||||
<LinkTo
|
||||
data-test-job
|
||||
@route="jobs.job"
|
||||
@model={{this.activeAllocation.job}}
|
||||
@query={{hash jobNamespace=this.activeAllocation.job.namespace.id}} data-test-job>
|
||||
@query={{hash jobNamespace=this.activeAllocation.job.namespace.id}}>
|
||||
{{this.activeAllocation.job.name}}</LinkTo>
|
||||
<span class="is-faded" data-test-task-group> / {{this.activeAllocation.taskGroupName}}</span>
|
||||
</h3>
|
||||
@@ -157,7 +160,7 @@
|
||||
<div class="dashboard-metric with-divider">
|
||||
<h3 class="pair">
|
||||
<strong>Client:</strong>
|
||||
<LinkTo @route="clients.client" @model={{this.activeAllocation.node}}>
|
||||
<LinkTo data-test-client @route="clients.client" @model={{this.activeAllocation.node}}>
|
||||
{{this.activeAllocation.node.shortId}}
|
||||
</LinkTo>
|
||||
</h3>
|
||||
@@ -173,10 +176,10 @@
|
||||
{{else}}
|
||||
<div class="columns is-flush">
|
||||
<div class="dashboard-metric column">
|
||||
<p class="metric">{{this.model.nodes.length}} <span class="metric-label">Clients</span></p>
|
||||
<p data-test-node-count class="metric">{{this.model.nodes.length}} <span class="metric-label">Clients</span></p>
|
||||
</div>
|
||||
<div class="dashboard-metric column">
|
||||
<p class="metric">{{this.scheduledAllocations.length}} <span class="metric-label">Allocations</span></p>
|
||||
<p data-test-alloc-count class="metric">{{this.scheduledAllocations.length}} <span class="metric-label">Allocations</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dashboard-metric with-divider">
|
||||
@@ -185,6 +188,7 @@
|
||||
<div class="column">
|
||||
<div class="inline-chart" data-test-percentage-bar>
|
||||
<progress
|
||||
data-test-memory-progress-bar
|
||||
class="progress is-danger is-small"
|
||||
value="{{this.reservedMemoryPercent}}"
|
||||
max="1">
|
||||
@@ -193,10 +197,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-minimum">
|
||||
<span class="nowrap" data-test-percentage>{{format-percentage this.reservedMemoryPercent total=1}}</span>
|
||||
<span class="nowrap" data-test-memory-percentage>{{format-percentage this.reservedMemoryPercent total=1}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="annotation" data-test-absolute-value>
|
||||
<div class="annotation" data-test-memory-absolute-value>
|
||||
<strong>{{format-bytes this.totalReservedMemory}}</strong> / {{format-bytes this.totalMemory}} reserved
|
||||
</div>
|
||||
</div>
|
||||
@@ -206,6 +210,7 @@
|
||||
<div class="column">
|
||||
<div class="inline-chart" data-test-percentage-bar>
|
||||
<progress
|
||||
data-test-cpu-progress-bar
|
||||
class="progress is-info is-small"
|
||||
value="{{this.reservedCPUPercent}}"
|
||||
max="1">
|
||||
@@ -214,10 +219,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-minimum">
|
||||
<span class="nowrap" data-test-percentage>{{format-percentage this.reservedCPUPercent total=1}}</span>
|
||||
<span class="nowrap" data-test-cpu-percentage>{{format-percentage this.reservedCPUPercent total=1}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="annotation" data-test-absolute-value>
|
||||
<div class="annotation" data-test-cpu-absolute-value>
|
||||
<strong>{{this.totalReservedCPU}} Mhz</strong> / {{this.totalCPU}} Mhz reserved
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { get } from '@ember/object';
|
||||
import { currentURL } from '@ember/test-helpers';
|
||||
import { module, test } from 'qunit';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit';
|
||||
import Topology from 'nomad-ui/tests/pages/topology';
|
||||
import { reduceToLargestUnit } from 'nomad-ui/helpers/format-bytes';
|
||||
import queryString from 'query-string';
|
||||
|
||||
// TODO: Once we settle on the contents of the info panel, the contents
|
||||
// should also get acceptance tests.
|
||||
const sumResources = (list, dimension) =>
|
||||
list.reduce((agg, val) => agg + (get(val, dimension) || 0), 0);
|
||||
|
||||
module('Acceptance | topology', function(hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
@@ -30,6 +34,44 @@ module('Acceptance | topology', function(hooks) {
|
||||
await Topology.visit();
|
||||
assert.equal(Topology.infoPanelTitle, 'Cluster Details');
|
||||
assert.notOk(Topology.filteredNodesWarning.isPresent);
|
||||
|
||||
assert.equal(
|
||||
Topology.clusterInfoPanel.nodeCount,
|
||||
`${server.schema.nodes.all().length} Clients`
|
||||
);
|
||||
|
||||
const allocs = server.schema.allocations.all().models;
|
||||
const scheduledAllocs = allocs.filter(alloc =>
|
||||
['pending', 'running'].includes(alloc.clientStatus)
|
||||
);
|
||||
assert.equal(Topology.clusterInfoPanel.allocCount, `${scheduledAllocs.length} Allocations`);
|
||||
|
||||
const nodeResources = server.schema.nodes.all().models.mapBy('nodeResources');
|
||||
const taskResources = scheduledAllocs
|
||||
.mapBy('taskResources.models')
|
||||
.flat()
|
||||
.mapBy('resources');
|
||||
|
||||
const totalMem = sumResources(nodeResources, 'Memory.MemoryMB');
|
||||
const totalCPU = sumResources(nodeResources, 'Cpu.CpuShares');
|
||||
const reservedMem = sumResources(taskResources, 'Memory.MemoryMB');
|
||||
const reservedCPU = sumResources(taskResources, 'Cpu.CpuShares');
|
||||
|
||||
assert.equal(Topology.clusterInfoPanel.memoryProgressValue, reservedMem / totalMem);
|
||||
assert.equal(Topology.clusterInfoPanel.cpuProgressValue, reservedCPU / totalCPU);
|
||||
|
||||
const [rNum, rUnit] = reduceToLargestUnit(reservedMem * 1024 * 1024);
|
||||
const [tNum, tUnit] = reduceToLargestUnit(totalMem * 1024 * 1024);
|
||||
|
||||
assert.equal(
|
||||
Topology.clusterInfoPanel.memoryAbsoluteValue,
|
||||
`${Math.floor(rNum)} ${rUnit} / ${Math.floor(tNum)} ${tUnit} reserved`
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
Topology.clusterInfoPanel.cpuAbsoluteValue,
|
||||
`${reservedCPU} Mhz / ${totalCPU} Mhz reserved`
|
||||
);
|
||||
});
|
||||
|
||||
test('all allocations for all namespaces and all clients are queried on load', async function(assert) {
|
||||
@@ -52,28 +94,126 @@ module('Acceptance | topology', function(hooks) {
|
||||
});
|
||||
|
||||
test('when an allocation is selected, the info panel shows information on the allocation', async function(assert) {
|
||||
server.createList('node', 1);
|
||||
server.createList('allocation', 5);
|
||||
const nodes = server.createList('node', 5);
|
||||
const job = server.create('job', { createAllocations: false });
|
||||
const taskGroup = server.schema.find('taskGroup', job.taskGroupIds[0]).name;
|
||||
const allocs = server.createList('allocation', 5, {
|
||||
forceRunningClientStatus: true,
|
||||
jobId: job.id,
|
||||
taskGroup,
|
||||
});
|
||||
|
||||
await Topology.visit();
|
||||
|
||||
if (Topology.viz.datacenters[0].nodes[0].isEmpty) {
|
||||
assert.expect(0);
|
||||
} else {
|
||||
await Topology.viz.datacenters[0].nodes[0].memoryRects[0].select();
|
||||
assert.equal(Topology.infoPanelTitle, 'Allocation Details');
|
||||
// Get the first alloc of the first node that has an alloc
|
||||
const sortedNodes = nodes.sortBy('datacenter');
|
||||
let node, alloc;
|
||||
for (let n of sortedNodes) {
|
||||
alloc = allocs.find(a => a.nodeId === n.id);
|
||||
if (alloc) {
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const dcIndex = nodes
|
||||
.mapBy('datacenter')
|
||||
.uniq()
|
||||
.sort()
|
||||
.indexOf(node.datacenter);
|
||||
const nodeIndex = nodes.filterBy('datacenter', node.datacenter).indexOf(node);
|
||||
|
||||
const reset = async () => {
|
||||
await Topology.visit();
|
||||
await Topology.viz.datacenters[dcIndex].nodes[nodeIndex].memoryRects[0].select();
|
||||
};
|
||||
|
||||
await reset();
|
||||
assert.equal(Topology.infoPanelTitle, 'Allocation Details');
|
||||
|
||||
assert.equal(Topology.allocInfoPanel.id, alloc.id.split('-')[0]);
|
||||
|
||||
const uniqueClients = allocs.mapBy('nodeId').uniq();
|
||||
assert.equal(Topology.allocInfoPanel.siblingAllocs, `Sibling Allocations: ${allocs.length}`);
|
||||
assert.equal(
|
||||
Topology.allocInfoPanel.uniquePlacements,
|
||||
`Unique Client Placements: ${uniqueClients.length}`
|
||||
);
|
||||
|
||||
assert.equal(Topology.allocInfoPanel.job, job.name);
|
||||
assert.ok(Topology.allocInfoPanel.taskGroup.endsWith(alloc.taskGroup));
|
||||
assert.equal(Topology.allocInfoPanel.client, node.id.split('-')[0]);
|
||||
|
||||
await Topology.allocInfoPanel.visitAlloc();
|
||||
assert.equal(currentURL(), `/allocations/${alloc.id}`);
|
||||
|
||||
await reset();
|
||||
|
||||
await Topology.allocInfoPanel.visitJob();
|
||||
assert.equal(currentURL(), `/jobs/${job.id}`);
|
||||
|
||||
await reset();
|
||||
|
||||
await Topology.allocInfoPanel.visitClient();
|
||||
assert.equal(currentURL(), `/clients/${node.id}`);
|
||||
});
|
||||
|
||||
test('when a node is selected, the info panel shows information on the node', async function(assert) {
|
||||
// A high node count is required for node selection
|
||||
server.createList('node', 51);
|
||||
server.createList('allocation', 5);
|
||||
const nodes = server.createList('node', 51);
|
||||
const node = nodes.sortBy('datacenter')[0];
|
||||
server.createList('allocation', 5, { forceRunningClientStatus: true });
|
||||
|
||||
const allocs = server.schema.allocations.where({ nodeId: node.id }).models;
|
||||
|
||||
await Topology.visit();
|
||||
|
||||
await Topology.viz.datacenters[0].nodes[0].selectNode();
|
||||
assert.equal(Topology.infoPanelTitle, 'Client Details');
|
||||
|
||||
assert.equal(Topology.nodeInfoPanel.id, node.id.split('-')[0]);
|
||||
assert.equal(Topology.nodeInfoPanel.name, `Name: ${node.name}`);
|
||||
assert.equal(Topology.nodeInfoPanel.address, `Address: ${node.httpAddr}`);
|
||||
assert.equal(Topology.nodeInfoPanel.status, `Status: ${node.status}`);
|
||||
|
||||
assert.equal(Topology.nodeInfoPanel.drainingLabel, node.drain ? 'Yes' : 'No');
|
||||
assert.equal(
|
||||
Topology.nodeInfoPanel.eligibleLabel,
|
||||
node.schedulingEligibility === 'eligible' ? 'Yes' : 'No'
|
||||
);
|
||||
|
||||
assert.equal(Topology.nodeInfoPanel.drainingIsAccented, node.drain);
|
||||
assert.equal(
|
||||
Topology.nodeInfoPanel.eligibleIsAccented,
|
||||
node.schedulingEligibility !== 'eligible'
|
||||
);
|
||||
|
||||
const taskResources = allocs
|
||||
.mapBy('taskResources.models')
|
||||
.flat()
|
||||
.mapBy('resources');
|
||||
const reservedMem = sumResources(taskResources, 'Memory.MemoryMB');
|
||||
const reservedCPU = sumResources(taskResources, 'Cpu.CpuShares');
|
||||
|
||||
const totalMem = node.nodeResources.Memory.MemoryMB;
|
||||
const totalCPU = node.nodeResources.Cpu.CpuShares;
|
||||
|
||||
assert.equal(Topology.nodeInfoPanel.memoryProgressValue, reservedMem / totalMem);
|
||||
assert.equal(Topology.nodeInfoPanel.cpuProgressValue, reservedCPU / totalCPU);
|
||||
|
||||
const [rNum, rUnit] = reduceToLargestUnit(reservedMem * 1024 * 1024);
|
||||
const [tNum, tUnit] = reduceToLargestUnit(totalMem * 1024 * 1024);
|
||||
|
||||
assert.equal(
|
||||
Topology.nodeInfoPanel.memoryAbsoluteValue,
|
||||
`${Math.floor(rNum)} ${rUnit} / ${Math.floor(tNum)} ${tUnit} reserved`
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
Topology.nodeInfoPanel.cpuAbsoluteValue,
|
||||
`${reservedCPU} Mhz / ${totalCPU} Mhz reserved`
|
||||
);
|
||||
|
||||
await Topology.nodeInfoPanel.visitNode();
|
||||
assert.equal(currentURL(), `/clients/${node.id}`);
|
||||
});
|
||||
|
||||
test('when one or more nodes lack the NodeResources property, a warning message is shown', async function(assert) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { create, text, visitable } from 'ember-cli-page-object';
|
||||
import { attribute, clickable, create, hasClass, text, visitable } from 'ember-cli-page-object';
|
||||
|
||||
import TopoViz from 'nomad-ui/tests/pages/components/topo-viz';
|
||||
import notification from 'nomad-ui/tests/pages/components/notification';
|
||||
@@ -10,4 +10,54 @@ export default create({
|
||||
filteredNodesWarning: notification('[data-test-filtered-nodes-warning]'),
|
||||
|
||||
viz: TopoViz('[data-test-topo-viz]'),
|
||||
|
||||
clusterInfoPanel: {
|
||||
scope: '[data-test-info-panel]',
|
||||
nodeCount: text('[data-test-node-count]'),
|
||||
allocCount: text('[data-test-alloc-count]'),
|
||||
|
||||
memoryProgressValue: attribute('value', '[data-test-memory-progress-bar]'),
|
||||
memoryAbsoluteValue: text('[data-test-memory-absolute-value]'),
|
||||
cpuProgressValue: attribute('value', '[data-test-cpu-progress-bar]'),
|
||||
cpuAbsoluteValue: text('[data-test-cpu-absolute-value]'),
|
||||
},
|
||||
|
||||
nodeInfoPanel: {
|
||||
scope: '[data-test-info-panel]',
|
||||
allocations: text('[data-test-allocaions]'),
|
||||
|
||||
visitNode: clickable('[data-test-client-link]'),
|
||||
|
||||
id: text('[data-test-client-link]'),
|
||||
name: text('[data-test-name]'),
|
||||
address: text('[data-test-address]'),
|
||||
status: text('[data-test-status]'),
|
||||
|
||||
drainingLabel: text('[data-test-draining]'),
|
||||
drainingIsAccented: hasClass('is-info', '[data-test-draining]'),
|
||||
|
||||
eligibleLabel: text('[data-test-eligible]'),
|
||||
eligibleIsAccented: hasClass('is-warning', '[data-test-eligible]'),
|
||||
|
||||
memoryProgressValue: attribute('value', '[data-test-memory-progress-bar]'),
|
||||
memoryAbsoluteValue: text('[data-test-memory-absolute-value]'),
|
||||
cpuProgressValue: attribute('value', '[data-test-cpu-progress-bar]'),
|
||||
cpuAbsoluteValue: text('[data-test-cpu-absolute-value]'),
|
||||
},
|
||||
|
||||
allocInfoPanel: {
|
||||
scope: '[data-test-info-panel]',
|
||||
id: text('[data-test-id]'),
|
||||
visitAlloc: clickable('[data-test-id]'),
|
||||
|
||||
siblingAllocs: text('[data-test-sibling-allocs]'),
|
||||
uniquePlacements: text('[data-test-unique-placements]'),
|
||||
|
||||
job: text('[data-test-job]'),
|
||||
visitJob: clickable('[data-test-job]'),
|
||||
taskGroup: text('[data-test-task-group]'),
|
||||
|
||||
client: text('[data-test-client]'),
|
||||
visitClient: clickable('[data-test-client]'),
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user