},
event_type: 'stdout'
}).then(function(log) {
- cy.get('[data-cy=process-logs]')
+ cy.get('[data-cy=process-logs]', {timeout: 7000})
.should('not.contain', 'No logs yet')
.and('contain', 'hello world');
})
});
});
+ it('shows process details', function() {
+ createContainerRequest(
+ activeUser,
+ `test_container_request ${Math.floor(Math.random() * 999999)}`,
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .then(function(containerRequest) {
+ cy.loginAs(activeUser);
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.get('[data-cy=process-details]').should('contain', containerRequest.name);
+ cy.get('[data-cy=process-details-attributes-modifiedby-user]').contains(`Active User (${activeUser.user.uuid})`);
+ cy.get('[data-cy=process-details-attributes-runtime-user]').should('not.exist');
+ });
+
+ // Fake submitted by another user
+ cy.intercept({method: 'GET', url: '**/arvados/v1/container_requests/*'}, (req) => {
+ req.reply((res) => {
+ res.body.modified_by_user_uuid = 'zzzzz-tpzed-000000000000000';
+ });
+ });
+
+ createContainerRequest(
+ activeUser,
+ `test_container_request ${Math.floor(Math.random() * 999999)}`,
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .then(function(containerRequest) {
+ cy.loginAs(activeUser);
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.get('[data-cy=process-details]').should('contain', containerRequest.name);
+ cy.get('[data-cy=process-details-attributes-modifiedby-user]').contains(`zzzzz-tpzed-000000000000000`);
+ cy.get('[data-cy=process-details-attributes-runtime-user]').contains(`Active User (${activeUser.user.uuid})`);
+ });
+ });
+
it('filters process logs by event type', function() {
const nodeInfoLogs = [
'Host Information',
cy.getAll('@stdoutLogs', '@nodeInfoLogs', '@crunchRunLogs').then(function() {
cy.loginAs(activeUser);
cy.goToPath(`/processes/${containerRequest.uuid}`);
- // Should should all logs
- cy.get('[data-cy=process-logs-filter]').should('contain', 'All logs');
+ // Should show main logs by default
+ cy.get('[data-cy=process-logs-filter]', {timeout: 7000}).should('contain', 'Main logs');
+ cy.get('[data-cy=process-logs]')
+ .should('contain', stdoutLogs[Math.floor(Math.random() * stdoutLogs.length)])
+ .and('not.contain', nodeInfoLogs[Math.floor(Math.random() * nodeInfoLogs.length)])
+ .and('contain', crunchRunLogs[Math.floor(Math.random() * crunchRunLogs.length)]);
+ // Select 'All logs'
+ cy.get('[data-cy=process-logs-filter]').click();
+ cy.get('body').contains('li', 'All logs').click();
cy.get('[data-cy=process-logs]')
.should('contain', stdoutLogs[Math.floor(Math.random() * stdoutLogs.length)])
.and('contain', nodeInfoLogs[Math.floor(Math.random() * nodeInfoLogs.length)])
.should('contain', 'Free disk space is low')
.and('contain', 'No additional warning details available');
});
+
+
+ // Force container_count for testing
+ let containerCount = 2;
+ cy.intercept({method: 'GET', url: '**/arvados/v1/container_requests/*'}, (req) => {
+ req.reply((res) => {
+ res.body.container_count = containerCount;
+ });
+ });
+
+ cy.getAll('@containerRequest').then(function([containerRequest]) {
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.get('[data-cy=process-runtime-status-retry-warning]', {timeout: 7000})
+ .should('contain', 'Process retried 1 time');
+ });
+
+ cy.getAll('@containerRequest').then(function([containerRequest]) {
+ containerCount = 3;
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.get('[data-cy=process-runtime-status-retry-warning]', {timeout: 7000})
+ .should('contain', 'Process retried 2 times');
+ });
+ });
+
+
+ const testInputs = [
+ {
+ definition: {
+ "id": "#main/input_file",
+ "label": "Label Description",
+ "type": "File"
+ },
+ input: {
+ "input_file": {
+ "basename": "input1.tar",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+01/input1.tar",
+ "secondaryFiles": [
+ {
+ "basename": "input1-2.txt",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+01/input1-2.txt"
+ },
+ {
+ "basename": "input1-3.txt",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+01/input1-3.txt"
+ },
+ {
+ "basename": "input1-4.txt",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+01/input1-4.txt"
+ }
+ ]
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_dir",
+ "doc": "Doc Description",
+ "type": "Directory"
+ },
+ input: {
+ "input_dir": {
+ "basename": "11111111111111111111111111111111+01",
+ "class": "Directory",
+ "location": "keep:11111111111111111111111111111111+01"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_bool",
+ "doc": ["Doc desc 1", "Doc desc 2"],
+ "type": "boolean"
+ },
+ input: {
+ "input_bool": true,
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_int",
+ "type": "int"
+ },
+ input: {
+ "input_int": 1,
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_long",
+ "type": "long"
+ },
+ input: {
+ "input_long" : 1,
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_float",
+ "type": "float"
+ },
+ input: {
+ "input_float": 1.5,
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_double",
+ "type": "double"
+ },
+ input: {
+ "input_double": 1.3,
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_string",
+ "type": "string"
+ },
+ input: {
+ "input_string": "Hello World",
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_file_array",
+ "type": {
+ "items": "File",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_file_array": [
+ {
+ "basename": "input2.tar",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+02/input2.tar"
+ },
+ {
+ "basename": "input3.tar",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+03/input3.tar",
+ "secondaryFiles": [
+ {
+ "basename": "input3-2.txt",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+03/input3-2.txt"
+ }
+ ]
+ },
+ {
+ "$import": "import_path"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_dir_array",
+ "type": {
+ "items": "Directory",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_dir_array": [
+ {
+ "basename": "11111111111111111111111111111111+02",
+ "class": "Directory",
+ "location": "keep:11111111111111111111111111111111+02"
+ },
+ {
+ "basename": "11111111111111111111111111111111+03",
+ "class": "Directory",
+ "location": "keep:11111111111111111111111111111111+03"
+ },
+ {
+ "$import": "import_path"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_int_array",
+ "type": {
+ "items": "int",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_int_array": [
+ 1,
+ 3,
+ 5,
+ {
+ "$import": "import_path"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_long_array",
+ "type": {
+ "items": "long",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_long_array": [
+ 10,
+ 20,
+ {
+ "$import": "import_path"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_float_array",
+ "type": {
+ "items": "float",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_float_array": [
+ 10.2,
+ 10.4,
+ 10.6,
+ {
+ "$import": "import_path"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_double_array",
+ "type": {
+ "items": "double",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_double_array": [
+ 20.1,
+ 20.2,
+ 20.3,
+ {
+ "$import": "import_path"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_string_array",
+ "type": {
+ "items": "string",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_string_array": [
+ "Hello",
+ "World",
+ "!",
+ {
+ "$import": "import_path"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_bool_include",
+ "type": "boolean"
+ },
+ input: {
+ "input_bool_include": {
+ "$include": "include_path"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_int_include",
+ "type": "int"
+ },
+ input: {
+ "input_int_include": {
+ "$include": "include_path"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_float_include",
+ "type": "float"
+ },
+ input: {
+ "input_float_include": {
+ "$include": "include_path"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_string_include",
+ "type": "string"
+ },
+ input: {
+ "input_string_include": {
+ "$include": "include_path"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_file_include",
+ "type": "File"
+ },
+ input: {
+ "input_file_include": {
+ "$include": "include_path"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_directory_include",
+ "type": "Directory"
+ },
+ input: {
+ "input_directory_include": {
+ "$include": "include_path"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_file_url",
+ "type": "File"
+ },
+ input: {
+ "input_file_url": {
+ "basename": "index.html",
+ "class": "File",
+ "location": "http://example.com/index.html"
+ }
+ }
+ }
+ ];
+
+ const testOutputs = [
+ {
+ definition: {
+ "id": "#main/output_file",
+ "label": "Label Description",
+ "type": "File"
+ },
+ output: {
+ "output_file": {
+ "basename": "cat.png",
+ "class": "File",
+ "location": "cat.png"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_file_with_secondary",
+ "doc": "Doc Description",
+ "type": "File"
+ },
+ output: {
+ "output_file_with_secondary": {
+ "basename": "main.dat",
+ "class": "File",
+ "location": "main.dat",
+ "secondaryFiles": [
+ {
+ "basename": "secondary.dat",
+ "class": "File",
+ "location": "secondary.dat"
+ },
+ {
+ "basename": "secondary2.dat",
+ "class": "File",
+ "location": "secondary2.dat"
+ }
+ ]
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_dir",
+ "doc": ["Doc desc 1", "Doc desc 2"],
+ "type": "Directory"
+ },
+ output: {
+ "output_dir": {
+ "basename": "outdir1",
+ "class": "Directory",
+ "location": "outdir1"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_bool",
+ "type": "boolean"
+ },
+ output: {
+ "output_bool": true
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_int",
+ "type": "int"
+ },
+ output: {
+ "output_int": 1
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_long",
+ "type": "long"
+ },
+ output: {
+ "output_long": 1
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_float",
+ "type": "float"
+ },
+ output: {
+ "output_float": 100.5
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_double",
+ "type": "double"
+ },
+ output: {
+ "output_double": 100.3
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_string",
+ "type": "string"
+ },
+ output: {
+ "output_string": "Hello output"
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_file_array",
+ "type": {
+ "items": "File",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_file_array": [
+ {
+ "basename": "output2.tar",
+ "class": "File",
+ "location": "output2.tar"
+ },
+ {
+ "basename": "output3.tar",
+ "class": "File",
+ "location": "output3.tar"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_dir_array",
+ "type": {
+ "items": "Directory",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_dir_array": [
+ {
+ "basename": "outdir2",
+ "class": "Directory",
+ "location": "outdir2"
+ },
+ {
+ "basename": "outdir3",
+ "class": "Directory",
+ "location": "outdir3"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_int_array",
+ "type": {
+ "items": "int",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_int_array": [
+ 10,
+ 11,
+ 12
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_long_array",
+ "type": {
+ "items": "long",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_long_array": [
+ 51,
+ 52
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_float_array",
+ "type": {
+ "items": "float",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_float_array": [
+ 100.2,
+ 100.4,
+ 100.6
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_double_array",
+ "type": {
+ "items": "double",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_double_array": [
+ 100.1,
+ 100.2,
+ 100.3
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_string_array",
+ "type": {
+ "items": "string",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_string_array": [
+ "Hello",
+ "Output",
+ "!"
+ ]
+ }
+ }
+ ];
+
+ const verifyIOParameter = (name, label, doc, val, collection, multipleRows) => {
+ cy.get('table tr').contains(name).parents('tr').within(($mainRow) => {
+ label && cy.contains(label);
+
+ if (multipleRows) {
+ cy.get($mainRow).nextUntil('[data-cy="process-io-param"]').as('secondaryRows');
+ if (val) {
+ if (Array.isArray(val)) {
+ val.forEach(v => cy.get('@secondaryRows').contains(v));
+ } else {
+ cy.get('@secondaryRows').contains(val);
+ }
+ }
+ if (collection) {
+ cy.get('@secondaryRows').contains(collection);
+ }
+ } else {
+ if (val) {
+ if (Array.isArray(val)) {
+ val.forEach(v => cy.contains(v));
+ } else {
+ cy.contains(val);
+ }
+ }
+ if (collection) {
+ cy.contains(collection);
+ }
+ }
+
+
+ });
+ };
+
+ const verifyIOParameterImage = (name, url) => {
+ cy.get('table tr').contains(name).parents('tr').within(() => {
+ cy.get('[alt="Inline Preview"]')
+ .should('be.visible')
+ .and(($img) => {
+ expect($img[0].naturalWidth).to.be.greaterThan(0);
+ expect($img[0].src).contains(url);
+ })
+ });
+ };
+
+ it('displays IO parameters with keep links and previews', function() {
+ // Create output collection for real files
+ cy.createCollection(adminUser.token, {
+ name: `Test collection ${Math.floor(Math.random() * 999999)}`,
+ owner_uuid: activeUser.user.uuid,
+ }).then((testOutputCollection) => {
+ cy.loginAs(activeUser);
+
+ cy.goToPath(`/collections/${testOutputCollection.uuid}`);
+
+ cy.get('[data-cy=upload-button]').click();
+
+ cy.fixture('files/cat.png', 'base64').then(content => {
+ cy.get('[data-cy=drag-and-drop]').upload(content, 'cat.png');
+ cy.get('[data-cy=form-submit-btn]').click();
+ cy.waitForDom().get('[data-cy=form-submit-btn]').should('not.exist');
+ // Confirm final collection state.
+ cy.get('[data-cy=collection-files-panel]')
+ .contains('cat.png').should('exist');
+ });
+
+ cy.getCollection(activeUser.token, testOutputCollection.uuid).as('testOutputCollection');
+ });
+
+ // Get updated collection pdh
+ cy.getAll('@testOutputCollection').then(([testOutputCollection]) => {
+ // Add output uuid and inputs to container request
+ cy.intercept({method: 'GET', url: '**/arvados/v1/container_requests/*'}, (req) => {
+ req.reply((res) => {
+ res.body.output_uuid = testOutputCollection.uuid;
+ res.body.mounts["/var/lib/cwl/cwl.input.json"] = {
+ content: testInputs.map((param) => (param.input)).reduce((acc, val) => (Object.assign(acc, val)), {})
+ };
+ res.body.mounts["/var/lib/cwl/workflow.json"] = {
+ content: {
+ $graph: [{
+ id: "#main",
+ inputs: testInputs.map((input) => (input.definition)),
+ outputs: testOutputs.map((output) => (output.definition))
+ }]
+ }
+ };
+ });
+ });
+
+ // Stub fake output collection
+ cy.intercept({method: 'GET', url: `**/arvados/v1/collections/${testOutputCollection.uuid}*`}, {
+ statusCode: 200,
+ body: {
+ uuid: testOutputCollection.uuid,
+ portable_data_hash: testOutputCollection.portable_data_hash,
+ }
+ });
+
+ // Stub fake output json
+ cy.intercept({method: 'GET', url: '**/c%3Dzzzzz-4zz18-zzzzzzzzzzzzzzz/cwl.output.json'}, {
+ statusCode: 200,
+ body: testOutputs.map((param) => (param.output)).reduce((acc, val) => (Object.assign(acc, val)), {})
+ });
+
+ // Stub webdav response, points to output json
+ cy.intercept({method: 'PROPFIND', url: '*'}, {
+ fixture: 'webdav-propfind-outputs.xml',
+ });
+ });
+
+ createContainerRequest(
+ activeUser,
+ 'test_container_request',
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .as('containerRequest');
+
+ cy.getAll('@containerRequest', '@testOutputCollection').then(function([containerRequest, testOutputCollection]) {
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.get('[data-cy=process-io-card] h6').contains('Inputs')
+ .parents('[data-cy=process-io-card]').within(() => {
+ verifyIOParameter('input_file', null, "Label Description", 'input1.tar', '00000000000000000000000000000000+01');
+ verifyIOParameter('input_file', null, "Label Description", 'input1-2.txt', undefined, true);
+ verifyIOParameter('input_file', null, "Label Description", 'input1-3.txt', undefined, true);
+ verifyIOParameter('input_file', null, "Label Description", 'input1-4.txt', undefined, true);
+ verifyIOParameter('input_dir', null, "Doc Description", '/', '11111111111111111111111111111111+01');
+ verifyIOParameter('input_bool', null, "Doc desc 1, Doc desc 2", 'true');
+ verifyIOParameter('input_int', null, null, '1');
+ verifyIOParameter('input_long', null, null, '1');
+ verifyIOParameter('input_float', null, null, '1.5');
+ verifyIOParameter('input_double', null, null, '1.3');
+ verifyIOParameter('input_string', null, null, 'Hello World');
+ verifyIOParameter('input_file_array', null, null, 'input2.tar', '00000000000000000000000000000000+02');
+ verifyIOParameter('input_file_array', null, null, 'input3.tar', undefined, true);
+ verifyIOParameter('input_file_array', null, null, 'input3-2.txt', undefined, true);
+ verifyIOParameter('input_file_array', null, null, 'Cannot display value', undefined, true);
+ verifyIOParameter('input_dir_array', null, null, '/', '11111111111111111111111111111111+02');
+ verifyIOParameter('input_dir_array', null, null, '/', '11111111111111111111111111111111+03', true);
+ verifyIOParameter('input_dir_array', null, null, 'Cannot display value', undefined, true);
+ verifyIOParameter('input_int_array', null, null, ["1", "3", "5", "Cannot display value"]);
+ verifyIOParameter('input_long_array', null, null, ["10", "20", "Cannot display value"]);
+ verifyIOParameter('input_float_array', null, null, ["10.2", "10.4", "10.6", "Cannot display value"]);
+ verifyIOParameter('input_double_array', null, null, ["20.1", "20.2", "20.3", "Cannot display value"]);
+ verifyIOParameter('input_string_array', null, null, ["Hello", "World", "!", "Cannot display value"]);
+ verifyIOParameter('input_bool_include', null, null, "Cannot display value");
+ verifyIOParameter('input_int_include', null, null, "Cannot display value");
+ verifyIOParameter('input_float_include', null, null, "Cannot display value");
+ verifyIOParameter('input_string_include', null, null, "Cannot display value");
+ verifyIOParameter('input_file_include', null, null, "Cannot display value");
+ verifyIOParameter('input_directory_include', null, null, "Cannot display value");
+ verifyIOParameter('input_file_url', null, null, "http://example.com/index.html");
+ });
+ cy.get('[data-cy=process-io-card] h6').contains('Outputs')
+ .parents('[data-cy=process-io-card]').within((ctx) => {
+ cy.get(ctx).scrollIntoView();
+ cy.get('[data-cy="io-preview-image-toggle"]').click();
+ const outPdh = testOutputCollection.portable_data_hash;
+
+ verifyIOParameter('output_file', null, "Label Description", 'cat.png', `${outPdh}`);
+ verifyIOParameterImage('output_file', `/c=${outPdh}/cat.png`);
+ verifyIOParameter('output_file_with_secondary', null, "Doc Description", 'main.dat', `${outPdh}`);
+ verifyIOParameter('output_file_with_secondary', null, "Doc Description", 'secondary.dat', undefined, true);
+ verifyIOParameter('output_file_with_secondary', null, "Doc Description", 'secondary2.dat', undefined, true);
+ verifyIOParameter('output_dir', null, "Doc desc 1, Doc desc 2", 'outdir1', `${outPdh}`);
+ verifyIOParameter('output_bool', null, null, 'true');
+ verifyIOParameter('output_int', null, null, '1');
+ verifyIOParameter('output_long', null, null, '1');
+ verifyIOParameter('output_float', null, null, '100.5');
+ verifyIOParameter('output_double', null, null, '100.3');
+ verifyIOParameter('output_string', null, null, 'Hello output');
+ verifyIOParameter('output_file_array', null, null, 'output2.tar', `${outPdh}`);
+ verifyIOParameter('output_file_array', null, null, 'output3.tar', undefined, true);
+ verifyIOParameter('output_dir_array', null, null, 'outdir2', `${outPdh}`);
+ verifyIOParameter('output_dir_array', null, null, 'outdir3', undefined, true);
+ verifyIOParameter('output_int_array', null, null, ["10", "11", "12"]);
+ verifyIOParameter('output_long_array', null, null, ["51", "52"]);
+ verifyIOParameter('output_float_array', null, null, ["100.2", "100.4", "100.6"]);
+ verifyIOParameter('output_double_array', null, null, ["100.1", "100.2", "100.3"]);
+ verifyIOParameter('output_string_array', null, null, ["Hello", "Output", "!"]);
+ });
+ });
});
+
+ it('displays IO parameters with no value', function() {
+
+ const fakeOutputUUID = 'zzzzz-4zz18-abcdefghijklmno';
+ const fakeOutputPDH = '11111111111111111111111111111111+99/';
+
+ cy.loginAs(activeUser);
+
+ // Add output uuid and inputs to container request
+ cy.intercept({method: 'GET', url: '**/arvados/v1/container_requests/*'}, (req) => {
+ req.reply((res) => {
+ res.body.output_uuid = fakeOutputUUID;
+ res.body.mounts["/var/lib/cwl/cwl.input.json"] = {
+ content: {}
+ };
+ res.body.mounts["/var/lib/cwl/workflow.json"] = {
+ content: {
+ $graph: [{
+ id: "#main",
+ inputs: testInputs.map((input) => (input.definition)),
+ outputs: testOutputs.map((output) => (output.definition))
+ }]
+ }
+ };
+ });
+ });
+
+ // Stub fake output collection
+ cy.intercept({method: 'GET', url: `**/arvados/v1/collections/${fakeOutputUUID}*`}, {
+ statusCode: 200,
+ body: {
+ uuid: fakeOutputUUID,
+ portable_data_hash: fakeOutputPDH,
+ }
+ });
+
+ // Stub fake output json
+ cy.intercept({method: 'GET', url: `**/c%3D${fakeOutputUUID}/cwl.output.json`}, {
+ statusCode: 200,
+ body: {}
+ });
+
+ cy.readFile('cypress/fixtures/webdav-propfind-outputs.xml').then((data) => {
+ // Stub webdav response, points to output json
+ cy.intercept({method: 'PROPFIND', url: '*'}, {
+ statusCode: 200,
+ body: data.replace(/zzzzz-4zz18-zzzzzzzzzzzzzzz/g, fakeOutputUUID)
+ });
+ });
+
+ createContainerRequest(
+ activeUser,
+ 'test_container_request',
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .as('containerRequest');
+
+ cy.getAll('@containerRequest').then(function([containerRequest]) {
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.get('[data-cy=process-io-card] h6').contains('Inputs')
+ .parents('[data-cy=process-io-card]').within(() => {
+ cy.wait(2000);
+ cy.waitForDom();
+ cy.get('tbody tr').each((item) => {
+ cy.wrap(item).contains('No value');
+ });
+ });
+ cy.get('[data-cy=process-io-card] h6').contains('Outputs')
+ .parents('[data-cy=process-io-card]').within(() => {
+ cy.get('tbody tr').each((item) => {
+ cy.wrap(item).contains('No value');
+ });
+ });
+ });
+ });
+
+
+ it('allows copying processes', function() {
+ const crName = 'first_container_request';
+ const copiedCrName = 'copied_container_request';
+ createContainerRequest(
+ activeUser,
+ crName,
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .then(function(containerRequest) {
+ cy.loginAs(activeUser);
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.get('[data-cy=process-details]').should('contain', crName);
+
+ cy.get('[data-cy=process-details]').find('button[title="More options"]').click();
+ cy.get('ul[data-cy=context-menu]').contains("Copy and re-run process").click();
+ });
+
+ cy.get('[data-cy=form-dialog]').within(() => {
+ cy.get('input[name=name]').clear().type(copiedCrName);
+ cy.get('[data-cy=projects-tree-home-tree-picker]').click();
+ cy.get('[data-cy=form-submit-btn]').click();
+ });
+
+ cy.get('[data-cy=process-details]').should('contain', copiedCrName);
+ cy.get('[data-cy=process-details]').find('button').contains('Run');
+ });
+
+ const getFakeContainer = (fakeContainerUuid) => ({
+ href: `/containers/${fakeContainerUuid}`,
+ kind: "arvados#container",
+ etag: "ecfosljpnxfari9a8m7e4yv06",
+ uuid: fakeContainerUuid,
+ owner_uuid: "zzzzz-tpzed-000000000000000",
+ created_at: "2023-02-13T15:55:47.308915000Z",
+ modified_by_client_uuid: "zzzzz-ozdt8-q6dzdi1lcc03155",
+ modified_by_user_uuid: "zzzzz-tpzed-000000000000000",
+ modified_at: "2023-02-15T19:12:45.987086000Z",
+ command: [
+ "arvados-cwl-runner",
+ "--api=containers",
+ "--local",
+ "--project-uuid=zzzzz-j7d0g-yr18k784zplfeza",
+ "/var/lib/cwl/workflow.json#main",
+ "/var/lib/cwl/cwl.input.json",
+ ],
+ container_image: "4ad7d11381df349e464694762db14e04+303",
+ cwd: "/var/spool/cwl",
+ environment: {},
+ exit_code: null,
+ finished_at: null,
+ locked_by_uuid: null,
+ log: null,
+ output: null,
+ output_path: "/var/spool/cwl",
+ progress: null,
+ runtime_constraints: {
+ API: true,
+ cuda: {
+ device_count: 0,
+ driver_version: "",
+ hardware_capability: "",
+ },
+ keep_cache_disk: 2147483648,
+ keep_cache_ram: 0,
+ ram: 1342177280,
+ vcpus: 1,
+ },
+ runtime_status: {},
+ started_at: null,
+ auth_uuid: null,
+ scheduling_parameters: {
+ max_run_time: 0,
+ partitions: [],
+ preemptible: false,
+ },
+ runtime_user_uuid: "zzzzz-tpzed-vllbpebicy84rd5",
+ runtime_auth_scopes: ["all"],
+ lock_count: 2,
+ gateway_address: null,
+ interactive_session_started: false,
+ output_storage_classes: ["default"],
+ output_properties: {},
+ cost: 0.0,
+ subrequests_cost: 0.0,
+ });
+
+ it('shows cancel button when appropriate', function() {
+ // Ignore collection requests
+ cy.intercept({method: 'GET', url: `**/arvados/v1/collections/*`}, {
+ statusCode: 200,
+ body: {}
+ });
+
+ // Uncommitted container
+ const crUncommitted = `Test process ${Math.floor(Math.random() * 999999)}`;
+ createContainerRequest(
+ activeUser,
+ crUncommitted,
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Uncommitted')
+ .then(function(containerRequest) {
+ // Navigate to process and verify run / cancel button
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.waitForDom();
+ cy.get('[data-cy=process-details]').should('contain', crUncommitted);
+ cy.get('[data-cy=process-run-button]').should('exist');
+ cy.get('[data-cy=process-cancel-button]').should('not.exist');
+ });
+
+ // Queued container
+ const crQueued = `Test process ${Math.floor(Math.random() * 999999)}`;
+ const fakeCrUuid = 'zzzzz-dz642-000000000000001';
+ createContainerRequest(
+ activeUser,
+ crQueued,
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .then(function(containerRequest) {
+ // Fake container uuid
+ cy.intercept({method: 'GET', url: `**/arvados/v1/container_requests/${containerRequest.uuid}`}, (req) => {
+ req.reply((res) => {
+ res.body.output_uuid = fakeCrUuid;
+ res.body.priority = 500;
+ res.body.state = "Committed";
+ });
+ });
+
+ // Fake container
+ const container = getFakeContainer(fakeCrUuid);
+ cy.intercept({method: 'GET', url: `**/arvados/v1/container/${fakeCrUuid}`}, {
+ statusCode: 200,
+ body: {...container, state: "Queued", priority: 500}
+ });
+
+ // Navigate to process and verify cancel button
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.waitForDom();
+ cy.get('[data-cy=process-details]').should('contain', crQueued);
+ cy.get('[data-cy=process-cancel-button]').contains('Cancel');
+ });
+
+ // Locked container
+ const crLocked = `Test process ${Math.floor(Math.random() * 999999)}`;
+ const fakeCrLockedUuid = 'zzzzz-dz642-000000000000002';
+ createContainerRequest(
+ activeUser,
+ crLocked,
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .then(function(containerRequest) {
+ // Fake container uuid
+ cy.intercept({method: 'GET', url: `**/arvados/v1/container_requests/${containerRequest.uuid}`}, (req) => {
+ req.reply((res) => {
+ res.body.output_uuid = fakeCrLockedUuid;
+ res.body.priority = 500;
+ res.body.state = "Committed";
+ });
+ });
+
+ // Fake container
+ const container = getFakeContainer(fakeCrLockedUuid);
+ cy.intercept({method: 'GET', url: `**/arvados/v1/container/${fakeCrLockedUuid}`}, {
+ statusCode: 200,
+ body: {...container, state: "Locked", priority: 500}
+ });
+
+ // Navigate to process and verify cancel button
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.waitForDom();
+ cy.get('[data-cy=process-details]').should('contain', crLocked);
+ cy.get('[data-cy=process-cancel-button]').contains('Cancel');
+ });
+
+ // On Hold container
+ const crOnHold = `Test process ${Math.floor(Math.random() * 999999)}`;
+ const fakeCrOnHoldUuid = 'zzzzz-dz642-000000000000003';
+ createContainerRequest(
+ activeUser,
+ crOnHold,
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .then(function(containerRequest) {
+ // Fake container uuid
+ cy.intercept({method: 'GET', url: `**/arvados/v1/container_requests/${containerRequest.uuid}`}, (req) => {
+ req.reply((res) => {
+ res.body.output_uuid = fakeCrOnHoldUuid;
+ res.body.priority = 0;
+ res.body.state = "Committed";
+ });
+ });
+
+ // Fake container
+ const container = getFakeContainer(fakeCrOnHoldUuid);
+ cy.intercept({method: 'GET', url: `**/arvados/v1/container/${fakeCrOnHoldUuid}`}, {
+ statusCode: 200,
+ body: {...container, state: "Queued", priority: 0}
+ });
+
+ // Navigate to process and verify cancel button
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.waitForDom();
+ cy.get('[data-cy=process-details]').should('contain', crOnHold);
+ cy.get('[data-cy=process-run-button]').should('exist');
+ cy.get('[data-cy=process-cancel-button]').should('not.exist');
+ });
+ });
+
});