mirror of
https://github.com/kemko/nomad.git
synced 2026-01-03 17:05:43 +03:00
This only needs to check that the token is sent, the rest of the assertions were covered by the previous test.
459 lines
14 KiB
JavaScript
459 lines
14 KiB
JavaScript
import { module, test } from 'qunit';
|
||
import { currentURL, settled } from '@ember/test-helpers';
|
||
import { setupApplicationTest } from 'ember-qunit';
|
||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||
import Service from '@ember/service';
|
||
import Exec from 'nomad-ui/tests/pages/exec';
|
||
|
||
module('Acceptance | exec', function(hooks) {
|
||
setupApplicationTest(hooks);
|
||
setupMirage(hooks);
|
||
|
||
hooks.beforeEach(async function() {
|
||
localStorage.clear();
|
||
sessionStorage.clear();
|
||
|
||
server.create('agent');
|
||
server.create('node');
|
||
|
||
this.job = server.create('job', {
|
||
groupsCount: 2,
|
||
groupTaskCount: 5,
|
||
createAllocations: false,
|
||
});
|
||
|
||
this.job.task_group_ids.forEach(taskGroupId => {
|
||
server.create('allocation', {
|
||
jobId: this.job.id,
|
||
taskGroup: server.db.taskGroups.find(taskGroupId).name,
|
||
forceRunningClientStatus: true,
|
||
});
|
||
});
|
||
});
|
||
|
||
test('/exec/:job should show the region, namespace, and job name', async function(assert) {
|
||
server.create('namespace');
|
||
let namespace = server.create('namespace');
|
||
|
||
server.create('region', { id: 'global' });
|
||
server.create('region', { id: 'region-2' });
|
||
|
||
this.job = server.create('job', { createAllocations: false, namespaceId: namespace.id });
|
||
|
||
await Exec.visitJob({ job: this.job.id, namespace: namespace.id, region: 'region-2' });
|
||
|
||
assert.equal(document.title, 'Exec - region-2 - Nomad');
|
||
|
||
assert.equal(Exec.header.region.text, this.job.region);
|
||
assert.equal(Exec.header.namespace.text, this.job.namespace);
|
||
assert.equal(Exec.header.job, this.job.name);
|
||
});
|
||
|
||
test('/exec/:job should not show region and namespace when there are none', async function(assert) {
|
||
await Exec.visitJob({ job: this.job.id });
|
||
|
||
assert.ok(Exec.header.region.isHidden);
|
||
assert.ok(Exec.header.namespace.isHidden);
|
||
});
|
||
|
||
test('/exec/:job should show the task groups collapsed by default and allow the tasks to be shown', async function(assert) {
|
||
await Exec.visitJob({ job: this.job.id });
|
||
|
||
assert.equal(Exec.taskGroups.length, this.job.task_groups.length);
|
||
|
||
assert.equal(Exec.taskGroups[0].name, this.job.task_groups.models[0].name);
|
||
assert.equal(Exec.taskGroups[0].tasks.length, 0);
|
||
assert.ok(Exec.taskGroups[0].chevron.isRight);
|
||
|
||
await Exec.taskGroups[0].click();
|
||
assert.equal(Exec.taskGroups[0].tasks.length, this.job.task_groups.models[0].tasks.length);
|
||
assert.notOk(Exec.taskGroups[0].tasks[0].isActive);
|
||
assert.ok(Exec.taskGroups[0].chevron.isDown);
|
||
|
||
await Exec.taskGroups[0].click();
|
||
assert.equal(Exec.taskGroups[0].tasks.length, 0);
|
||
});
|
||
|
||
test('/exec/:job should require selecting a task', async function(assert) {
|
||
await Exec.visitJob({ job: this.job.id });
|
||
|
||
assert.equal(
|
||
window.execTerminal.buffer
|
||
.getLine(0)
|
||
.translateToString()
|
||
.trim(),
|
||
'Select a task to start your session.'
|
||
);
|
||
});
|
||
|
||
test('a task group with no running task states should not be shown', async function(assert) {
|
||
let taskGroup = this.job.task_groups.models[0];
|
||
this.server.db.allocations.update({ taskGroup: taskGroup.name }, { clientStatus: 'pending' });
|
||
|
||
await Exec.visitJob({ job: this.job.id });
|
||
assert.notEqual(Exec.taskGroups[0].name, taskGroup.name);
|
||
});
|
||
|
||
test('an inactive task should not be shown', async function(assert) {
|
||
let notRunningTaskGroup = this.job.task_groups.models[0];
|
||
this.server.db.allocations.update(
|
||
{ taskGroup: notRunningTaskGroup.name },
|
||
{ clientStatus: 'pending' }
|
||
);
|
||
|
||
let runningTaskGroup = this.job.task_groups.models[1];
|
||
runningTaskGroup.tasks.models.forEach((task, index) => {
|
||
if (index > 0) {
|
||
this.server.db.taskStates.update({ name: task.name }, { finishedAt: new Date() });
|
||
}
|
||
});
|
||
|
||
await Exec.visitJob({ job: this.job.id });
|
||
await Exec.taskGroups[0].click();
|
||
|
||
assert.equal(Exec.taskGroups[0].tasks.length, 1);
|
||
});
|
||
|
||
test('visiting a path with a task group should open the group by default', async function(assert) {
|
||
let taskGroup = this.job.task_groups.models[0];
|
||
await Exec.visitTaskGroup({ job: this.job.id, task_group: taskGroup.name });
|
||
|
||
assert.equal(Exec.taskGroups[0].tasks.length, this.job.task_groups.models[0].tasks.length);
|
||
assert.ok(Exec.taskGroups[0].chevron.isDown);
|
||
|
||
let task = taskGroup.tasks.models[0];
|
||
await Exec.visitTask({ job: this.job.id, task_group: taskGroup.name, task_name: task.name });
|
||
|
||
assert.equal(Exec.taskGroups[0].tasks.length, this.job.task_groups.models[0].tasks.length);
|
||
assert.ok(Exec.taskGroups[0].chevron.isDown);
|
||
});
|
||
|
||
test('navigating to a task adds its name to the route, chooses an allocation, and assigns a default command', async function(assert) {
|
||
await Exec.visitJob({ job: this.job.id });
|
||
await Exec.taskGroups[0].click();
|
||
await Exec.taskGroups[0].tasks[0].click();
|
||
|
||
let taskGroup = this.job.task_groups.models[0];
|
||
let task = taskGroup.tasks.models[0];
|
||
|
||
let taskStates = this.server.db.taskStates.where({
|
||
name: task.name,
|
||
});
|
||
let allocationId = taskStates.find(ts => ts.allocationId).allocationId;
|
||
|
||
await settled();
|
||
|
||
assert.equal(currentURL(), `/exec/${this.job.id}/${taskGroup.name}/${task.name}`);
|
||
assert.ok(Exec.taskGroups[0].tasks[0].isActive);
|
||
|
||
assert.equal(
|
||
window.execTerminal.buffer
|
||
.getLine(2)
|
||
.translateToString()
|
||
.trim(),
|
||
'Multiple instances of this task are running. The allocation below was selected by random draw.'
|
||
);
|
||
|
||
assert.equal(
|
||
window.execTerminal.buffer
|
||
.getLine(4)
|
||
.translateToString()
|
||
.trim(),
|
||
'Customize your command, then hit ‘return’ to run.'
|
||
);
|
||
|
||
assert.equal(
|
||
window.execTerminal.buffer
|
||
.getLine(6)
|
||
.translateToString()
|
||
.trim(),
|
||
`$ nomad alloc exec -i -t -task ${task.name} ${allocationId.split('-')[0]} /bin/bash`
|
||
);
|
||
});
|
||
|
||
test('an allocation can be specified', async function(assert) {
|
||
let taskGroup = this.job.task_groups.models[0];
|
||
let task = taskGroup.tasks.models[0];
|
||
let allocations = this.server.db.allocations.where({
|
||
jobId: this.job.id,
|
||
taskGroup: taskGroup.name,
|
||
});
|
||
let allocation = allocations[allocations.length - 1];
|
||
|
||
this.server.db.taskStates.update({ name: task.name }, { name: 'spaced name!' });
|
||
|
||
task.name = 'spaced name!';
|
||
task.save();
|
||
|
||
await Exec.visitTask({
|
||
job: this.job.id,
|
||
task_group: taskGroup.name,
|
||
task_name: task.name,
|
||
allocation: allocation.id.split('-')[0],
|
||
});
|
||
|
||
await settled();
|
||
|
||
assert.equal(
|
||
window.execTerminal.buffer
|
||
.getLine(4)
|
||
.translateToString()
|
||
.trim(),
|
||
`$ nomad alloc exec -i -t -task spaced\\ name\\! ${allocation.id.split('-')[0]} /bin/bash`
|
||
);
|
||
});
|
||
|
||
test('running the command opens the socket for reading/writing and detects it closing', async function(assert) {
|
||
let mockSocket = new MockSocket();
|
||
let mockSockets = Service.extend({
|
||
getTaskStateSocket(taskState, command) {
|
||
assert.equal(taskState.name, task.name);
|
||
assert.equal(taskState.allocation.id, allocation.id);
|
||
|
||
assert.equal(command, '/bin/bash');
|
||
|
||
assert.step('Socket built');
|
||
|
||
return mockSocket;
|
||
},
|
||
});
|
||
|
||
this.owner.register('service:sockets', mockSockets);
|
||
|
||
let taskGroup = this.job.task_groups.models[0];
|
||
let task = taskGroup.tasks.models[0];
|
||
let allocations = this.server.db.allocations.where({
|
||
jobId: this.job.id,
|
||
taskGroup: taskGroup.name,
|
||
});
|
||
let allocation = allocations[allocations.length - 1];
|
||
|
||
await Exec.visitTask({
|
||
job: this.job.id,
|
||
task_group: taskGroup.name,
|
||
task_name: task.name,
|
||
allocation: allocation.id.split('-')[0],
|
||
});
|
||
|
||
await settled();
|
||
|
||
await Exec.terminal.pressEnter();
|
||
await settled();
|
||
mockSocket.onopen();
|
||
|
||
assert.verifySteps(['Socket built']);
|
||
|
||
mockSocket.onmessage({
|
||
data: '{"stdout":{"data":"c2gtMy4yIPCfpbMk"}}',
|
||
});
|
||
|
||
await settled();
|
||
|
||
assert.equal(
|
||
window.execTerminal.buffer
|
||
.getLine(5)
|
||
.translateToString()
|
||
.trim(),
|
||
'sh-3.2 🥳$'
|
||
);
|
||
|
||
await Exec.terminal.pressEnter();
|
||
await settled();
|
||
|
||
assert.deepEqual(mockSocket.sent, [
|
||
'{"version":1,"auth_token":""}',
|
||
`{"tty_size":{"width":${window.execTerminal.cols},"height":${window.execTerminal.rows}}}`,
|
||
'{"stdin":{"data":"DQ=="}}',
|
||
]);
|
||
|
||
await mockSocket.onclose();
|
||
await settled();
|
||
|
||
assert.equal(
|
||
window.execTerminal.buffer
|
||
.getLine(6)
|
||
.translateToString()
|
||
.trim(),
|
||
'The connection has closed.'
|
||
);
|
||
});
|
||
|
||
test('the opening message includes the token if it exists', async function(assert) {
|
||
const { secretId } = server.create('token');
|
||
window.localStorage.nomadTokenSecret = secretId;
|
||
|
||
let mockSocket = new MockSocket();
|
||
let mockSockets = Service.extend({
|
||
getTaskStateSocket(taskState, command) {
|
||
assert.equal(taskState.name, task.name);
|
||
assert.equal(taskState.allocation.id, allocation.id);
|
||
|
||
assert.equal(command, '/bin/bash');
|
||
|
||
assert.step('Socket built');
|
||
|
||
return mockSocket;
|
||
},
|
||
});
|
||
|
||
this.owner.register('service:sockets', mockSockets);
|
||
|
||
let taskGroup = this.job.task_groups.models[0];
|
||
let task = taskGroup.tasks.models[0];
|
||
let allocations = this.server.db.allocations.where({
|
||
jobId: this.job.id,
|
||
taskGroup: taskGroup.name,
|
||
});
|
||
let allocation = allocations[allocations.length - 1];
|
||
|
||
await Exec.visitTask({
|
||
job: this.job.id,
|
||
task_group: taskGroup.name,
|
||
task_name: task.name,
|
||
allocation: allocation.id.split('-')[0],
|
||
});
|
||
|
||
await settled();
|
||
|
||
await Exec.terminal.pressEnter();
|
||
await settled();
|
||
mockSocket.onopen();
|
||
|
||
assert.verifySteps(['Socket built']);
|
||
|
||
await Exec.terminal.pressEnter();
|
||
await settled();
|
||
|
||
assert.equal(mockSocket.sent[0], `{"version":1,"auth_token":"${secretId}"}`);
|
||
});
|
||
|
||
test('only one socket is opened after switching between tasks', async function(assert) {
|
||
let mockSockets = Service.extend({
|
||
getTaskStateSocket() {
|
||
assert.step('Socket built');
|
||
return new MockSocket();
|
||
},
|
||
});
|
||
|
||
this.owner.register('service:sockets', mockSockets);
|
||
|
||
await Exec.visitJob({
|
||
job: this.job.id,
|
||
});
|
||
|
||
await settled();
|
||
|
||
await Exec.taskGroups[0].click();
|
||
await Exec.taskGroups[0].tasks[0].click();
|
||
|
||
await Exec.taskGroups[1].click();
|
||
await Exec.taskGroups[1].tasks[0].click();
|
||
|
||
await Exec.terminal.pressEnter();
|
||
|
||
assert.verifySteps(['Socket built']);
|
||
});
|
||
|
||
test('the command can be customised', async function(assert) {
|
||
let mockSockets = Service.extend({
|
||
getTaskStateSocket(taskState, command) {
|
||
assert.equal(command, '/sh');
|
||
localStorage.getItem('nomadExecCommand', JSON.stringify('/sh'));
|
||
|
||
assert.step('Socket built');
|
||
|
||
return new MockSocket();
|
||
},
|
||
});
|
||
|
||
this.owner.register('service:sockets', mockSockets);
|
||
|
||
await Exec.visitJob({ job: this.job.id });
|
||
await Exec.taskGroups[0].click();
|
||
await Exec.taskGroups[0].tasks[0].click();
|
||
|
||
let taskGroup = this.job.task_groups.models[0];
|
||
let task = taskGroup.tasks.models[0];
|
||
let allocation = this.server.db.allocations.findBy({
|
||
jobId: this.job.id,
|
||
taskGroup: taskGroup.name,
|
||
});
|
||
|
||
await settled();
|
||
|
||
// Delete /bash
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
|
||
// Delete /bin and try to go beyond
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
await window.execTerminal.simulateCommandKeyEvent({ domEvent: { key: 'Backspace' } });
|
||
|
||
await settled();
|
||
|
||
assert.equal(
|
||
window.execTerminal.buffer
|
||
.getLine(6)
|
||
.translateToString()
|
||
.trim(),
|
||
`$ nomad alloc exec -i -t -task ${task.name} ${allocation.id.split('-')[0]}`
|
||
);
|
||
|
||
await window.execTerminal.simulateCommandKeyEvent({ key: '/', domEvent: {} });
|
||
await window.execTerminal.simulateCommandKeyEvent({ key: 's', domEvent: {} });
|
||
await window.execTerminal.simulateCommandKeyEvent({ key: 'h', domEvent: {} });
|
||
|
||
await Exec.terminal.pressEnter();
|
||
await settled();
|
||
|
||
assert.verifySteps(['Socket built']);
|
||
});
|
||
|
||
test('a persisted customised command is recalled', async function(assert) {
|
||
localStorage.setItem('nomadExecCommand', JSON.stringify('/bin/sh'));
|
||
|
||
let taskGroup = this.job.task_groups.models[0];
|
||
let task = taskGroup.tasks.models[0];
|
||
let allocations = this.server.db.allocations.where({
|
||
jobId: this.job.id,
|
||
taskGroup: taskGroup.name,
|
||
});
|
||
let allocation = allocations[allocations.length - 1];
|
||
|
||
await Exec.visitTask({
|
||
job: this.job.id,
|
||
task_group: taskGroup.name,
|
||
task_name: task.name,
|
||
allocation: allocation.id.split('-')[0],
|
||
});
|
||
|
||
await settled();
|
||
|
||
assert.equal(
|
||
window.execTerminal.buffer
|
||
.getLine(4)
|
||
.translateToString()
|
||
.trim(),
|
||
`$ nomad alloc exec -i -t -task ${task.name} ${allocation.id.split('-')[0]} /bin/sh`
|
||
);
|
||
});
|
||
});
|
||
|
||
class MockSocket {
|
||
constructor() {
|
||
this.sent = [];
|
||
}
|
||
|
||
send(message) {
|
||
this.sent.push(message);
|
||
}
|
||
}
|