2023-04-10 15:36:59 +00:00
|
|
|
|
/**
|
|
|
|
|
* Copyright (c) HashiCorp, Inc.
|
|
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
*/
|
|
|
|
|
|
2021-12-28 19:30:38 +00:00
|
|
|
|
/* eslint-disable qunit/require-expect */
|
|
|
|
|
/* eslint-disable qunit/no-conditional-assertions */
|
2019-03-13 00:08:16 +00:00
|
|
|
|
import { currentURL } from '@ember/test-helpers';
|
2019-03-13 00:04:16 +00:00
|
|
|
|
import { module, test } from 'qunit';
|
|
|
|
|
import { setupApplicationTest } from 'ember-qunit';
|
2019-09-26 18:47:07 +00:00
|
|
|
|
import { setupMirage } from 'ember-cli-mirage/test-support';
|
2020-07-28 17:59:14 +00:00
|
|
|
|
import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit';
|
2018-07-11 16:45:30 +00:00
|
|
|
|
import Versions from 'nomad-ui/tests/pages/jobs/job/versions';
|
2021-04-20 13:33:16 +00:00
|
|
|
|
import Layout from 'nomad-ui/tests/pages/layout';
|
2017-09-19 14:47:10 +00:00
|
|
|
|
import moment from 'moment';
|
|
|
|
|
|
|
|
|
|
let job;
|
2021-04-20 13:33:16 +00:00
|
|
|
|
let namespace;
|
2017-09-19 14:47:10 +00:00
|
|
|
|
let versions;
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
module('Acceptance | job versions', function (hooks) {
|
2019-03-13 00:04:16 +00:00
|
|
|
|
setupApplicationTest(hooks);
|
2019-03-13 01:09:19 +00:00
|
|
|
|
setupMirage(hooks);
|
2019-03-13 00:04:16 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
hooks.beforeEach(async function () {
|
2023-06-22 17:11:44 +00:00
|
|
|
|
server.create('node-pool');
|
2021-04-20 13:33:16 +00:00
|
|
|
|
server.create('namespace');
|
|
|
|
|
namespace = server.create('namespace');
|
|
|
|
|
|
2021-12-28 16:08:12 +00:00
|
|
|
|
job = server.create('job', {
|
|
|
|
|
namespaceId: namespace.id,
|
|
|
|
|
createAllocations: false,
|
|
|
|
|
});
|
2017-09-19 14:47:10 +00:00
|
|
|
|
versions = server.db.jobVersions.where({ jobId: job.id });
|
|
|
|
|
|
2021-04-20 13:33:16 +00:00
|
|
|
|
const managementToken = server.create('token');
|
|
|
|
|
window.localStorage.nomadTokenSecret = managementToken.secretId;
|
|
|
|
|
|
2022-02-16 14:30:51 +00:00
|
|
|
|
await Versions.visit({ id: `${job.id}@${namespace.id}` });
|
2019-03-13 00:04:16 +00:00
|
|
|
|
});
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('it passes an accessibility audit', async function (assert) {
|
2020-08-25 15:56:02 +00:00
|
|
|
|
await a11yAudit(assert);
|
2020-07-28 17:59:14 +00:00
|
|
|
|
});
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('/jobs/:id/versions should list all job versions', async function (assert) {
|
2021-12-28 19:30:38 +00:00
|
|
|
|
assert.equal(
|
2021-12-28 16:08:12 +00:00
|
|
|
|
Versions.versions.length,
|
|
|
|
|
versions.length,
|
|
|
|
|
'Each version gets a row in the timeline'
|
|
|
|
|
);
|
2019-07-17 20:02:58 +00:00
|
|
|
|
assert.equal(document.title, `Job ${job.name} versions - Nomad`);
|
2019-03-13 00:04:16 +00:00
|
|
|
|
});
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('each version mentions the version number, the stability, and the submitted time', async function (assert) {
|
2019-03-13 00:04:16 +00:00
|
|
|
|
const version = versions.sortBy('submitTime').reverse()[0];
|
|
|
|
|
const formattedSubmitTime = moment(version.submitTime / 1000000).format(
|
|
|
|
|
"MMM DD, 'YY HH:mm:ss ZZ"
|
|
|
|
|
);
|
|
|
|
|
const versionRow = Versions.versions.objectAt(0);
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.ok(
|
|
|
|
|
versionRow.text.includes(`Version #${version.version}`),
|
|
|
|
|
'Version #'
|
|
|
|
|
);
|
2019-03-13 00:04:16 +00:00
|
|
|
|
assert.equal(versionRow.stability, version.stable.toString(), 'Stability');
|
|
|
|
|
assert.equal(versionRow.submitTime, formattedSubmitTime, 'Submit time');
|
|
|
|
|
});
|
2018-11-05 23:42:04 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('all versions but the current one have a button to revert to that version', async function (assert) {
|
2021-04-20 13:33:16 +00:00
|
|
|
|
let versionRowToRevertTo;
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
Versions.versions.forEach((versionRow) => {
|
2021-04-20 13:33:16 +00:00
|
|
|
|
if (versionRow.number === job.version) {
|
|
|
|
|
assert.ok(versionRow.revertToButton.isHidden);
|
|
|
|
|
} else {
|
|
|
|
|
assert.ok(versionRow.revertToButton.isPresent);
|
|
|
|
|
|
|
|
|
|
versionRowToRevertTo = versionRow;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (versionRowToRevertTo) {
|
|
|
|
|
const versionNumberRevertingTo = versionRowToRevertTo.number;
|
|
|
|
|
await versionRowToRevertTo.revertToButton.idle();
|
|
|
|
|
await versionRowToRevertTo.revertToButton.confirm();
|
|
|
|
|
|
2021-12-28 16:08:12 +00:00
|
|
|
|
const revertRequest = this.server.pretender.handledRequests.find(
|
|
|
|
|
(request) => request.url.includes('revert')
|
2021-07-14 20:27:24 +00:00
|
|
|
|
);
|
2021-04-20 13:33:16 +00:00
|
|
|
|
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.equal(
|
|
|
|
|
revertRequest.url,
|
|
|
|
|
`/v1/job/${job.id}/revert?namespace=${namespace.id}`
|
|
|
|
|
);
|
2021-04-20 13:33:16 +00:00
|
|
|
|
|
|
|
|
|
assert.deepEqual(JSON.parse(revertRequest.requestBody), {
|
|
|
|
|
JobID: job.id,
|
|
|
|
|
JobVersion: versionNumberRevertingTo,
|
|
|
|
|
});
|
|
|
|
|
|
2023-01-26 21:03:07 +00:00
|
|
|
|
assert.equal(currentURL(), `/jobs/${job.id}@${namespace.id}`);
|
2021-04-20 13:33:16 +00:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('when reversion fails, the error message from the API is piped through to the alert', async function (assert) {
|
2021-07-14 20:27:24 +00:00
|
|
|
|
const versionRowToRevertTo = Versions.versions.filter(
|
2021-12-28 14:45:20 +00:00
|
|
|
|
(versionRow) => versionRow.revertToButton.isPresent
|
2021-07-14 20:27:24 +00:00
|
|
|
|
)[0];
|
2021-04-20 13:33:16 +00:00
|
|
|
|
|
|
|
|
|
if (versionRowToRevertTo) {
|
|
|
|
|
const message = 'A plaintext error message';
|
|
|
|
|
server.pretender.post('/v1/job/:id/revert', () => [500, {}, message]);
|
|
|
|
|
|
|
|
|
|
await versionRowToRevertTo.revertToButton.idle();
|
|
|
|
|
await versionRowToRevertTo.revertToButton.confirm();
|
|
|
|
|
|
|
|
|
|
assert.ok(Layout.inlineError.isShown);
|
|
|
|
|
assert.ok(Layout.inlineError.isDanger);
|
|
|
|
|
assert.ok(Layout.inlineError.title.includes('Could Not Revert'));
|
|
|
|
|
assert.equal(Layout.inlineError.message, message);
|
|
|
|
|
|
|
|
|
|
await Layout.inlineError.dismiss();
|
|
|
|
|
|
|
|
|
|
assert.notOk(Layout.inlineError.isShown);
|
|
|
|
|
} else {
|
|
|
|
|
assert.expect(0);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('when reversion has no effect, the error message explains', async function (assert) {
|
2021-07-14 20:27:24 +00:00
|
|
|
|
const versionRowToRevertTo = Versions.versions.filter(
|
2021-12-28 14:45:20 +00:00
|
|
|
|
(versionRow) => versionRow.revertToButton.isPresent
|
2021-07-14 20:27:24 +00:00
|
|
|
|
)[0];
|
2021-04-20 13:33:16 +00:00
|
|
|
|
|
|
|
|
|
if (versionRowToRevertTo) {
|
|
|
|
|
// The default Mirage implementation updates the job version as passed in, this does nothing
|
2021-11-02 20:52:19 +00:00
|
|
|
|
server.pretender.post('/v1/job/:id/revert', () => [200, {}, '{}']);
|
2021-04-20 13:33:16 +00:00
|
|
|
|
|
|
|
|
|
await versionRowToRevertTo.revertToButton.idle();
|
|
|
|
|
await versionRowToRevertTo.revertToButton.confirm();
|
|
|
|
|
|
|
|
|
|
assert.ok(Layout.inlineError.isShown);
|
|
|
|
|
assert.ok(Layout.inlineError.isWarning);
|
|
|
|
|
assert.ok(Layout.inlineError.title.includes('Reversion Had No Effect'));
|
2021-07-14 20:27:24 +00:00
|
|
|
|
assert.equal(
|
|
|
|
|
Layout.inlineError.message,
|
|
|
|
|
'Reverting to an identical older version doesn’t produce a new version'
|
|
|
|
|
);
|
2021-04-20 13:33:16 +00:00
|
|
|
|
} else {
|
|
|
|
|
assert.expect(0);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('when the job for the versions is not found, an error message is shown, but the URL persists', async function (assert) {
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await Versions.visit({ id: 'not-a-real-job' });
|
2018-11-05 23:42:04 +00:00
|
|
|
|
|
|
|
|
|
assert.equal(
|
2020-01-20 20:57:01 +00:00
|
|
|
|
server.pretender.handledRequests
|
2021-12-28 14:45:20 +00:00
|
|
|
|
.filter((request) => !request.url.includes('policy'))
|
2020-01-20 20:57:01 +00:00
|
|
|
|
.findBy('status', 404).url,
|
2018-11-05 23:42:04 +00:00
|
|
|
|
'/v1/job/not-a-real-job',
|
|
|
|
|
'A request to the nonexistent job is made'
|
|
|
|
|
);
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.equal(
|
|
|
|
|
currentURL(),
|
|
|
|
|
'/jobs/not-a-real-job/versions',
|
|
|
|
|
'The URL persists'
|
|
|
|
|
);
|
2018-11-05 23:42:04 +00:00
|
|
|
|
assert.ok(Versions.error.isPresent, 'Error message is shown');
|
|
|
|
|
assert.equal(Versions.error.title, 'Not Found', 'Error message is for 404');
|
|
|
|
|
});
|
|
|
|
|
});
|
2021-04-20 13:33:16 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
module('Acceptance | job versions (with client token)', function (hooks) {
|
2021-04-20 13:33:16 +00:00
|
|
|
|
setupApplicationTest(hooks);
|
|
|
|
|
setupMirage(hooks);
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
hooks.beforeEach(async function () {
|
2023-06-22 17:11:44 +00:00
|
|
|
|
server.create('node-pool');
|
2021-04-20 13:33:16 +00:00
|
|
|
|
job = server.create('job', { createAllocations: false });
|
|
|
|
|
versions = server.db.jobVersions.where({ jobId: job.id });
|
|
|
|
|
|
|
|
|
|
server.create('token');
|
|
|
|
|
const clientToken = server.create('token');
|
|
|
|
|
window.localStorage.nomadTokenSecret = clientToken.secretId;
|
|
|
|
|
|
|
|
|
|
await Versions.visit({ id: job.id });
|
|
|
|
|
});
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('reversion buttons are disabled when the token lacks permissions', async function (assert) {
|
2021-07-14 20:27:24 +00:00
|
|
|
|
const versionRowWithReversion = Versions.versions.filter(
|
2021-12-28 14:45:20 +00:00
|
|
|
|
(versionRow) => versionRow.revertToButton.isPresent
|
2021-07-14 20:27:24 +00:00
|
|
|
|
)[0];
|
2021-04-20 13:33:16 +00:00
|
|
|
|
|
|
|
|
|
if (versionRowWithReversion) {
|
|
|
|
|
assert.ok(versionRowWithReversion.revertToButtonIsDisabled);
|
|
|
|
|
} else {
|
|
|
|
|
assert.expect(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.localStorage.clear();
|
|
|
|
|
});
|
2021-07-14 20:27:24 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('reversion buttons are available when the client token has permissions', async function (assert) {
|
2021-07-14 20:27:24 +00:00
|
|
|
|
const REVERT_NAMESPACE = 'revert-namespace';
|
|
|
|
|
window.localStorage.clear();
|
|
|
|
|
const clientToken = server.create('token');
|
|
|
|
|
|
|
|
|
|
server.create('namespace', { id: REVERT_NAMESPACE });
|
|
|
|
|
|
|
|
|
|
const job = server.create('job', {
|
|
|
|
|
groupCount: 0,
|
|
|
|
|
createAllocations: false,
|
|
|
|
|
shallow: true,
|
|
|
|
|
noActiveDeployment: true,
|
|
|
|
|
namespaceId: REVERT_NAMESPACE,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const policy = server.create('policy', {
|
|
|
|
|
id: 'something',
|
|
|
|
|
name: 'something',
|
|
|
|
|
rulesJSON: {
|
|
|
|
|
Namespaces: [
|
|
|
|
|
{
|
|
|
|
|
Name: REVERT_NAMESPACE,
|
|
|
|
|
Capabilities: ['submit-job'],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
clientToken.policyIds = [policy.id];
|
|
|
|
|
clientToken.save();
|
|
|
|
|
|
|
|
|
|
window.localStorage.nomadTokenSecret = clientToken.secretId;
|
|
|
|
|
|
|
|
|
|
versions = server.db.jobVersions.where({ jobId: job.id });
|
|
|
|
|
await Versions.visit({ id: job.id, namespace: REVERT_NAMESPACE });
|
|
|
|
|
const versionRowWithReversion = Versions.versions.filter(
|
2021-12-28 14:45:20 +00:00
|
|
|
|
(versionRow) => versionRow.revertToButton.isPresent
|
2021-07-14 20:27:24 +00:00
|
|
|
|
)[0];
|
|
|
|
|
|
|
|
|
|
if (versionRowWithReversion) {
|
|
|
|
|
assert.ok(versionRowWithReversion.revertToButtonIsDisabled);
|
|
|
|
|
} else {
|
|
|
|
|
assert.expect(0);
|
|
|
|
|
}
|
|
|
|
|
});
|
2021-04-20 13:33:16 +00:00
|
|
|
|
});
|