ui: fix remaining linting errors
This commit is contained in:
parent
3350f3fb11
commit
52cf998e2c
|
@ -21,14 +21,14 @@ export default class Client extends AbstractAbility {
|
|||
get policiesIncludeNodeRead() {
|
||||
return policiesIncludePermissions(this.get('token.selfTokenPolicies'), [
|
||||
'read',
|
||||
'write'
|
||||
'write',
|
||||
]);
|
||||
}
|
||||
|
||||
@computed('token.selfTokenPolicies.[]')
|
||||
get policiesIncludeNodeWrite() {
|
||||
return policiesIncludePermissions(this.get('token.selfTokenPolicies'), [
|
||||
'write'
|
||||
'write',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -37,9 +37,9 @@ function policiesIncludePermissions(policies = [], permissions = []) {
|
|||
// For each policy record, extract the Node policy
|
||||
const nodePolicies = policies
|
||||
.toArray()
|
||||
.map(policy => get(policy, 'rulesJSON.Node.Policy'))
|
||||
.map((policy) => get(policy, 'rulesJSON.Node.Policy'))
|
||||
.compact();
|
||||
|
||||
// Check for requested permissions
|
||||
return nodePolicies.some(policy => permissions.includes(policy));
|
||||
return nodePolicies.some((policy) => permissions.includes(policy));
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ export default class Trigger extends Component {
|
|||
this.error = null;
|
||||
}
|
||||
|
||||
@task(function*() {
|
||||
@task(function* () {
|
||||
this._reset();
|
||||
try {
|
||||
this.result = yield this.args.do();
|
||||
|
|
|
@ -35,7 +35,12 @@ export default class AllocationsAllocationController extends Controller {
|
|||
{
|
||||
title: 'Task Group',
|
||||
label: allocation.taskGroupName,
|
||||
args: ['jobs.job.task-group', job.plainId, allocation.taskGroupName, jobQueryParams],
|
||||
args: [
|
||||
'jobs.job.task-group',
|
||||
job.plainId,
|
||||
allocation.taskGroupName,
|
||||
jobQueryParams,
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Allocation',
|
||||
|
|
|
@ -9,7 +9,11 @@ export default class AllocationsAllocationTaskController extends Controller {
|
|||
return {
|
||||
title: 'Task',
|
||||
label: this.task.get('name'),
|
||||
args: ['allocations.allocation.task', this.task.get('allocation'), this.task],
|
||||
args: [
|
||||
'allocations.allocation.task',
|
||||
this.task.get('allocation'),
|
||||
this.task,
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,9 @@ export default class VolumeController extends Controller {
|
|||
label: 'Volumes',
|
||||
args: [
|
||||
'csi.volumes',
|
||||
qpBuilder({ volumeNamespace: volume.get('namespace.name') || 'default' }),
|
||||
qpBuilder({
|
||||
volumeNamespace: volume.get('namespace.name') || 'default',
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -33,7 +35,9 @@ export default class VolumeController extends Controller {
|
|||
args: [
|
||||
'csi.volumes.volume',
|
||||
volume.plainId,
|
||||
qpBuilder({ volumeNamespace: volume.get('namespace.name') || 'default' }),
|
||||
qpBuilder({
|
||||
volumeNamespace: volume.get('namespace.name') || 'default',
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
@ -35,9 +35,7 @@ export default class Allocation extends Model {
|
|||
@attr('string') nodeName;
|
||||
@computed
|
||||
get shortNodeId() {
|
||||
return this.belongsTo('node')
|
||||
.id()
|
||||
.split('-')[0];
|
||||
return this.belongsTo('node').id().split('-')[0];
|
||||
}
|
||||
|
||||
@attr('number') modifyIndex;
|
||||
|
|
|
@ -17,7 +17,7 @@ export default class AllocationRoute extends Route.extend(WithWatchers) {
|
|||
// Preload the job for the allocation since it's required for the breadcrumb trail
|
||||
return super
|
||||
.model(...arguments)
|
||||
.then(allocation =>
|
||||
.then((allocation) =>
|
||||
allocation
|
||||
.get('job')
|
||||
.then(() => this.store.findAll('namespace')) // namespaces belong to a job and are an asynchronous relationship so we can peak them later on
|
||||
|
|
|
@ -16,7 +16,7 @@ export default class VolumeRoute extends Route.extend(WithWatchers) {
|
|||
if (!model) return;
|
||||
|
||||
controller.set('watchers', {
|
||||
model: this.watch.perform(model)
|
||||
model: this.watch.perform(model),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,9 @@ export default class VolumeRoute extends Route.extend(WithWatchers) {
|
|||
const fullId = JSON.stringify([`csi/${name}`, namespace || 'default']);
|
||||
return RSVP.hash({
|
||||
volume: this.store.findRecord('volume', fullId, { reload: true }),
|
||||
namespaces: this.store.findAll('namespace')
|
||||
namespaces: this.store.findAll('namespace'),
|
||||
})
|
||||
.then(hash => hash.volume)
|
||||
.then((hash) => hash.volume)
|
||||
.catch(notifyError(this));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
watchRecord,
|
||||
watchRelationship,
|
||||
watchAll,
|
||||
watchQuery
|
||||
watchQuery,
|
||||
} from 'nomad-ui/utils/properties/watch';
|
||||
import WithWatchers from 'nomad-ui/mixins/with-watchers';
|
||||
|
||||
|
@ -43,12 +43,12 @@ export default class IndexRoute extends Route.extend(WithWatchers) {
|
|||
list:
|
||||
model.job.get('hasChildren') &&
|
||||
this.watchAllJobs.perform({
|
||||
namespace: model.job.namespace.get('name')
|
||||
namespace: model.job.namespace.get('name'),
|
||||
}),
|
||||
nodes:
|
||||
this.can.can('read client') &&
|
||||
model.job.get('hasClientStatus') &&
|
||||
this.watchNodes.perform()
|
||||
this.watchNodes.perform(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ export default class IndexRoute extends Route.extend(WithWatchers) {
|
|||
) {
|
||||
controller.setProperties({
|
||||
sortProperty: 'submitTime',
|
||||
sortDescending: true
|
||||
sortDescending: true,
|
||||
});
|
||||
}
|
||||
return super.setupController(...arguments);
|
||||
|
|
|
@ -4,7 +4,7 @@ import EmberError from '@ember/error';
|
|||
import { resolve, all } from 'rsvp';
|
||||
import {
|
||||
watchRecord,
|
||||
watchRelationship
|
||||
watchRelationship,
|
||||
} from 'nomad-ui/utils/properties/watch';
|
||||
import WithWatchers from 'nomad-ui/mixins/with-watchers';
|
||||
import notifyError from 'nomad-ui/utils/notify-error';
|
||||
|
@ -34,7 +34,7 @@ export default class TaskGroupRoute extends Route.extend(WithWatchers) {
|
|||
// Refresh job allocations before-hand (so page sort works on load)
|
||||
return all([
|
||||
job.hasMany('allocations').reload(),
|
||||
job.get('scaleState')
|
||||
job.get('scaleState'),
|
||||
]).then(() => taskGroup);
|
||||
})
|
||||
.catch(notifyError(this));
|
||||
|
@ -50,7 +50,7 @@ export default class TaskGroupRoute extends Route.extend(WithWatchers) {
|
|||
allocations: this.watchAllocations.perform(job),
|
||||
latestDeployment:
|
||||
job.get('supportsDeployments') &&
|
||||
this.watchLatestDeployment.perform(job)
|
||||
this.watchLatestDeployment.perform(job),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ export default class BucketService extends Service {
|
|||
}
|
||||
|
||||
@action deregisterBreadcrumb(crumb) {
|
||||
const newCrumbs = this.crumbs.filter(c => c !== crumb);
|
||||
const newCrumbs = this.crumbs.filter((c) => c !== crumb);
|
||||
|
||||
this.crumbs = newCrumbs;
|
||||
}
|
||||
|
|
|
@ -19,12 +19,12 @@ export default function jobClientStatus(nodesKey, jobKey) {
|
|||
return computed(
|
||||
`${nodesKey}.[]`,
|
||||
`${jobKey}.{datacenters,status,allocations.@each.clientStatus,taskGroups}`,
|
||||
function() {
|
||||
function () {
|
||||
const job = this.get(jobKey);
|
||||
const nodes = this.get(nodesKey);
|
||||
|
||||
// Filter nodes by the datacenters defined in the job.
|
||||
const filteredNodes = nodes.filter(n => {
|
||||
const filteredNodes = nodes.filter((n) => {
|
||||
return job.datacenters.indexOf(n.datacenter) >= 0;
|
||||
});
|
||||
|
||||
|
@ -34,7 +34,7 @@ export default function jobClientStatus(nodesKey, jobKey) {
|
|||
|
||||
// Group the job allocations by the ID of the client that is running them.
|
||||
const allocsByNodeID = {};
|
||||
job.allocations.forEach(a => {
|
||||
job.allocations.forEach((a) => {
|
||||
const nodeId = a.belongsTo('node').id();
|
||||
if (!allocsByNodeID[nodeId]) {
|
||||
allocsByNodeID[nodeId] = [];
|
||||
|
@ -47,7 +47,7 @@ export default function jobClientStatus(nodesKey, jobKey) {
|
|||
byStatus: {},
|
||||
totalNodes: filteredNodes.length,
|
||||
};
|
||||
filteredNodes.forEach(n => {
|
||||
filteredNodes.forEach((n) => {
|
||||
const status = jobStatus(allocsByNodeID[n.id], job.taskGroups.length);
|
||||
result.byNode[n.id] = status;
|
||||
|
||||
|
@ -63,9 +63,9 @@ export default function jobClientStatus(nodesKey, jobKey) {
|
|||
}
|
||||
|
||||
function allQueued(nodes) {
|
||||
const nodeIDs = nodes.map(n => n.id);
|
||||
const nodeIDs = nodes.map((n) => n.id);
|
||||
return {
|
||||
byNode: Object.fromEntries(nodeIDs.map(id => [id, 'queued'])),
|
||||
byNode: Object.fromEntries(nodeIDs.map((id) => [id, 'queued'])),
|
||||
byStatus: canonicalizeStatus({ queued: nodeIDs }),
|
||||
totalNodes: nodes.length,
|
||||
};
|
||||
|
@ -105,7 +105,7 @@ function jobStatus(allocs, expected) {
|
|||
|
||||
// Count how many allocations are in each `clientStatus` value.
|
||||
const summary = allocs
|
||||
.filter(a => !a.isOld)
|
||||
.filter((a) => !a.isOld)
|
||||
.reduce((acc, a) => {
|
||||
const status = a.clientStatus;
|
||||
if (!acc[status]) {
|
||||
|
|
|
@ -16,21 +16,21 @@ let job;
|
|||
let node;
|
||||
let allocation;
|
||||
|
||||
module('Acceptance | allocation detail', function(hooks) {
|
||||
module('Acceptance | allocation detail', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
server.create('agent');
|
||||
|
||||
node = server.create('node');
|
||||
job = server.create('job', {
|
||||
groupsCount: 1,
|
||||
withGroupServices: true,
|
||||
createAllocations: false
|
||||
createAllocations: false,
|
||||
});
|
||||
allocation = server.create('allocation', 'withTaskWithPorts', {
|
||||
clientStatus: 'running'
|
||||
clientStatus: 'running',
|
||||
});
|
||||
|
||||
// Make sure the node has an unhealthy driver
|
||||
|
@ -38,14 +38,14 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
driver: assign(node.drivers, {
|
||||
docker: {
|
||||
detected: true,
|
||||
healthy: false
|
||||
}
|
||||
})
|
||||
healthy: false,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
// Make sure a task for the allocation depends on the unhealthy driver
|
||||
server.schema.tasks.first().update({
|
||||
driver: 'docker'
|
||||
driver: 'docker',
|
||||
});
|
||||
|
||||
window.localStorage.clear();
|
||||
|
@ -53,11 +53,11 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
await Allocation.visit({ id: allocation.id });
|
||||
});
|
||||
|
||||
test('it passes an accessibility audit', async function(assert) {
|
||||
test('it passes an accessibility audit', async function (assert) {
|
||||
await a11yAudit(assert);
|
||||
});
|
||||
|
||||
test('/allocation/:id should name the allocation and link to the corresponding job and node', async function(assert) {
|
||||
test('/allocation/:id should name the allocation and link to the corresponding job and node', async function (assert) {
|
||||
assert.ok(
|
||||
Allocation.title.includes(allocation.name),
|
||||
'Allocation name is in the heading'
|
||||
|
@ -93,7 +93,7 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('/allocation/:id should include resource utilization graphs', async function(assert) {
|
||||
test('/allocation/:id should include resource utilization graphs', async function (assert) {
|
||||
assert.equal(
|
||||
Allocation.resourceCharts.length,
|
||||
2,
|
||||
|
@ -111,17 +111,17 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('/allocation/:id should present task lifecycles', async function(assert) {
|
||||
test('/allocation/:id should present task lifecycles', async function (assert) {
|
||||
const job = server.create('job', {
|
||||
groupsCount: 1,
|
||||
groupTaskCount: 6,
|
||||
withGroupServices: true,
|
||||
createAllocations: false
|
||||
createAllocations: false,
|
||||
});
|
||||
|
||||
const allocation = server.create('allocation', 'withTaskWithPorts', {
|
||||
clientStatus: 'running',
|
||||
jobId: job.id
|
||||
jobId: job.id,
|
||||
});
|
||||
|
||||
await Allocation.visit({ id: allocation.id });
|
||||
|
@ -136,7 +136,7 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
const prestartEphemeralTask = server.db.taskStates
|
||||
.where({ allocationId: allocation.id })
|
||||
.sortBy('name')
|
||||
.find(taskState => {
|
||||
.find((taskState) => {
|
||||
const task = server.db.tasks.findBy({ name: taskState.name });
|
||||
return (
|
||||
task.Lifecycle &&
|
||||
|
@ -151,7 +151,7 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('/allocation/:id should list all tasks for the allocation', async function(assert) {
|
||||
test('/allocation/:id should list all tasks for the allocation', async function (assert) {
|
||||
assert.equal(
|
||||
Allocation.tasks.length,
|
||||
server.db.taskStates.where({ allocationId: allocation.id }).length,
|
||||
|
@ -160,7 +160,7 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
assert.notOk(Allocation.isEmpty, 'Task table empty state is not shown');
|
||||
});
|
||||
|
||||
test('each task row should list high-level information for the task', async function(assert) {
|
||||
test('each task row should list high-level information for the task', async function (assert) {
|
||||
const task = server.db.taskStates
|
||||
.where({ allocationId: allocation.id })
|
||||
.sortBy('name')[0];
|
||||
|
@ -169,16 +169,16 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
|
||||
const taskGroup = server.schema.taskGroups.where({
|
||||
jobId: allocation.jobId,
|
||||
name: allocation.taskGroup
|
||||
name: allocation.taskGroup,
|
||||
}).models[0];
|
||||
|
||||
const jobTask = taskGroup.tasks.models.find(m => m.name === task.name);
|
||||
const volumes = jobTask.volumeMounts.map(volume => ({
|
||||
const jobTask = taskGroup.tasks.models.find((m) => m.name === task.name);
|
||||
const volumes = jobTask.volumeMounts.map((volume) => ({
|
||||
name: volume.Volume,
|
||||
source: taskGroup.volumes[volume.Volume].Source
|
||||
source: taskGroup.volumes[volume.Volume].Source,
|
||||
}));
|
||||
|
||||
Allocation.tasks[0].as(taskRow => {
|
||||
Allocation.tasks[0].as((taskRow) => {
|
||||
assert.equal(taskRow.name, task.name, 'Name');
|
||||
assert.equal(taskRow.state, task.state, 'State');
|
||||
assert.equal(taskRow.message, event.displayMessage, 'Event Message');
|
||||
|
@ -189,7 +189,7 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
);
|
||||
|
||||
const volumesText = taskRow.volumes;
|
||||
volumes.forEach(volume => {
|
||||
volumes.forEach((volume) => {
|
||||
assert.ok(
|
||||
volumesText.includes(volume.name),
|
||||
`Found label ${volume.name}`
|
||||
|
@ -202,7 +202,7 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
test('each task row should link to the task detail page', async function(assert) {
|
||||
test('each task row should link to the task detail page', async function (assert) {
|
||||
const task = server.db.taskStates
|
||||
.where({ allocationId: allocation.id })
|
||||
.sortBy('name')[0];
|
||||
|
@ -226,16 +226,16 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('tasks with an unhealthy driver have a warning icon', async function(assert) {
|
||||
test('tasks with an unhealthy driver have a warning icon', async function (assert) {
|
||||
// Driver health status require node:read permission.
|
||||
const policy = server.create('policy', {
|
||||
id: 'node-read',
|
||||
name: 'node-read',
|
||||
rulesJSON: {
|
||||
Node: {
|
||||
Policy: 'read'
|
||||
}
|
||||
}
|
||||
Policy: 'read',
|
||||
},
|
||||
},
|
||||
});
|
||||
const clientToken = server.create('token', { type: 'client' });
|
||||
clientToken.policyIds = [policy.id];
|
||||
|
@ -253,17 +253,17 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('proxy task has a proxy tag', async function(assert) {
|
||||
test('proxy task has a proxy tag', async function (assert) {
|
||||
// Must create a new job as existing one has loaded and it contains the tasks
|
||||
job = server.create('job', {
|
||||
groupsCount: 1,
|
||||
withGroupServices: true,
|
||||
createAllocations: false
|
||||
createAllocations: false,
|
||||
});
|
||||
|
||||
allocation = server.create('allocation', 'withTaskWithPorts', {
|
||||
clientStatus: 'running',
|
||||
jobId: job.id
|
||||
jobId: job.id,
|
||||
});
|
||||
|
||||
const taskState = allocation.taskStates.models.sortBy('name')[0];
|
||||
|
@ -276,24 +276,24 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
assert.ok(Allocation.tasks[0].hasProxyTag);
|
||||
});
|
||||
|
||||
test('when there are no tasks, an empty state is shown', async function(assert) {
|
||||
test('when there are no tasks, an empty state is shown', async function (assert) {
|
||||
// Make sure the allocation is pending in order to ensure there are no tasks
|
||||
allocation = server.create('allocation', 'withTaskWithPorts', {
|
||||
clientStatus: 'pending'
|
||||
clientStatus: 'pending',
|
||||
});
|
||||
await Allocation.visit({ id: allocation.id });
|
||||
|
||||
assert.ok(Allocation.isEmpty, 'Task table empty state is shown');
|
||||
});
|
||||
|
||||
test('when the allocation has not been rescheduled, the reschedule events section is not rendered', async function(assert) {
|
||||
test('when the allocation has not been rescheduled, the reschedule events section is not rendered', async function (assert) {
|
||||
assert.notOk(
|
||||
Allocation.hasRescheduleEvents,
|
||||
'Reschedule Events section exists'
|
||||
);
|
||||
});
|
||||
|
||||
test('ports are listed', async function(assert) {
|
||||
test('ports are listed', async function (assert) {
|
||||
const allServerPorts = allocation.taskResources.models[0].resources.Ports;
|
||||
|
||||
allServerPorts.sortBy('Label').forEach((serverPort, index) => {
|
||||
|
@ -308,9 +308,9 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
test('services are listed', async function(assert) {
|
||||
test('services are listed', async function (assert) {
|
||||
const taskGroup = server.schema.taskGroups.findBy({
|
||||
name: allocation.taskGroup
|
||||
name: allocation.taskGroup,
|
||||
});
|
||||
|
||||
assert.equal(Allocation.services.length, taskGroup.services.length);
|
||||
|
@ -331,7 +331,7 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
const upstreams = serverService.Connect.SidecarService.Proxy.Upstreams;
|
||||
const serverUpstreamsString = upstreams
|
||||
.map(
|
||||
upstream => `${upstream.DestinationName}:${upstream.LocalBindPort}`
|
||||
(upstream) => `${upstream.DestinationName}:${upstream.LocalBindPort}`
|
||||
)
|
||||
.join(' ');
|
||||
|
||||
|
@ -339,12 +339,12 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
test('when the allocation is not found, an error message is shown, but the URL persists', async function(assert) {
|
||||
test('when the allocation is not found, an error message is shown, but the URL persists', async function (assert) {
|
||||
await Allocation.visit({ id: 'not-a-real-allocation' });
|
||||
|
||||
assert.equal(
|
||||
server.pretender.handledRequests
|
||||
.filter(request => !request.url.includes('policy'))
|
||||
.filter((request) => !request.url.includes('policy'))
|
||||
.findBy('status', 404).url,
|
||||
'/v1/allocation/not-a-real-allocation',
|
||||
'A request to the nonexistent allocation is made'
|
||||
|
@ -362,20 +362,20 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('allocation can be stopped', async function(assert) {
|
||||
test('allocation can be stopped', async function (assert) {
|
||||
await Allocation.stop.idle();
|
||||
await Allocation.stop.confirm();
|
||||
|
||||
assert.equal(
|
||||
server.pretender.handledRequests
|
||||
.reject(request => request.url.includes('fuzzy'))
|
||||
.reject((request) => request.url.includes('fuzzy'))
|
||||
.findBy('method', 'POST').url,
|
||||
`/v1/allocation/${allocation.id}/stop`,
|
||||
'Stop request is made for the allocation'
|
||||
);
|
||||
});
|
||||
|
||||
test('allocation can be restarted', async function(assert) {
|
||||
test('allocation can be restarted', async function (assert) {
|
||||
await Allocation.restart.idle();
|
||||
await Allocation.restart.confirm();
|
||||
|
||||
|
@ -386,7 +386,7 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('while an allocation is being restarted, the stop button is disabled', async function(assert) {
|
||||
test('while an allocation is being restarted, the stop button is disabled', async function (assert) {
|
||||
server.pretender.post('/v1/allocation/:id/stop', () => [204, {}, ''], true);
|
||||
|
||||
await Allocation.stop.idle();
|
||||
|
@ -400,7 +400,7 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
await Allocation.stop.confirm();
|
||||
});
|
||||
|
||||
test('if stopping or restarting fails, an error message is shown', async function(assert) {
|
||||
test('if stopping or restarting fails, an error message is shown', async function (assert) {
|
||||
server.pretender.post('/v1/allocation/:id/stop', () => [403, {}, '']);
|
||||
|
||||
await Allocation.stop.idle();
|
||||
|
@ -425,11 +425,11 @@ module('Acceptance | allocation detail', function(hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
module('Acceptance | allocation detail (rescheduled)', function(hooks) {
|
||||
module('Acceptance | allocation detail (rescheduled)', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
server.create('agent');
|
||||
|
||||
node = server.create('node');
|
||||
|
@ -439,7 +439,7 @@ module('Acceptance | allocation detail (rescheduled)', function(hooks) {
|
|||
await Allocation.visit({ id: allocation.id });
|
||||
});
|
||||
|
||||
test('when the allocation has been rescheduled, the reschedule events section is rendered', async function(assert) {
|
||||
test('when the allocation has been rescheduled, the reschedule events section is rendered', async function (assert) {
|
||||
assert.ok(
|
||||
Allocation.hasRescheduleEvents,
|
||||
'Reschedule Events section exists'
|
||||
|
@ -447,11 +447,11 @@ module('Acceptance | allocation detail (rescheduled)', function(hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
module('Acceptance | allocation detail (not running)', function(hooks) {
|
||||
module('Acceptance | allocation detail (not running)', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
server.create('agent');
|
||||
|
||||
node = server.create('node');
|
||||
|
@ -461,7 +461,7 @@ module('Acceptance | allocation detail (not running)', function(hooks) {
|
|||
await Allocation.visit({ id: allocation.id });
|
||||
});
|
||||
|
||||
test('when the allocation is not running, the utilization graphs are replaced by an empty message', async function(assert) {
|
||||
test('when the allocation is not running, the utilization graphs are replaced by an empty message', async function (assert) {
|
||||
assert.equal(Allocation.resourceCharts.length, 0, 'No resource charts');
|
||||
assert.equal(
|
||||
Allocation.resourceEmptyMessage,
|
||||
|
@ -470,25 +470,25 @@ module('Acceptance | allocation detail (not running)', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('the exec and stop/restart buttons are absent', async function(assert) {
|
||||
test('the exec and stop/restart buttons are absent', async function (assert) {
|
||||
assert.notOk(Allocation.execButton.isPresent);
|
||||
assert.notOk(Allocation.stop.isPresent);
|
||||
assert.notOk(Allocation.restart.isPresent);
|
||||
});
|
||||
});
|
||||
|
||||
module('Acceptance | allocation detail (preemptions)', function(hooks) {
|
||||
module('Acceptance | allocation detail (preemptions)', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
server.create('agent');
|
||||
node = server.create('node');
|
||||
job = server.create('job', { createAllocations: false });
|
||||
window.localStorage.clear();
|
||||
});
|
||||
|
||||
test('shows a dedicated section to the allocation that preempted this allocation', async function(assert) {
|
||||
test('shows a dedicated section to the allocation that preempted this allocation', async function (assert) {
|
||||
allocation = server.create('allocation', 'preempted');
|
||||
const preempter = server.schema.find(
|
||||
'allocation',
|
||||
|
@ -539,7 +539,7 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('shows a dedicated section to the allocations this allocation preempted', async function(assert) {
|
||||
test('shows a dedicated section to the allocations this allocation preempted', async function (assert) {
|
||||
allocation = server.create('allocation', 'preempter');
|
||||
await Allocation.visit({ id: allocation.id });
|
||||
assert.ok(
|
||||
|
@ -548,12 +548,12 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('each preempted allocation in the table lists basic allocation information', async function(assert) {
|
||||
test('each preempted allocation in the table lists basic allocation information', async function (assert) {
|
||||
allocation = server.create('allocation', 'preempter');
|
||||
await Allocation.visit({ id: allocation.id });
|
||||
|
||||
const preemption = allocation.preemptedAllocations
|
||||
.map(id => server.schema.find('allocation', id))
|
||||
.map((id) => server.schema.find('allocation', id))
|
||||
.sortBy('modifyIndex')
|
||||
.reverse()[0];
|
||||
const preemptionRow = Allocation.preemptions.objectAt(0);
|
||||
|
@ -596,16 +596,16 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('clicking the client ID in the preempted allocation row naviates to the client page', async function(assert) {
|
||||
test('clicking the client ID in the preempted allocation row naviates to the client page', async function (assert) {
|
||||
// Navigating to the client page requires node:read permission.
|
||||
const policy = server.create('policy', {
|
||||
id: 'node-read',
|
||||
name: 'node-read',
|
||||
rulesJSON: {
|
||||
Node: {
|
||||
Policy: 'read'
|
||||
}
|
||||
}
|
||||
Policy: 'read',
|
||||
},
|
||||
},
|
||||
});
|
||||
const clientToken = server.create('token', { type: 'client' });
|
||||
clientToken.policyIds = [policy.id];
|
||||
|
@ -616,7 +616,7 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) {
|
|||
await Allocation.visit({ id: allocation.id });
|
||||
|
||||
const preemption = allocation.preemptedAllocations
|
||||
.map(id => server.schema.find('allocation', id))
|
||||
.map((id) => server.schema.find('allocation', id))
|
||||
.sortBy('modifyIndex')
|
||||
.reverse()[0];
|
||||
const preemptionRow = Allocation.preemptions.objectAt(0);
|
||||
|
@ -629,7 +629,7 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('when an allocation both preempted allocations and was preempted itself, both preemptions sections are shown', async function(assert) {
|
||||
test('when an allocation both preempted allocations and was preempted itself, both preemptions sections are shown', async function (assert) {
|
||||
allocation = server.create('allocation', 'preempter', 'preempted');
|
||||
await Allocation.visit({ id: allocation.id });
|
||||
assert.ok(
|
||||
|
|
|
@ -11,11 +11,11 @@ let node;
|
|||
let managementToken;
|
||||
let clientToken;
|
||||
|
||||
module('Acceptance | client monitor', function(hooks) {
|
||||
module('Acceptance | client monitor', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(function() {
|
||||
hooks.beforeEach(function () {
|
||||
node = server.create('node');
|
||||
|
||||
managementToken = server.create('token');
|
||||
|
@ -27,12 +27,14 @@ module('Acceptance | client monitor', function(hooks) {
|
|||
run.later(run, run.cancelTimers, 500);
|
||||
});
|
||||
|
||||
test('it passes an accessibility audit', async function(assert) {
|
||||
test('it passes an accessibility audit', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
await ClientMonitor.visit({ id: node.id });
|
||||
await a11yAudit(assert);
|
||||
});
|
||||
|
||||
test('/clients/:id/monitor should have a breadcrumb trail linking back to clients', async function(assert) {
|
||||
test('/clients/:id/monitor should have a breadcrumb trail linking back to clients', async function (assert) {
|
||||
await ClientMonitor.visit({ id: node.id });
|
||||
|
||||
assert.equal(Layout.breadcrumbFor('clients.index').text, 'Clients');
|
||||
|
@ -45,10 +47,10 @@ module('Acceptance | client monitor', function(hooks) {
|
|||
assert.equal(currentURL(), '/clients');
|
||||
});
|
||||
|
||||
test('the monitor page immediately streams agent monitor output at the info level', async function(assert) {
|
||||
test('the monitor page immediately streams agent monitor output at the info level', async function (assert) {
|
||||
await ClientMonitor.visit({ id: node.id });
|
||||
|
||||
const logRequest = server.pretender.handledRequests.find(req =>
|
||||
const logRequest = server.pretender.handledRequests.find((req) =>
|
||||
req.url.startsWith('/v1/agent/monitor')
|
||||
);
|
||||
assert.ok(ClientMonitor.logsArePresent);
|
||||
|
@ -56,13 +58,13 @@ module('Acceptance | client monitor', function(hooks) {
|
|||
assert.ok(logRequest.url.includes('log_level=info'));
|
||||
});
|
||||
|
||||
test('switching the log level persists the new log level as a query param', async function(assert) {
|
||||
test('switching the log level persists the new log level as a query param', async function (assert) {
|
||||
await ClientMonitor.visit({ id: node.id });
|
||||
await ClientMonitor.selectLogLevel('Debug');
|
||||
assert.equal(currentURL(), `/clients/${node.id}/monitor?level=debug`);
|
||||
});
|
||||
|
||||
test('when the current access token does not include the agent:read rule, a descriptive error message is shown', async function(assert) {
|
||||
test('when the current access token does not include the agent:read rule, a descriptive error message is shown', async function (assert) {
|
||||
window.localStorage.nomadTokenSecret = clientToken.secretId;
|
||||
|
||||
await ClientMonitor.visit({ id: node.id });
|
||||
|
|
|
@ -40,7 +40,10 @@ module('Acceptance | server monitor', function (hooks) {
|
|||
'Servers',
|
||||
'The page should read the breadcrumb Servers'
|
||||
);
|
||||
assert.equal(Layout.breadcrumbFor('servers.server').text, `Server ${agent.name}`);
|
||||
assert.equal(
|
||||
Layout.breadcrumbFor('servers.server').text,
|
||||
`Server ${agent.name}`
|
||||
);
|
||||
|
||||
await Layout.breadcrumbFor('servers.index').visit();
|
||||
assert.equal(currentURL(), '/servers');
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable qunit/require-expect */
|
||||
import { currentURL, waitFor } from '@ember/test-helpers';
|
||||
import { module, test } from 'qunit';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
|
@ -10,27 +11,29 @@ import moment from 'moment';
|
|||
let allocation;
|
||||
let task;
|
||||
|
||||
module('Acceptance | task detail', function(hooks) {
|
||||
module('Acceptance | task detail', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
server.create('agent');
|
||||
server.create('node');
|
||||
server.create('job', { createAllocations: false });
|
||||
allocation = server.create('allocation', 'withTaskWithPorts', {
|
||||
clientStatus: 'running'
|
||||
clientStatus: 'running',
|
||||
});
|
||||
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
|
||||
|
||||
await Task.visit({ id: allocation.id, name: task.name });
|
||||
});
|
||||
|
||||
test('it passes an accessibility audit', async function(assert) {
|
||||
test('it passes an accessibility audit', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
await a11yAudit(assert);
|
||||
});
|
||||
|
||||
test('/allocation/:id/:task_name should name the task and list high-level task information', async function(assert) {
|
||||
test('/allocation/:id/:task_name should name the task and list high-level task information', async function (assert) {
|
||||
assert.ok(Task.title.text.includes(task.name), 'Task name');
|
||||
assert.ok(Task.state.includes(task.state), 'Task state');
|
||||
|
||||
|
@ -61,7 +64,7 @@ module('Acceptance | task detail', function(hooks) {
|
|||
assert.equal(document.title, `Task ${task.name} - Nomad`);
|
||||
});
|
||||
|
||||
test('breadcrumbs match jobs / job / task group / allocation / task', async function(assert) {
|
||||
test('breadcrumbs match jobs / job / task group / allocation / task', async function (assert) {
|
||||
const { jobId, taskGroup } = allocation;
|
||||
const job = server.db.jobs.find(jobId);
|
||||
|
||||
|
@ -122,7 +125,7 @@ module('Acceptance | task detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('/allocation/:id/:task_name should include resource utilization graphs', async function(assert) {
|
||||
test('/allocation/:id/:task_name should include resource utilization graphs', async function (assert) {
|
||||
assert.equal(
|
||||
Task.resourceCharts.length,
|
||||
2,
|
||||
|
@ -140,7 +143,7 @@ module('Acceptance | task detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('the events table lists all recent events', async function(assert) {
|
||||
test('the events table lists all recent events', async function (assert) {
|
||||
const events = server.db.taskEvents.where({ taskStateId: task.id });
|
||||
|
||||
assert.equal(
|
||||
|
@ -150,26 +153,26 @@ module('Acceptance | task detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('when a task has volumes, the volumes table is shown', async function(assert) {
|
||||
test('when a task has volumes, the volumes table is shown', async function (assert) {
|
||||
const taskGroup = server.schema.taskGroups.where({
|
||||
jobId: allocation.jobId,
|
||||
name: allocation.taskGroup
|
||||
name: allocation.taskGroup,
|
||||
}).models[0];
|
||||
|
||||
const jobTask = taskGroup.tasks.models.find(m => m.name === task.name);
|
||||
const jobTask = taskGroup.tasks.models.find((m) => m.name === task.name);
|
||||
|
||||
assert.ok(Task.hasVolumes);
|
||||
assert.equal(Task.volumes.length, jobTask.volumeMounts.length);
|
||||
});
|
||||
|
||||
test('when a task does not have volumes, the volumes table is not shown', async function(assert) {
|
||||
test('when a task does not have volumes, the volumes table is not shown', async function (assert) {
|
||||
const job = server.create('job', {
|
||||
createAllocations: false,
|
||||
noHostVolumes: true
|
||||
noHostVolumes: true,
|
||||
});
|
||||
allocation = server.create('allocation', {
|
||||
jobId: job.id,
|
||||
clientStatus: 'running'
|
||||
clientStatus: 'running',
|
||||
});
|
||||
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
|
||||
|
||||
|
@ -177,16 +180,16 @@ module('Acceptance | task detail', function(hooks) {
|
|||
assert.notOk(Task.hasVolumes);
|
||||
});
|
||||
|
||||
test('each volume in the volumes table shows information about the volume', async function(assert) {
|
||||
test('each volume in the volumes table shows information about the volume', async function (assert) {
|
||||
const taskGroup = server.schema.taskGroups.where({
|
||||
jobId: allocation.jobId,
|
||||
name: allocation.taskGroup
|
||||
name: allocation.taskGroup,
|
||||
}).models[0];
|
||||
|
||||
const jobTask = taskGroup.tasks.models.find(m => m.name === task.name);
|
||||
const jobTask = taskGroup.tasks.models.find((m) => m.name === task.name);
|
||||
const volume = jobTask.volumeMounts[0];
|
||||
|
||||
Task.volumes[0].as(volumeRow => {
|
||||
Task.volumes[0].as((volumeRow) => {
|
||||
assert.equal(volumeRow.name, volume.Volume);
|
||||
assert.equal(volumeRow.destination, volume.Destination);
|
||||
assert.equal(
|
||||
|
@ -200,7 +203,7 @@ module('Acceptance | task detail', function(hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
test('each recent event should list the time, type, and description of the event', async function(assert) {
|
||||
test('each recent event should list the time, type, and description of the event', async function (assert) {
|
||||
const event = server.db.taskEvents.where({ taskStateId: task.id })[0];
|
||||
const recentEvent = Task.events.objectAt(Task.events.length - 1);
|
||||
|
||||
|
@ -213,12 +216,12 @@ module('Acceptance | task detail', function(hooks) {
|
|||
assert.equal(recentEvent.message, event.displayMessage, 'Event message');
|
||||
});
|
||||
|
||||
test('when the allocation is not found, the application errors', async function(assert) {
|
||||
test('when the allocation is not found, the application errors', async function (assert) {
|
||||
await Task.visit({ id: 'not-a-real-allocation', name: task.name });
|
||||
|
||||
assert.equal(
|
||||
server.pretender.handledRequests
|
||||
.filter(request => !request.url.includes('policy'))
|
||||
.filter((request) => !request.url.includes('policy'))
|
||||
.findBy('status', 404).url,
|
||||
'/v1/allocation/not-a-real-allocation',
|
||||
'A request to the nonexistent allocation is made'
|
||||
|
@ -232,7 +235,7 @@ module('Acceptance | task detail', function(hooks) {
|
|||
assert.equal(Task.error.title, 'Not Found', 'Error message is for 404');
|
||||
});
|
||||
|
||||
test('when the allocation is found but the task is not, the application errors', async function(assert) {
|
||||
test('when the allocation is found but the task is not, the application errors', async function (assert) {
|
||||
await Task.visit({ id: allocation.id, name: 'not-a-real-task-name' });
|
||||
|
||||
assert.ok(
|
||||
|
@ -251,7 +254,7 @@ module('Acceptance | task detail', function(hooks) {
|
|||
assert.equal(Task.error.title, 'Not Found', 'Error message is for 404');
|
||||
});
|
||||
|
||||
test('task can be restarted', async function(assert) {
|
||||
test('task can be restarted', async function (assert) {
|
||||
await Task.restart.idle();
|
||||
await Task.restart.confirm();
|
||||
|
||||
|
@ -269,11 +272,11 @@ module('Acceptance | task detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('when task restart fails (403), an ACL permissions error message is shown', async function(assert) {
|
||||
test('when task restart fails (403), an ACL permissions error message is shown', async function (assert) {
|
||||
server.pretender.put('/v1/client/allocation/:id/restart', () => [
|
||||
403,
|
||||
{},
|
||||
''
|
||||
'',
|
||||
]);
|
||||
|
||||
await Task.restart.idle();
|
||||
|
@ -294,12 +297,12 @@ module('Acceptance | task detail', function(hooks) {
|
|||
assert.notOk(Task.inlineError.isShown, 'Inline error is no longer shown');
|
||||
});
|
||||
|
||||
test('when task restart fails (500), the error message from the API is piped through to the alert', async function(assert) {
|
||||
test('when task restart fails (500), the error message from the API is piped through to the alert', async function (assert) {
|
||||
const message = 'A plaintext error message';
|
||||
server.pretender.put('/v1/client/allocation/:id/restart', () => [
|
||||
500,
|
||||
{},
|
||||
message
|
||||
message,
|
||||
]);
|
||||
|
||||
await Task.restart.idle();
|
||||
|
@ -314,21 +317,21 @@ module('Acceptance | task detail', function(hooks) {
|
|||
assert.notOk(Task.inlineError.isShown);
|
||||
});
|
||||
|
||||
test('exec button is present', async function(assert) {
|
||||
test('exec button is present', async function (assert) {
|
||||
assert.ok(Task.execButton.isPresent);
|
||||
});
|
||||
});
|
||||
|
||||
module('Acceptance | task detail (no addresses)', function(hooks) {
|
||||
module('Acceptance | task detail (no addresses)', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
server.create('agent');
|
||||
server.create('node');
|
||||
server.create('job');
|
||||
allocation = server.create('allocation', 'withoutTaskWithPorts', {
|
||||
clientStatus: 'running'
|
||||
clientStatus: 'running',
|
||||
});
|
||||
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
|
||||
|
||||
|
@ -336,28 +339,28 @@ module('Acceptance | task detail (no addresses)', function(hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
module('Acceptance | task detail (different namespace)', function(hooks) {
|
||||
module('Acceptance | task detail (different namespace)', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
server.create('agent');
|
||||
server.create('node');
|
||||
server.create('namespace');
|
||||
server.create('namespace', { id: 'other-namespace' });
|
||||
server.create('job', {
|
||||
createAllocations: false,
|
||||
namespaceId: 'other-namespace'
|
||||
namespaceId: 'other-namespace',
|
||||
});
|
||||
allocation = server.create('allocation', 'withTaskWithPorts', {
|
||||
clientStatus: 'running'
|
||||
clientStatus: 'running',
|
||||
});
|
||||
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
|
||||
|
||||
await Task.visit({ id: allocation.id, name: task.name });
|
||||
});
|
||||
|
||||
test('breadcrumbs match jobs / job / task group / allocation / task', async function(assert) {
|
||||
test('breadcrumbs match jobs / job / task group / allocation / task', async function (assert) {
|
||||
const { jobId, taskGroup } = allocation;
|
||||
const job = server.db.jobs.find(jobId);
|
||||
|
||||
|
@ -394,28 +397,28 @@ module('Acceptance | task detail (different namespace)', function(hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
module('Acceptance | task detail (not running)', function(hooks) {
|
||||
module('Acceptance | task detail (not running)', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
server.create('agent');
|
||||
server.create('node');
|
||||
server.create('namespace');
|
||||
server.create('namespace', { id: 'other-namespace' });
|
||||
server.create('job', {
|
||||
createAllocations: false,
|
||||
namespaceId: 'other-namespace'
|
||||
namespaceId: 'other-namespace',
|
||||
});
|
||||
allocation = server.create('allocation', 'withTaskWithPorts', {
|
||||
clientStatus: 'complete'
|
||||
clientStatus: 'complete',
|
||||
});
|
||||
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
|
||||
|
||||
await Task.visit({ id: allocation.id, name: task.name });
|
||||
});
|
||||
|
||||
test('when the allocation for a task is not running, the resource utilization graphs are replaced by an empty message', async function(assert) {
|
||||
test('when the allocation for a task is not running, the resource utilization graphs are replaced by an empty message', async function (assert) {
|
||||
assert.equal(Task.resourceCharts.length, 0, 'No resource charts');
|
||||
assert.equal(
|
||||
Task.resourceEmptyMessage,
|
||||
|
@ -424,21 +427,21 @@ module('Acceptance | task detail (not running)', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('exec button is absent', async function(assert) {
|
||||
test('exec button is absent', async function (assert) {
|
||||
assert.notOk(Task.execButton.isPresent);
|
||||
});
|
||||
});
|
||||
|
||||
module('Acceptance | proxy task detail', function(hooks) {
|
||||
module('Acceptance | proxy task detail', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
server.create('agent');
|
||||
server.create('node');
|
||||
server.create('job', { createAllocations: false });
|
||||
allocation = server.create('allocation', 'withTaskWithPorts', {
|
||||
clientStatus: 'running'
|
||||
clientStatus: 'running',
|
||||
});
|
||||
|
||||
const taskState = allocation.taskStates.models[0];
|
||||
|
@ -449,7 +452,7 @@ module('Acceptance | proxy task detail', function(hooks) {
|
|||
await Task.visit({ id: allocation.id, name: taskState.name });
|
||||
});
|
||||
|
||||
test('a proxy tag is shown', async function(assert) {
|
||||
test('a proxy tag is shown', async function (assert) {
|
||||
assert.ok(Task.title.proxyTag.isPresent);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
formatBytes,
|
||||
formatHertz,
|
||||
formatScheduledBytes,
|
||||
formatScheduledHertz
|
||||
formatScheduledHertz,
|
||||
} from 'nomad-ui/utils/units';
|
||||
import TaskGroup from 'nomad-ui/tests/pages/jobs/job/task-group';
|
||||
import Layout from 'nomad-ui/tests/pages/layout';
|
||||
|
@ -24,30 +24,30 @@ let managementToken;
|
|||
|
||||
const sum = (total, n) => total + n;
|
||||
|
||||
module('Acceptance | task group detail', function(hooks) {
|
||||
module('Acceptance | task group detail', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
server.create('agent');
|
||||
server.create('node', 'forceIPv4');
|
||||
|
||||
job = server.create('job', {
|
||||
groupsCount: 2,
|
||||
createAllocations: false
|
||||
createAllocations: false,
|
||||
});
|
||||
|
||||
const taskGroups = server.db.taskGroups.where({ jobId: job.id });
|
||||
taskGroup = taskGroups[0];
|
||||
|
||||
tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id));
|
||||
tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id));
|
||||
|
||||
server.create('node', 'forceIPv4');
|
||||
|
||||
allocations = server.createList('allocation', 2, {
|
||||
jobId: job.id,
|
||||
taskGroup: taskGroup.name,
|
||||
clientStatus: 'running'
|
||||
clientStatus: 'running',
|
||||
});
|
||||
|
||||
// Allocations associated to a different task group on the job to
|
||||
|
@ -55,20 +55,20 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
server.createList('allocation', 3, {
|
||||
jobId: job.id,
|
||||
taskGroup: taskGroups[1].name,
|
||||
clientStatus: 'running'
|
||||
clientStatus: 'running',
|
||||
});
|
||||
|
||||
// Set a static name to make the search test deterministic
|
||||
server.db.allocations.forEach(alloc => {
|
||||
server.db.allocations.forEach((alloc) => {
|
||||
alloc.name = 'aaaaa';
|
||||
});
|
||||
|
||||
// Mark the first alloc as rescheduled
|
||||
allocations[0].update({
|
||||
nextAllocation: allocations[1].id
|
||||
nextAllocation: allocations[1].id,
|
||||
});
|
||||
allocations[1].update({
|
||||
previousAllocation: allocations[0].id
|
||||
previousAllocation: allocations[0].id,
|
||||
});
|
||||
|
||||
managementToken = server.create('token');
|
||||
|
@ -76,16 +76,16 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
window.localStorage.clear();
|
||||
});
|
||||
|
||||
test('it passes an accessibility audit', async function(assert) {
|
||||
test('it passes an accessibility audit', async function (assert) {
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
await a11yAudit(assert);
|
||||
});
|
||||
|
||||
test('/jobs/:id/:task-group should list high-level metrics for the allocation', async function(assert) {
|
||||
test('/jobs/:id/:task-group should list high-level metrics for the allocation', async function (assert) {
|
||||
const totalCPU = tasks.mapBy('resources.CPU').reduce(sum, 0);
|
||||
const totalMemory = tasks.mapBy('resources.MemoryMB').reduce(sum, 0);
|
||||
const totalMemoryMax = tasks
|
||||
.map(t => t.resources.MemoryMaxMB || t.resources.MemoryMB)
|
||||
.map((t) => t.resources.MemoryMaxMB || t.resources.MemoryMB)
|
||||
.reduce(sum, 0);
|
||||
const totalDisk = taskGroup.ephemeralDisk.SizeMB;
|
||||
|
||||
|
@ -127,7 +127,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('/jobs/:id/:task-group should have breadcrumbs for job and jobs', async function(assert) {
|
||||
test('/jobs/:id/:task-group should have breadcrumbs for job and jobs', async function (assert) {
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
||||
assert.equal(
|
||||
|
@ -147,14 +147,14 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('/jobs/:id/:task-group first breadcrumb should link to jobs', async function(assert) {
|
||||
test('/jobs/:id/:task-group first breadcrumb should link to jobs', async function (assert) {
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
||||
await Layout.breadcrumbFor('jobs.index').visit();
|
||||
assert.equal(currentURL(), '/jobs', 'First breadcrumb links back to jobs');
|
||||
});
|
||||
|
||||
test('/jobs/:id/:task-group second breadcrumb should link to the job for the task group', async function(assert) {
|
||||
test('/jobs/:id/:task-group second breadcrumb should link to the job for the task group', async function (assert) {
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
||||
await Layout.breadcrumbFor('jobs.job.index').visit();
|
||||
|
@ -165,7 +165,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('when the user has a client token that has a namespace with a policy to run and scale a job the autoscaler options should be available', async function(assert) {
|
||||
test('when the user has a client token that has a namespace with a policy to run and scale a job the autoscaler options should be available', async function (assert) {
|
||||
window.localStorage.clear();
|
||||
|
||||
const SCALE_AND_WRITE_NAMESPACE = 'scale-and-write-namespace';
|
||||
|
@ -174,7 +174,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
|
||||
server.create('namespace', { id: SCALE_AND_WRITE_NAMESPACE });
|
||||
const secondNamespace = server.create('namespace', {
|
||||
id: READ_ONLY_NAMESPACE
|
||||
id: READ_ONLY_NAMESPACE,
|
||||
});
|
||||
|
||||
job = server.create('job', {
|
||||
|
@ -182,14 +182,14 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
createAllocations: false,
|
||||
shallow: true,
|
||||
noActiveDeployment: true,
|
||||
namespaceId: SCALE_AND_WRITE_NAMESPACE
|
||||
namespaceId: SCALE_AND_WRITE_NAMESPACE,
|
||||
});
|
||||
const scalingGroup = server.create('task-group', {
|
||||
job,
|
||||
name: 'scaling',
|
||||
count: 1,
|
||||
shallow: true,
|
||||
withScaling: true
|
||||
withScaling: true,
|
||||
});
|
||||
job.update({ taskGroupIds: [scalingGroup.id] });
|
||||
|
||||
|
@ -198,14 +198,14 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
createAllocations: false,
|
||||
shallow: true,
|
||||
noActiveDeployment: true,
|
||||
namespaceId: READ_ONLY_NAMESPACE
|
||||
namespaceId: READ_ONLY_NAMESPACE,
|
||||
});
|
||||
const scalingGroup2 = server.create('task-group', {
|
||||
job: job2,
|
||||
name: 'scaling',
|
||||
count: 1,
|
||||
shallow: true,
|
||||
withScaling: true
|
||||
withScaling: true,
|
||||
});
|
||||
job2.update({ taskGroupIds: [scalingGroup2.id] });
|
||||
|
||||
|
@ -216,14 +216,14 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
Namespaces: [
|
||||
{
|
||||
Name: SCALE_AND_WRITE_NAMESPACE,
|
||||
Capabilities: ['scale-job', 'submit-job', 'read-job', 'list-jobs']
|
||||
Capabilities: ['scale-job', 'submit-job', 'read-job', 'list-jobs'],
|
||||
},
|
||||
{
|
||||
Name: READ_ONLY_NAMESPACE,
|
||||
Capabilities: ['list-jobs', 'read-job']
|
||||
}
|
||||
]
|
||||
}
|
||||
Capabilities: ['list-jobs', 'read-job'],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
clientToken.policyIds = [policy.id];
|
||||
|
@ -234,7 +234,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
await TaskGroup.visit({
|
||||
id: job.id,
|
||||
name: scalingGroup.name,
|
||||
namespace: SCALE_AND_WRITE_NAMESPACE
|
||||
namespace: SCALE_AND_WRITE_NAMESPACE,
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
|
@ -246,7 +246,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
await TaskGroup.visit({
|
||||
id: job2.id,
|
||||
name: scalingGroup2.name,
|
||||
namespace: secondNamespace.name
|
||||
namespace: secondNamespace.name,
|
||||
});
|
||||
assert.equal(
|
||||
currentURL(),
|
||||
|
@ -255,11 +255,11 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
assert.ok(TaskGroup.countStepper.increment.isDisabled);
|
||||
});
|
||||
|
||||
test('/jobs/:id/:task-group should list one page of allocations for the task group', async function(assert) {
|
||||
test('/jobs/:id/:task-group should list one page of allocations for the task group', async function (assert) {
|
||||
server.createList('allocation', TaskGroup.pageSize, {
|
||||
jobId: job.id,
|
||||
taskGroup: taskGroup.name,
|
||||
clientStatus: 'running'
|
||||
clientStatus: 'running',
|
||||
});
|
||||
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
@ -277,7 +277,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('each allocation should show basic information about the allocation', async function(assert) {
|
||||
test('each allocation should show basic information about the allocation', async function (assert) {
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
||||
const allocation = allocations.sortBy('modifyIndex').reverse()[0];
|
||||
|
@ -320,16 +320,16 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('clicking the client ID in the allocation row naviates to the client page', async function(assert) {
|
||||
test('clicking the client ID in the allocation row naviates to the client page', async function (assert) {
|
||||
// Navigating to the client page requires node:read permission.
|
||||
const policy = server.create('policy', {
|
||||
id: 'node-read',
|
||||
name: 'node-read',
|
||||
rulesJSON: {
|
||||
Node: {
|
||||
Policy: 'read'
|
||||
}
|
||||
}
|
||||
Policy: 'read',
|
||||
},
|
||||
},
|
||||
});
|
||||
const clientToken = server.create('token', { type: 'client' });
|
||||
clientToken.policyIds = [policy.id];
|
||||
|
@ -349,14 +349,14 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('each allocation should show stats about the allocation', async function(assert) {
|
||||
test('each allocation should show stats about the allocation', async function (assert) {
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
||||
const allocation = allocations.sortBy('name')[0];
|
||||
const allocationRow = TaskGroup.allocations.objectAt(0);
|
||||
|
||||
const allocStats = server.db.clientAllocationStats.find(allocation.id);
|
||||
const tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id));
|
||||
const tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id));
|
||||
|
||||
const cpuUsed = tasks.reduce((sum, task) => sum + task.resources.CPU, 0);
|
||||
const memoryUsed = tasks.reduce(
|
||||
|
@ -395,7 +395,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('when the allocation search has no matches, there is an empty message', async function(assert) {
|
||||
test('when the allocation search has no matches, there is an empty message', async function (assert) {
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
||||
await TaskGroup.search('zzzzzz');
|
||||
|
@ -408,7 +408,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('when the allocation has reschedule events, the allocation row is denoted with an icon', async function(assert) {
|
||||
test('when the allocation has reschedule events, the allocation row is denoted with an icon', async function (assert) {
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
||||
const rescheduleRow = TaskGroup.allocationFor(allocations[0].id);
|
||||
|
@ -421,10 +421,10 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
assert.notOk(normalRow.rescheduled, 'Normal row has no reschedule icon');
|
||||
});
|
||||
|
||||
test('/jobs/:id/:task-group should present task lifecycles', async function(assert) {
|
||||
test('/jobs/:id/:task-group should present task lifecycles', async function (assert) {
|
||||
job = server.create('job', {
|
||||
groupsCount: 2,
|
||||
groupTaskCount: 3
|
||||
groupTaskCount: 3,
|
||||
});
|
||||
|
||||
const taskGroups = server.db.taskGroups.where({ jobId: job.id });
|
||||
|
@ -438,21 +438,21 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
'Task Lifecycle Configuration'
|
||||
);
|
||||
|
||||
tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id));
|
||||
tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id));
|
||||
const taskNames = tasks.mapBy('name');
|
||||
|
||||
// This is thoroughly tested in allocation detail tests, so this mostly checks what’s different
|
||||
|
||||
assert.equal(TaskGroup.lifecycleChart.tasks.length, 3);
|
||||
|
||||
TaskGroup.lifecycleChart.tasks.forEach(Task => {
|
||||
TaskGroup.lifecycleChart.tasks.forEach((Task) => {
|
||||
assert.ok(taskNames.includes(Task.name));
|
||||
assert.notOk(Task.isActive);
|
||||
assert.notOk(Task.isFinished);
|
||||
});
|
||||
});
|
||||
|
||||
test('when the task group depends on volumes, the volumes table is shown', async function(assert) {
|
||||
test('when the task group depends on volumes, the volumes table is shown', async function (assert) {
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
||||
assert.ok(TaskGroup.hasVolumes);
|
||||
|
@ -462,7 +462,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('when the task group does not depend on volumes, the volumes table is not shown', async function(assert) {
|
||||
test('when the task group does not depend on volumes, the volumes table is not shown', async function (assert) {
|
||||
job = server.create('job', { noHostVolumes: true, shallow: true });
|
||||
taskGroup = server.db.taskGroups.where({ jobId: job.id })[0];
|
||||
|
||||
|
@ -471,10 +471,10 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
assert.notOk(TaskGroup.hasVolumes);
|
||||
});
|
||||
|
||||
test('each row in the volumes table lists information about the volume', async function(assert) {
|
||||
test('each row in the volumes table lists information about the volume', async function (assert) {
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
||||
TaskGroup.volumes[0].as(volumeRow => {
|
||||
TaskGroup.volumes[0].as((volumeRow) => {
|
||||
const volume = taskGroup.volumes[volumeRow.name];
|
||||
assert.equal(volumeRow.name, volume.Name);
|
||||
assert.equal(volumeRow.type, volume.Type);
|
||||
|
@ -486,21 +486,21 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
test('the count stepper sends the appropriate POST request', async function(assert) {
|
||||
test('the count stepper sends the appropriate POST request', async function (assert) {
|
||||
window.localStorage.nomadTokenSecret = managementToken.secretId;
|
||||
|
||||
job = server.create('job', {
|
||||
groupCount: 0,
|
||||
createAllocations: false,
|
||||
shallow: true,
|
||||
noActiveDeployment: true
|
||||
noActiveDeployment: true,
|
||||
});
|
||||
const scalingGroup = server.create('task-group', {
|
||||
job,
|
||||
name: 'scaling',
|
||||
count: 1,
|
||||
shallow: true,
|
||||
withScaling: true
|
||||
withScaling: true,
|
||||
});
|
||||
job.update({ taskGroupIds: [scalingGroup.id] });
|
||||
|
||||
|
@ -509,28 +509,28 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
await settled();
|
||||
|
||||
const scaleRequest = server.pretender.handledRequests.find(
|
||||
req => req.method === 'POST' && req.url.endsWith('/scale')
|
||||
(req) => req.method === 'POST' && req.url.endsWith('/scale')
|
||||
);
|
||||
const requestBody = JSON.parse(scaleRequest.requestBody);
|
||||
assert.equal(requestBody.Target.Group, scalingGroup.name);
|
||||
assert.equal(requestBody.Count, scalingGroup.count + 1);
|
||||
});
|
||||
|
||||
test('the count stepper is disabled when a deployment is running', async function(assert) {
|
||||
test('the count stepper is disabled when a deployment is running', async function (assert) {
|
||||
window.localStorage.nomadTokenSecret = managementToken.secretId;
|
||||
|
||||
job = server.create('job', {
|
||||
groupCount: 0,
|
||||
createAllocations: false,
|
||||
shallow: true,
|
||||
activeDeployment: true
|
||||
activeDeployment: true,
|
||||
});
|
||||
const scalingGroup = server.create('task-group', {
|
||||
job,
|
||||
name: 'scaling',
|
||||
count: 1,
|
||||
shallow: true,
|
||||
withScaling: true
|
||||
withScaling: true,
|
||||
});
|
||||
job.update({ taskGroupIds: [scalingGroup.id] });
|
||||
|
||||
|
@ -541,15 +541,15 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
assert.ok(TaskGroup.countStepper.decrement.isDisabled);
|
||||
});
|
||||
|
||||
test('when the job for the task group is not found, an error message is shown, but the URL persists', async function(assert) {
|
||||
test('when the job for the task group is not found, an error message is shown, but the URL persists', async function (assert) {
|
||||
await TaskGroup.visit({
|
||||
id: 'not-a-real-job',
|
||||
name: 'not-a-real-task-group'
|
||||
name: 'not-a-real-task-group',
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
server.pretender.handledRequests
|
||||
.filter(request => !request.url.includes('policy'))
|
||||
.filter((request) => !request.url.includes('policy'))
|
||||
.findBy('status', 404).url,
|
||||
'/v1/job/not-a-real-job',
|
||||
'A request to the nonexistent job is made'
|
||||
|
@ -567,7 +567,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('when the task group is not found on the job, an error message is shown, but the URL persists', async function(assert) {
|
||||
test('when the task group is not found on the job, an error message is shown, but the URL persists', async function (assert) {
|
||||
await TaskGroup.visit({ id: job.id, name: 'not-a-real-task-group' });
|
||||
|
||||
assert.ok(
|
||||
|
@ -598,16 +598,16 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
server.createList('allocation', TaskGroup.pageSize, {
|
||||
jobId: job.id,
|
||||
taskGroup: taskGroup.name,
|
||||
clientStatus: 'running'
|
||||
clientStatus: 'running',
|
||||
});
|
||||
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
test('when a task group has no scaling events, there is no recent scaling events section', async function(assert) {
|
||||
test('when a task group has no scaling events, there is no recent scaling events section', async function (assert) {
|
||||
const taskGroupScale = job.jobScale.taskGroupScales.models.find(
|
||||
m => m.name === taskGroup.name
|
||||
(m) => m.name === taskGroup.name
|
||||
);
|
||||
taskGroupScale.update({ events: [] });
|
||||
|
||||
|
@ -616,9 +616,9 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
assert.notOk(TaskGroup.hasScaleEvents);
|
||||
});
|
||||
|
||||
test('the recent scaling events section shows all recent scaling events in reverse chronological order', async function(assert) {
|
||||
test('the recent scaling events section shows all recent scaling events in reverse chronological order', async function (assert) {
|
||||
const taskGroupScale = job.jobScale.taskGroupScales.models.find(
|
||||
m => m.name === taskGroup.name
|
||||
(m) => m.name === taskGroup.name
|
||||
);
|
||||
taskGroupScale.update({
|
||||
events: [
|
||||
|
@ -627,8 +627,8 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
server.create('scale-event', { error: true }),
|
||||
server.create('scale-event', { error: true }),
|
||||
server.create('scale-event', { count: 3, error: false }),
|
||||
server.create('scale-event', { count: 1, error: false })
|
||||
]
|
||||
server.create('scale-event', { count: 1, error: false }),
|
||||
],
|
||||
});
|
||||
const scaleEvents = taskGroupScale.events.models.sortBy('time').reverse();
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
@ -660,9 +660,9 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
test('when a task group has at least two count scaling events and the count scaling events outnumber the non-count scaling events, a timeline is shown in addition to the accordion', async function(assert) {
|
||||
test('when a task group has at least two count scaling events and the count scaling events outnumber the non-count scaling events, a timeline is shown in addition to the accordion', async function (assert) {
|
||||
const taskGroupScale = job.jobScale.taskGroupScales.models.find(
|
||||
m => m.name === taskGroup.name
|
||||
(m) => m.name === taskGroup.name
|
||||
);
|
||||
taskGroupScale.update({
|
||||
events: [
|
||||
|
@ -674,8 +674,8 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
server.create('scale-event', { count: 3, error: false }),
|
||||
server.create('scale-event', { count: 2, error: false }),
|
||||
server.create('scale-event', { count: 9, error: false }),
|
||||
server.create('scale-event', { count: 1, error: false })
|
||||
]
|
||||
server.create('scale-event', { count: 1, error: false }),
|
||||
],
|
||||
});
|
||||
const scaleEvents = taskGroupScale.events.models.sortBy('time').reverse();
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
@ -685,7 +685,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
|
||||
assert.equal(
|
||||
TaskGroup.scalingAnnotations.length,
|
||||
scaleEvents.filter(ev => ev.count == null).length
|
||||
scaleEvents.filter((ev) => ev.count == null).length
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -694,7 +694,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
paramName: 'status',
|
||||
expectedOptions: ['Pending', 'Running', 'Complete', 'Failed', 'Lost'],
|
||||
async beforeEach() {
|
||||
['pending', 'running', 'complete', 'failed', 'lost'].forEach(s => {
|
||||
['pending', 'running', 'complete', 'failed', 'lost'].forEach((s) => {
|
||||
server.createList('allocation', 5, { clientStatus: s });
|
||||
});
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
@ -702,7 +702,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
filter: (alloc, selection) =>
|
||||
alloc.jobId == job.id &&
|
||||
alloc.taskGroup == taskGroup.name &&
|
||||
selection.includes(alloc.clientStatus)
|
||||
selection.includes(alloc.clientStatus),
|
||||
});
|
||||
|
||||
testFacet('Client', {
|
||||
|
@ -713,21 +713,21 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
new Set(
|
||||
allocs
|
||||
.filter(
|
||||
alloc =>
|
||||
(alloc) =>
|
||||
alloc.jobId == job.id && alloc.taskGroup == taskGroup.name
|
||||
)
|
||||
.mapBy('nodeId')
|
||||
.map(id => id.split('-')[0])
|
||||
.map((id) => id.split('-')[0])
|
||||
)
|
||||
).sort();
|
||||
},
|
||||
async beforeEach() {
|
||||
const nodes = server.createList('node', 3, 'forceIPv4');
|
||||
nodes.forEach(node =>
|
||||
nodes.forEach((node) =>
|
||||
server.createList('allocation', 5, {
|
||||
nodeId: node.id,
|
||||
jobId: job.id,
|
||||
taskGroup: taskGroup.name
|
||||
taskGroup: taskGroup.name,
|
||||
})
|
||||
);
|
||||
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
|
||||
|
@ -735,7 +735,7 @@ module('Acceptance | task group detail', function(hooks) {
|
|||
filter: (alloc, selection) =>
|
||||
alloc.jobId == job.id &&
|
||||
alloc.taskGroup == taskGroup.name &&
|
||||
selection.includes(alloc.nodeId.split('-')[0])
|
||||
selection.includes(alloc.nodeId.split('-')[0]),
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -743,7 +743,7 @@ function testFacet(
|
|||
label,
|
||||
{ facet, paramName, beforeEach, filter, expectedOptions }
|
||||
) {
|
||||
test(`facet ${label} | the ${label} facet has the correct options`, async function(assert) {
|
||||
test(`facet ${label} | the ${label} facet has the correct options`, async function (assert) {
|
||||
await beforeEach();
|
||||
await facet.toggle();
|
||||
|
||||
|
@ -755,13 +755,13 @@ function testFacet(
|
|||
}
|
||||
|
||||
assert.deepEqual(
|
||||
facet.options.map(option => option.label.trim()),
|
||||
facet.options.map((option) => option.label.trim()),
|
||||
expectation,
|
||||
'Options for facet are as expected'
|
||||
);
|
||||
});
|
||||
|
||||
test(`facet ${label} | the ${label} facet filters the allocations list by ${label}`, async function(assert) {
|
||||
test(`facet ${label} | the ${label} facet filters the allocations list by ${label}`, async function (assert) {
|
||||
let option;
|
||||
|
||||
await beforeEach();
|
||||
|
@ -772,7 +772,7 @@ function testFacet(
|
|||
|
||||
const selection = [option.key];
|
||||
const expectedAllocs = server.db.allocations
|
||||
.filter(alloc => filter(alloc, selection))
|
||||
.filter((alloc) => filter(alloc, selection))
|
||||
.sortBy('modifyIndex')
|
||||
.reverse();
|
||||
|
||||
|
@ -785,7 +785,7 @@ function testFacet(
|
|||
});
|
||||
});
|
||||
|
||||
test(`facet ${label} | selecting multiple options in the ${label} facet results in a broader search`, async function(assert) {
|
||||
test(`facet ${label} | selecting multiple options in the ${label} facet results in a broader search`, async function (assert) {
|
||||
const selection = [];
|
||||
|
||||
await beforeEach();
|
||||
|
@ -799,7 +799,7 @@ function testFacet(
|
|||
selection.push(option2.key);
|
||||
|
||||
const expectedAllocs = server.db.allocations
|
||||
.filter(alloc => filter(alloc, selection))
|
||||
.filter((alloc) => filter(alloc, selection))
|
||||
.sortBy('modifyIndex')
|
||||
.reverse();
|
||||
|
||||
|
@ -812,7 +812,7 @@ function testFacet(
|
|||
});
|
||||
});
|
||||
|
||||
test(`facet ${label} | selecting options in the ${label} facet updates the ${paramName} query param`, async function(assert) {
|
||||
test(`facet ${label} | selecting options in the ${label} facet updates the ${paramName} query param`, async function (assert) {
|
||||
const selection = [];
|
||||
|
||||
await beforeEach();
|
||||
|
|
|
@ -16,10 +16,10 @@ export default function moduleForJob(
|
|||
) {
|
||||
let job;
|
||||
|
||||
module(title, function(hooks) {
|
||||
module(title, function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
hooks.before(function() {
|
||||
hooks.before(function () {
|
||||
if (context !== 'allocations' && context !== 'children') {
|
||||
throw new Error(
|
||||
`Invalid context provided to moduleForJob, expected either "allocations" or "children", got ${context}`
|
||||
|
@ -27,7 +27,7 @@ export default function moduleForJob(
|
|||
}
|
||||
});
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
server.create('node');
|
||||
job = jobFactory();
|
||||
if (!job.namespace || job.namespace === 'default') {
|
||||
|
@ -37,7 +37,7 @@ export default function moduleForJob(
|
|||
}
|
||||
});
|
||||
|
||||
test('visiting /jobs/:job_id', async function(assert) {
|
||||
test('visiting /jobs/:job_id', async function (assert) {
|
||||
const expectedURL = new URL(
|
||||
urlWithNamespace(`/jobs/${encodeURIComponent(job.id)}`, job.namespace),
|
||||
window.location
|
||||
|
@ -49,7 +49,7 @@ export default function moduleForJob(
|
|||
assert.equal(document.title, `Job ${job.name} - Nomad`);
|
||||
});
|
||||
|
||||
test('the subnav links to overview', async function(assert) {
|
||||
test('the subnav links to overview', async function (assert) {
|
||||
await JobDetail.tabFor('overview').visit();
|
||||
|
||||
const expectedURL = new URL(
|
||||
|
@ -62,7 +62,7 @@ export default function moduleForJob(
|
|||
assert.deepEqual(gotURL.searchParams, expectedURL.searchParams);
|
||||
});
|
||||
|
||||
test('the subnav links to definition', async function(assert) {
|
||||
test('the subnav links to definition', async function (assert) {
|
||||
await JobDetail.tabFor('definition').visit();
|
||||
assert.equal(
|
||||
currentURL(),
|
||||
|
@ -73,7 +73,7 @@ export default function moduleForJob(
|
|||
);
|
||||
});
|
||||
|
||||
test('the subnav links to versions', async function(assert) {
|
||||
test('the subnav links to versions', async function (assert) {
|
||||
await JobDetail.tabFor('versions').visit();
|
||||
assert.equal(
|
||||
currentURL(),
|
||||
|
@ -84,7 +84,7 @@ export default function moduleForJob(
|
|||
);
|
||||
});
|
||||
|
||||
test('the subnav links to evaluations', async function(assert) {
|
||||
test('the subnav links to evaluations', async function (assert) {
|
||||
await JobDetail.tabFor('evaluations').visit();
|
||||
assert.equal(
|
||||
currentURL(),
|
||||
|
@ -95,7 +95,7 @@ export default function moduleForJob(
|
|||
);
|
||||
});
|
||||
|
||||
test('the title buttons are dependent on job status', async function(assert) {
|
||||
test('the title buttons are dependent on job status', async function (assert) {
|
||||
if (job.status === 'dead') {
|
||||
assert.ok(JobDetail.start.isPresent);
|
||||
assert.notOk(JobDetail.stop.isPresent);
|
||||
|
@ -108,7 +108,7 @@ export default function moduleForJob(
|
|||
});
|
||||
|
||||
if (context === 'allocations') {
|
||||
test('allocations for the job are shown in the overview', async function(assert) {
|
||||
test('allocations for the job are shown in the overview', async function (assert) {
|
||||
assert.ok(
|
||||
JobDetail.allocationsSummary.isPresent,
|
||||
'Allocations are shown in the summary section'
|
||||
|
@ -119,7 +119,7 @@ export default function moduleForJob(
|
|||
);
|
||||
});
|
||||
|
||||
test('clicking in an allocation row navigates to that allocation', async function(assert) {
|
||||
test('clicking in an allocation row navigates to that allocation', async function (assert) {
|
||||
const allocationRow = JobDetail.allocations[0];
|
||||
const allocationId = allocationRow.id;
|
||||
|
||||
|
@ -132,7 +132,7 @@ export default function moduleForJob(
|
|||
);
|
||||
});
|
||||
|
||||
test('clicking legend item navigates to a pre-filtered allocations table', async function(assert) {
|
||||
test('clicking legend item navigates to a pre-filtered allocations table', async function (assert) {
|
||||
const legendItem =
|
||||
JobDetail.allocationsSummary.legend.clickableItems[1];
|
||||
const status = legendItem.label;
|
||||
|
@ -151,7 +151,7 @@ export default function moduleForJob(
|
|||
assert.deepEqual(gotURL.searchParams, expectedURL.searchParams);
|
||||
});
|
||||
|
||||
test('clicking in a slice takes you to a pre-filtered allocations table', async function(assert) {
|
||||
test('clicking in a slice takes you to a pre-filtered allocations table', async function (assert) {
|
||||
const slice = JobDetail.allocationsSummary.slices[1];
|
||||
const status = slice.label;
|
||||
await slice.click();
|
||||
|
@ -180,7 +180,7 @@ export default function moduleForJob(
|
|||
}
|
||||
|
||||
if (context === 'children') {
|
||||
test('children for the job are shown in the overview', async function(assert) {
|
||||
test('children for the job are shown in the overview', async function (assert) {
|
||||
assert.ok(
|
||||
JobDetail.childrenSummary.isPresent,
|
||||
'Children are shown in the summary section'
|
||||
|
@ -193,7 +193,7 @@ export default function moduleForJob(
|
|||
}
|
||||
|
||||
for (var testName in additionalTests) {
|
||||
test(testName, async function(assert) {
|
||||
test(testName, async function (assert) {
|
||||
await additionalTests[testName].call(this, job, assert);
|
||||
});
|
||||
}
|
||||
|
@ -208,20 +208,20 @@ export function moduleForJobWithClientStatus(
|
|||
) {
|
||||
let job;
|
||||
|
||||
module(title, function(hooks) {
|
||||
module(title, function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function() {
|
||||
hooks.beforeEach(async function () {
|
||||
// Displaying the job status in client requires node:read permission.
|
||||
const policy = server.create('policy', {
|
||||
id: 'node-read',
|
||||
name: 'node-read',
|
||||
rulesJSON: {
|
||||
Node: {
|
||||
Policy: 'read'
|
||||
}
|
||||
}
|
||||
Policy: 'read',
|
||||
},
|
||||
},
|
||||
});
|
||||
const clientToken = server.create('token', { type: 'client' });
|
||||
clientToken.policyIds = [policy.id];
|
||||
|
@ -232,10 +232,10 @@ export function moduleForJobWithClientStatus(
|
|||
|
||||
const clients = server.createList('node', 3, {
|
||||
datacenter: 'dc1',
|
||||
status: 'ready'
|
||||
status: 'ready',
|
||||
});
|
||||
job = jobFactory();
|
||||
clients.forEach(c => {
|
||||
clients.forEach((c) => {
|
||||
server.create('allocation', { jobId: job.id, nodeId: c.id });
|
||||
});
|
||||
if (!job.namespace || job.namespace === 'default') {
|
||||
|
@ -245,7 +245,7 @@ export function moduleForJobWithClientStatus(
|
|||
}
|
||||
});
|
||||
|
||||
test('job status summary is collapsed when not authorized', async function(assert) {
|
||||
test('job status summary is collapsed when not authorized', async function (assert) {
|
||||
const clientToken = server.create('token', { type: 'client' });
|
||||
await Tokens.visit();
|
||||
await Tokens.secret(clientToken.secretId).submit();
|
||||
|
@ -262,7 +262,7 @@ export function moduleForJobWithClientStatus(
|
|||
);
|
||||
});
|
||||
|
||||
test('the subnav links to clients', async function(assert) {
|
||||
test('the subnav links to clients', async function (assert) {
|
||||
await JobDetail.tabFor('clients').visit();
|
||||
assert.equal(
|
||||
currentURL(),
|
||||
|
@ -273,14 +273,14 @@ export function moduleForJobWithClientStatus(
|
|||
);
|
||||
});
|
||||
|
||||
test('job status summary is shown in the overview', async function(assert) {
|
||||
test('job status summary is shown in the overview', async function (assert) {
|
||||
assert.ok(
|
||||
JobDetail.jobClientStatusSummary.statusBar.isPresent,
|
||||
'Summary bar is displayed in the Job Status in Client summary section'
|
||||
);
|
||||
});
|
||||
|
||||
test('clicking legend item navigates to a pre-filtered clients table', async function(assert) {
|
||||
test('clicking legend item navigates to a pre-filtered clients table', async function (assert) {
|
||||
const legendItem =
|
||||
JobDetail.jobClientStatusSummary.statusBar.legend.clickableItems[0];
|
||||
const status = legendItem.label;
|
||||
|
@ -299,7 +299,7 @@ export function moduleForJobWithClientStatus(
|
|||
assert.deepEqual(gotURL.searchParams, expectedURL.searchParams);
|
||||
});
|
||||
|
||||
test('clicking in a slice takes you to a pre-filtered clients table', async function(assert) {
|
||||
test('clicking in a slice takes you to a pre-filtered clients table', async function (assert) {
|
||||
const slice = JobDetail.jobClientStatusSummary.statusBar.slices[0];
|
||||
const status = slice.label;
|
||||
await slice.click();
|
||||
|
@ -325,7 +325,7 @@ export function moduleForJobWithClientStatus(
|
|||
});
|
||||
|
||||
for (var testName in additionalTests) {
|
||||
test(testName, async function(assert) {
|
||||
test(testName, async function (assert) {
|
||||
await additionalTests[testName].call(this, job, assert);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@ import Response from 'ember-cli-mirage/response';
|
|||
import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer';
|
||||
import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit';
|
||||
|
||||
module('Integration | Component | allocation row', function(hooks) {
|
||||
module('Integration | Component | allocation row', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function() {
|
||||
hooks.beforeEach(function () {
|
||||
fragmentSerializerInitializer(this.owner);
|
||||
this.store = this.owner.lookup('service:store');
|
||||
this.token = this.owner.lookup('service:token');
|
||||
|
@ -22,11 +22,11 @@ module('Integration | Component | allocation row', function(hooks) {
|
|||
window.localStorage.clear();
|
||||
});
|
||||
|
||||
hooks.afterEach(function() {
|
||||
hooks.afterEach(function () {
|
||||
this.server.shutdown();
|
||||
});
|
||||
|
||||
test('Allocation row polls for stats, even when it errors or has an invalid response', async function(assert) {
|
||||
test('Allocation row polls for stats, even when it errors or has an invalid response', async function (assert) {
|
||||
const component = this;
|
||||
|
||||
let currentFrame = 0;
|
||||
|
@ -35,10 +35,10 @@ module('Integration | Component | allocation row', function(hooks) {
|
|||
JSON.stringify({ ResourceUsage: generateResources() }),
|
||||
null,
|
||||
'<Not>Valid JSON</Not>',
|
||||
JSON.stringify({ ResourceUsage: generateResources() })
|
||||
JSON.stringify({ ResourceUsage: generateResources() }),
|
||||
];
|
||||
|
||||
this.server.get('/client/allocation/:id/stats', function() {
|
||||
this.server.get('/client/allocation/:id/stats', function () {
|
||||
const response = frames[++currentFrame];
|
||||
|
||||
// Disable polling to stop the EC task in the component
|
||||
|
@ -60,7 +60,7 @@ module('Integration | Component | allocation row', function(hooks) {
|
|||
this.setProperties({
|
||||
allocation,
|
||||
context: 'job',
|
||||
enablePolling: true
|
||||
enablePolling: true,
|
||||
});
|
||||
|
||||
await render(hbs`
|
||||
|
@ -80,16 +80,18 @@ module('Integration | Component | allocation row', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('Allocation row shows warning when it requires drivers that are unhealthy on the node it is running on', async function(assert) {
|
||||
test('Allocation row shows warning when it requires drivers that are unhealthy on the node it is running on', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
// Driver health status require node:read permission.
|
||||
const policy = server.create('policy', {
|
||||
id: 'node-read',
|
||||
name: 'node-read',
|
||||
rulesJSON: {
|
||||
Node: {
|
||||
Policy: 'read'
|
||||
}
|
||||
}
|
||||
Policy: 'read',
|
||||
},
|
||||
},
|
||||
});
|
||||
const clientToken = server.create('token', { type: 'client' });
|
||||
clientToken.policyIds = [policy.id];
|
||||
|
@ -101,7 +103,7 @@ module('Integration | Component | allocation row', function(hooks) {
|
|||
|
||||
const node = this.server.schema.nodes.first();
|
||||
const drivers = node.drivers;
|
||||
Object.values(drivers).forEach(driver => {
|
||||
Object.values(drivers).forEach((driver) => {
|
||||
driver.Healthy = false;
|
||||
driver.Detected = true;
|
||||
});
|
||||
|
@ -116,7 +118,7 @@ module('Integration | Component | allocation row', function(hooks) {
|
|||
|
||||
this.setProperties({
|
||||
allocation,
|
||||
context: 'job'
|
||||
context: 'job',
|
||||
});
|
||||
|
||||
await render(hbs`
|
||||
|
@ -132,7 +134,9 @@ module('Integration | Component | allocation row', function(hooks) {
|
|||
await componentA11yAudit(this.element, assert);
|
||||
});
|
||||
|
||||
test('Allocation row shows an icon indicator when it was preempted', async function(assert) {
|
||||
test('Allocation row shows an icon indicator when it was preempted', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const allocId = this.server.create('allocation', 'preempted').id;
|
||||
const allocation = await this.store.findRecord('allocation', allocId);
|
||||
|
||||
|
@ -147,14 +151,16 @@ module('Integration | Component | allocation row', function(hooks) {
|
|||
await componentA11yAudit(this.element, assert);
|
||||
});
|
||||
|
||||
test('when an allocation is not running, the utilization graphs are omitted', async function(assert) {
|
||||
test('when an allocation is not running, the utilization graphs are omitted', async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
this.setProperties({
|
||||
context: 'job',
|
||||
enablePolling: false
|
||||
enablePolling: false,
|
||||
});
|
||||
|
||||
// All non-running statuses need to be tested
|
||||
['pending', 'complete', 'failed', 'lost'].forEach(clientStatus =>
|
||||
['pending', 'complete', 'failed', 'lost'].forEach((clientStatus) =>
|
||||
this.server.create('allocation', { clientStatus })
|
||||
);
|
||||
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
/* eslint-disable ember-a11y-testing/a11y-audit-called */
|
||||
import { setComponentTemplate } from '@ember/component';
|
||||
import Component from '@glimmer/component';
|
||||
import templateOnlyComponent from '@ember/component/template-only';
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { findAll, render } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
module('Integration | Component | app breadcrumbs', function(hooks) {
|
||||
module('Integration | Component | app breadcrumbs', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
const commonCrumbs = [
|
||||
{ label: 'Jobs', args: ['jobs.index'] },
|
||||
{ label: 'Job', args: ['jobs.job.index'] }
|
||||
{ label: 'Job', args: ['jobs.job.index'] },
|
||||
];
|
||||
|
||||
test('every breadcrumb is rendered correctly', async function(assert) {
|
||||
test('every breadcrumb is rendered correctly', async function (assert) {
|
||||
assert.expect(3);
|
||||
this.set('commonCrumbs', commonCrumbs);
|
||||
await render(hbs`
|
||||
<AppBreadcrumbs />
|
||||
|
@ -40,21 +41,20 @@ module('Integration | Component | app breadcrumbs', function(hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
test('when we register a crumb with a type property, a dedicated breadcrumb/<type> component renders', async function(assert) {
|
||||
test('when we register a crumb with a type property, a dedicated breadcrumb/<type> component renders', async function (assert) {
|
||||
const crumbs = [
|
||||
{ label: 'Jobs', args: ['jobs.index'] },
|
||||
{ type: 'special', label: 'Job', args: ['jobs.job.index'] }
|
||||
{ type: 'special', label: 'Job', args: ['jobs.job.index'] },
|
||||
];
|
||||
this.set('crumbs', crumbs);
|
||||
|
||||
class MockComponent extends Component {}
|
||||
this.owner.register(
|
||||
'component:breadcrumbs/special',
|
||||
setComponentTemplate(
|
||||
hbs`
|
||||
<div data-test-breadcrumb-special>Test</div>
|
||||
`,
|
||||
MockComponent
|
||||
templateOnlyComponent()
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@ import { setupRenderingTest } from 'ember-qunit';
|
|||
import { click, findAll, render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Component | breadcrumbs', function(hooks) {
|
||||
module('Integration | Component | breadcrumbs', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it declaratively renders a list of registered crumbs', async function(assert) {
|
||||
test('it declaratively renders a list of registered crumbs', async function (assert) {
|
||||
this.set('isRegistered', false);
|
||||
this.set('toggleCrumb', () => this.set('isRegistered', !this.isRegistered));
|
||||
await render(hbs`
|
||||
|
@ -25,8 +25,12 @@ module('Integration | Component | breadcrumbs', function(hooks) {
|
|||
{{/if}}
|
||||
`);
|
||||
|
||||
assert.dom('[data-test-crumb]').exists({ count: 1 }, 'We register one crumb');
|
||||
assert.dom('[data-test-crumb]').hasText('Zoey', 'The first registered crumb is Zoey');
|
||||
assert
|
||||
.dom('[data-test-crumb]')
|
||||
.exists({ count: 1 }, 'We register one crumb');
|
||||
assert
|
||||
.dom('[data-test-crumb]')
|
||||
.hasText('Zoey', 'The first registered crumb is Zoey');
|
||||
|
||||
await click('[data-test-button]');
|
||||
const crumbs = await findAll('[data-test-crumb]');
|
||||
|
@ -36,19 +40,30 @@ module('Integration | Component | breadcrumbs', function(hooks) {
|
|||
.exists({ count: 2 }, 'The second crumb registered successfully');
|
||||
assert
|
||||
.dom(crumbs[0])
|
||||
.hasText('Zoey', 'Breadcrumbs maintain the order in which they are declared');
|
||||
.hasText(
|
||||
'Zoey',
|
||||
'Breadcrumbs maintain the order in which they are declared'
|
||||
);
|
||||
assert
|
||||
.dom(crumbs[1])
|
||||
.hasText('Tomster', 'Breadcrumbs maintain the order in which they are declared');
|
||||
.hasText(
|
||||
'Tomster',
|
||||
'Breadcrumbs maintain the order in which they are declared'
|
||||
);
|
||||
|
||||
await click('[data-test-button]');
|
||||
assert.dom('[data-test-crumb]').exists({ count: 1 }, 'We deregister one crumb');
|
||||
assert
|
||||
.dom('[data-test-crumb]')
|
||||
.hasText('Zoey', 'Zoey remains in the template after Tomster deregisters');
|
||||
.exists({ count: 1 }, 'We deregister one crumb');
|
||||
assert
|
||||
.dom('[data-test-crumb]')
|
||||
.hasText(
|
||||
'Zoey',
|
||||
'Zoey remains in the template after Tomster deregisters'
|
||||
);
|
||||
});
|
||||
|
||||
test('it can register complex crumb objects', async function(assert) {
|
||||
test('it can register complex crumb objects', async function (assert) {
|
||||
await render(hbs`
|
||||
<Breadcrumbs as |bb|>
|
||||
<ul>
|
||||
|
@ -62,6 +77,9 @@ module('Integration | Component | breadcrumbs', function(hooks) {
|
|||
|
||||
assert
|
||||
.dom('[data-test-crumb]')
|
||||
.hasText('Tomster', 'We can access the registered breadcrumbs in the template');
|
||||
.hasText(
|
||||
'Tomster',
|
||||
'We can access the registered breadcrumbs in the template'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,11 +4,11 @@ import { setupRenderingTest } from 'ember-qunit';
|
|||
import { render, click, waitFor } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Component | trigger', function(hooks) {
|
||||
module('Integration | Component | trigger', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
module('Synchronous Interactions', function() {
|
||||
test('it can trigger a synchronous action', async function(assert) {
|
||||
module('Synchronous Interactions', function () {
|
||||
test('it can trigger a synchronous action', async function (assert) {
|
||||
this.set('name', 'Tomster');
|
||||
this.set('changeName', () => this.set('name', 'Zoey'));
|
||||
await render(hbs`
|
||||
|
@ -17,16 +17,21 @@ module('Integration | Component | trigger', function(hooks) {
|
|||
<button data-test-button type="button" {{on "click" trigger.fns.do}}>Change my name.</button>
|
||||
</Trigger>
|
||||
`);
|
||||
assert.dom('[data-test-name]').hasText('Tomster', 'Initial state renders correctly.');
|
||||
assert
|
||||
.dom('[data-test-name]')
|
||||
.hasText('Tomster', 'Initial state renders correctly.');
|
||||
|
||||
await click('[data-test-button]');
|
||||
|
||||
assert
|
||||
.dom('[data-test-name]')
|
||||
.hasText('Zoey', 'The name property changes when the button is clicked');
|
||||
.hasText(
|
||||
'Zoey',
|
||||
'The name property changes when the button is clicked'
|
||||
);
|
||||
});
|
||||
|
||||
test('it sets the result of the action', async function(assert) {
|
||||
test('it sets the result of the action', async function (assert) {
|
||||
this.set('tomster', () => 'Tomster');
|
||||
await render(hbs`
|
||||
<Trigger @do={{this.tomster}} as |trigger|>
|
||||
|
@ -38,22 +43,27 @@ module('Integration | Component | trigger', function(hooks) {
|
|||
`);
|
||||
assert
|
||||
.dom('[data-test-name]')
|
||||
.doesNotExist('Initial state does not render because there is no result yet.');
|
||||
.doesNotExist(
|
||||
'Initial state does not render because there is no result yet.'
|
||||
);
|
||||
|
||||
await click('[data-test-button]');
|
||||
|
||||
assert
|
||||
.dom('[data-test-name]')
|
||||
.hasText('Tomster', 'The result state updates after the triggered action');
|
||||
.hasText(
|
||||
'Tomster',
|
||||
'The result state updates after the triggered action'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
module('Asynchronous Interactions', function() {
|
||||
test('it can trigger an asynchronous action', async function(assert) {
|
||||
module('Asynchronous Interactions', function () {
|
||||
test('it can trigger an asynchronous action', async function (assert) {
|
||||
this.set(
|
||||
'onTrigger',
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
new Promise((resolve) => {
|
||||
this.set('resolve', resolve);
|
||||
})
|
||||
);
|
||||
|
@ -72,15 +82,21 @@ module('Integration | Component | trigger', function(hooks) {
|
|||
|
||||
assert
|
||||
.dom('[data-test-div]')
|
||||
.doesNotExist('The div does not render until after the action dispatches successfully');
|
||||
.doesNotExist(
|
||||
'The div does not render until after the action dispatches successfully'
|
||||
);
|
||||
|
||||
await click('[data-test-button]');
|
||||
assert
|
||||
.dom('[data-test-div-loading]')
|
||||
.exists('Loading state is displayed when the action hasnt resolved yet');
|
||||
.exists(
|
||||
'Loading state is displayed when the action hasnt resolved yet'
|
||||
);
|
||||
assert
|
||||
.dom('[data-test-div]')
|
||||
.doesNotExist('Success message does not display until after promise resolves');
|
||||
.doesNotExist(
|
||||
'Success message does not display until after promise resolves'
|
||||
);
|
||||
|
||||
this.resolve();
|
||||
await waitFor('[data-test-div]');
|
||||
|
@ -91,15 +107,21 @@ module('Integration | Component | trigger', function(hooks) {
|
|||
);
|
||||
assert
|
||||
.dom('[data-test-div]')
|
||||
.exists('Action has dispatched successfully after the promise resolves');
|
||||
.exists(
|
||||
'Action has dispatched successfully after the promise resolves'
|
||||
);
|
||||
|
||||
await click('[data-test-button]');
|
||||
assert
|
||||
.dom('[data-test-div]')
|
||||
.doesNotExist('Aftering clicking the button, again, the state is reset');
|
||||
.doesNotExist(
|
||||
'Aftering clicking the button, again, the state is reset'
|
||||
);
|
||||
assert
|
||||
.dom('[data-test-div-loading]')
|
||||
.exists('After clicking the button, again, we are back in the loading state');
|
||||
.exists(
|
||||
'After clicking the button, again, we are back in the loading state'
|
||||
);
|
||||
|
||||
this.resolve();
|
||||
await waitFor('[data-test-div]');
|
||||
|
@ -111,11 +133,11 @@ module('Integration | Component | trigger', function(hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('it handles the success state', async function(assert) {
|
||||
test('it handles the success state', async function (assert) {
|
||||
this.set(
|
||||
'onTrigger',
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
new Promise((resolve) => {
|
||||
this.set('resolve', resolve);
|
||||
})
|
||||
);
|
||||
|
@ -132,14 +154,16 @@ module('Integration | Component | trigger', function(hooks) {
|
|||
|
||||
assert
|
||||
.dom('[data-test-div]')
|
||||
.doesNotExist('No text should appear until after the onSuccess callback is fired');
|
||||
.doesNotExist(
|
||||
'No text should appear until after the onSuccess callback is fired'
|
||||
);
|
||||
await click('[data-test-button]');
|
||||
this.resolve();
|
||||
await waitFor('[data-test-div]');
|
||||
assert.verifySteps(['On success happened']);
|
||||
});
|
||||
|
||||
test('it handles the error state', async function(assert) {
|
||||
test('it handles the error state', async function (assert) {
|
||||
this.set(
|
||||
'onTrigger',
|
||||
() =>
|
||||
|
@ -166,11 +190,15 @@ module('Integration | Component | trigger', function(hooks) {
|
|||
await click('[data-test-button]');
|
||||
assert
|
||||
.dom('[data-test-div-loading]')
|
||||
.exists('Loading state is displayed when the action hasnt resolved yet');
|
||||
.exists(
|
||||
'Loading state is displayed when the action hasnt resolved yet'
|
||||
);
|
||||
|
||||
assert
|
||||
.dom('[data-test-div]')
|
||||
.doesNotExist('No text should appear until after the onError callback is fired');
|
||||
.doesNotExist(
|
||||
'No text should appear until after the onError callback is fired'
|
||||
);
|
||||
|
||||
this.reject();
|
||||
await waitFor('[data-test-span]');
|
||||
|
@ -180,7 +208,9 @@ module('Integration | Component | trigger', function(hooks) {
|
|||
|
||||
assert
|
||||
.dom('[data-test-div-loading]')
|
||||
.exists('The previous error state was cleared and we show loading, again.');
|
||||
.exists(
|
||||
'The previous error state was cleared and we show loading, again.'
|
||||
);
|
||||
|
||||
assert.dom('[data-test-div]').doesNotExist('The error state is cleared');
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
isPresent,
|
||||
property,
|
||||
text,
|
||||
visitable
|
||||
visitable,
|
||||
} from 'ember-cli-page-object';
|
||||
|
||||
import allocations from 'nomad-ui/tests/pages/components/allocations';
|
||||
|
@ -22,7 +22,7 @@ export default create({
|
|||
|
||||
tabs: collection('[data-test-tab]', {
|
||||
id: attribute('data-test-tab'),
|
||||
visit: clickable('a')
|
||||
visit: clickable('a'),
|
||||
}),
|
||||
|
||||
tabFor(id) {
|
||||
|
@ -44,22 +44,22 @@ export default create({
|
|||
scope: '[data-test-exec-button]',
|
||||
isDisabled: property('disabled'),
|
||||
hasTooltip: hasClass('tooltip'),
|
||||
tooltipText: attribute('aria-label')
|
||||
tooltipText: attribute('aria-label'),
|
||||
},
|
||||
|
||||
incrementButton: {
|
||||
scope: '[data-test-scale-controls-increment]',
|
||||
isDisabled: property('disabled')
|
||||
isDisabled: property('disabled'),
|
||||
},
|
||||
|
||||
dispatchButton: {
|
||||
scope: '[data-test-dispatch-button]',
|
||||
isDisabled: property('disabled')
|
||||
isDisabled: property('disabled'),
|
||||
},
|
||||
|
||||
stats: collection('[data-test-job-stat]', {
|
||||
id: attribute('data-test-job-stat'),
|
||||
text: text()
|
||||
text: text(),
|
||||
}),
|
||||
|
||||
statFor(id) {
|
||||
|
@ -68,7 +68,7 @@ export default create({
|
|||
|
||||
packStats: collection('[data-test-pack-stat]', {
|
||||
id: attribute('data-test-pack-stat'),
|
||||
text: text()
|
||||
text: text(),
|
||||
}),
|
||||
|
||||
packStatFor(id) {
|
||||
|
@ -82,8 +82,8 @@ export default create({
|
|||
scope: '[data-test-accordion-head] [data-test-accordion-toggle]',
|
||||
click: clickable(),
|
||||
isDisabled: attribute('disabled'),
|
||||
tooltip: attribute('aria-label')
|
||||
}
|
||||
tooltip: attribute('aria-label'),
|
||||
},
|
||||
},
|
||||
childrenSummary: jobClientStatusBar(
|
||||
'[data-test-job-summary] [data-test-children-status-bar]'
|
||||
|
@ -98,7 +98,7 @@ export default create({
|
|||
jobsHeader: {
|
||||
scope: '[data-test-jobs-header]',
|
||||
hasSubmitTime: isPresent('[data-test-jobs-submit-time-header]'),
|
||||
hasNamespace: isPresent('[data-test-jobs-namespace-header]')
|
||||
hasNamespace: isPresent('[data-test-jobs-namespace-header]'),
|
||||
},
|
||||
|
||||
jobs: collection('[data-test-job-row]', {
|
||||
|
@ -113,17 +113,17 @@ export default create({
|
|||
taskGroups: text('[data-test-job-task-groups]'),
|
||||
|
||||
clickRow: clickable(),
|
||||
clickName: clickable('[data-test-job-name] a')
|
||||
clickName: clickable('[data-test-job-name] a'),
|
||||
}),
|
||||
|
||||
error: {
|
||||
isPresent: isPresent('[data-test-error]'),
|
||||
title: text('[data-test-error-title]'),
|
||||
message: text('[data-test-error-message]'),
|
||||
seekHelp: clickable('[data-test-error-message] a')
|
||||
seekHelp: clickable('[data-test-error-message] a'),
|
||||
},
|
||||
|
||||
recentAllocationsEmptyState: {
|
||||
headline: text('[data-test-empty-recent-allocations-headline]')
|
||||
}
|
||||
headline: text('[data-test-empty-recent-allocations-headline]'),
|
||||
},
|
||||
});
|
||||
|
|
|
@ -4,11 +4,11 @@ import { setupTest } from 'ember-qunit';
|
|||
import Service from '@ember/service';
|
||||
import setupAbility from 'nomad-ui/tests/helpers/setup-ability';
|
||||
|
||||
module('Unit | Ability | client', function(hooks) {
|
||||
module('Unit | Ability | client', function (hooks) {
|
||||
setupTest(hooks);
|
||||
setupAbility('client')(hooks);
|
||||
|
||||
test('it permits client read and write when ACLs are disabled', function(assert) {
|
||||
test('it permits client read and write when ACLs are disabled', function (assert) {
|
||||
const mockToken = Service.extend({
|
||||
aclEnabled: false,
|
||||
});
|
||||
|
@ -18,7 +18,7 @@ module('Unit | Ability | client', function(hooks) {
|
|||
assert.ok(this.ability.canWrite);
|
||||
});
|
||||
|
||||
test('it permits client read and write for management tokens', function(assert) {
|
||||
test('it permits client read and write for management tokens', function (assert) {
|
||||
const mockToken = Service.extend({
|
||||
aclEnabled: true,
|
||||
selfToken: { type: 'management' },
|
||||
|
@ -29,7 +29,7 @@ module('Unit | Ability | client', function(hooks) {
|
|||
assert.ok(this.ability.canWrite);
|
||||
});
|
||||
|
||||
test('it permits client read and write for tokens with a policy that has node-write', function(assert) {
|
||||
test('it permits client read and write for tokens with a policy that has node-write', function (assert) {
|
||||
const mockToken = Service.extend({
|
||||
aclEnabled: true,
|
||||
selfToken: { type: 'client' },
|
||||
|
@ -49,7 +49,7 @@ module('Unit | Ability | client', function(hooks) {
|
|||
assert.ok(this.ability.canWrite);
|
||||
});
|
||||
|
||||
test('it permits client read and write for tokens with a policy that allows write and another policy that disallows it', function(assert) {
|
||||
test('it permits client read and write for tokens with a policy that allows write and another policy that disallows it', function (assert) {
|
||||
const mockToken = Service.extend({
|
||||
aclEnabled: true,
|
||||
selfToken: { type: 'client' },
|
||||
|
@ -76,7 +76,7 @@ module('Unit | Ability | client', function(hooks) {
|
|||
assert.ok(this.ability.canWrite);
|
||||
});
|
||||
|
||||
test('it permits client read and blocks client write for tokens with a policy that does not allow node-write', function(assert) {
|
||||
test('it permits client read and blocks client write for tokens with a policy that does not allow node-write', function (assert) {
|
||||
const mockToken = Service.extend({
|
||||
aclEnabled: true,
|
||||
selfToken: { type: 'client' },
|
||||
|
@ -96,7 +96,7 @@ module('Unit | Ability | client', function(hooks) {
|
|||
assert.notOk(this.ability.canWrite);
|
||||
});
|
||||
|
||||
test('it blocks client read and write for tokens without a node policy', function(assert) {
|
||||
test('it blocks client read and write for tokens without a node policy', function (assert) {
|
||||
const mockToken = Service.extend({
|
||||
aclEnabled: true,
|
||||
selfToken: { type: 'client' },
|
||||
|
|
|
@ -51,8 +51,8 @@ class AllocationMock {
|
|||
}
|
||||
}
|
||||
|
||||
module('Unit | Util | JobClientStatus', function() {
|
||||
test('it handles the case where all nodes are running', async function(assert) {
|
||||
module('Unit | Util | JobClientStatus', function () {
|
||||
test('it handles the case where all nodes are running', async function (assert) {
|
||||
const node = new NodeMock('node-1', 'dc1');
|
||||
const nodes = [node];
|
||||
const job = {
|
||||
|
@ -84,7 +84,7 @@ module('Unit | Util | JobClientStatus', function() {
|
|||
assert.deepEqual(result, expected);
|
||||
});
|
||||
|
||||
test('it handles the degraded case where a node has a failing allocation', async function(assert) {
|
||||
test('it handles the degraded case where a node has a failing allocation', async function (assert) {
|
||||
const node = new NodeMock('node-2', 'dc1');
|
||||
const nodes = [node];
|
||||
const job = {
|
||||
|
@ -120,7 +120,7 @@ module('Unit | Util | JobClientStatus', function() {
|
|||
assert.deepEqual(result, expected);
|
||||
});
|
||||
|
||||
test('it handles the case where a node has all lost allocations', async function(assert) {
|
||||
test('it handles the case where a node has all lost allocations', async function (assert) {
|
||||
const node = new NodeMock('node-1', 'dc1');
|
||||
const nodes = [node];
|
||||
const job = {
|
||||
|
@ -156,7 +156,7 @@ module('Unit | Util | JobClientStatus', function() {
|
|||
assert.deepEqual(result, expected);
|
||||
});
|
||||
|
||||
test('it handles the case where a node has all failed allocations', async function(assert) {
|
||||
test('it handles the case where a node has all failed allocations', async function (assert) {
|
||||
const node = new NodeMock('node-1', 'dc1');
|
||||
const nodes = [node];
|
||||
const job = {
|
||||
|
@ -192,7 +192,7 @@ module('Unit | Util | JobClientStatus', function() {
|
|||
assert.deepEqual(result, expected);
|
||||
});
|
||||
|
||||
test('it handles the degraded case where the expected number of allocations doesnt match the actual number of allocations', async function(assert) {
|
||||
test('it handles the degraded case where the expected number of allocations doesnt match the actual number of allocations', async function (assert) {
|
||||
const node = new NodeMock('node-1', 'dc1');
|
||||
const nodes = [node];
|
||||
const job = {
|
||||
|
@ -228,7 +228,7 @@ module('Unit | Util | JobClientStatus', function() {
|
|||
assert.deepEqual(result, expected);
|
||||
});
|
||||
|
||||
test('it handles the not scheduled case where a node has no allocations', async function(assert) {
|
||||
test('it handles the not scheduled case where a node has no allocations', async function (assert) {
|
||||
const node = new NodeMock('node-1', 'dc1');
|
||||
const nodes = [node];
|
||||
const job = {
|
||||
|
@ -260,7 +260,7 @@ module('Unit | Util | JobClientStatus', function() {
|
|||
assert.deepEqual(result, expected);
|
||||
});
|
||||
|
||||
test('it handles the queued case where the job is pending', async function(assert) {
|
||||
test('it handles the queued case where the job is pending', async function (assert) {
|
||||
const node = new NodeMock('node-1', 'dc1');
|
||||
const nodes = [node];
|
||||
const job = {
|
||||
|
@ -296,7 +296,7 @@ module('Unit | Util | JobClientStatus', function() {
|
|||
assert.deepEqual(result, expected);
|
||||
});
|
||||
|
||||
test('it filters nodes by the datacenter of the job', async function(assert) {
|
||||
test('it filters nodes by the datacenter of the job', async function (assert) {
|
||||
const node1 = new NodeMock('node-1', 'dc1');
|
||||
const node2 = new NodeMock('node-2', 'dc2');
|
||||
const nodes = [node1, node2];
|
||||
|
|
Loading…
Reference in a new issue