+ .should('contain', 'No logs yet')
+ .and('not.contain', 'hello world');
+
+ // Append a log line
+ cy.appendLog(adminUser.token, containerRequest.uuid, "stdout.txt", [
+ "2023-07-18T20:14:48.128642814Z hello world"
+ ]).then(() => {
+ cy.get('[data-cy=process-logs]', {timeout: 7000})
+ .should('not.contain', 'No logs yet')
+ .and('contain', 'hello world');
+ });
+
+ // Append new log line to different file
+ cy.appendLog(adminUser.token, containerRequest.uuid, "stderr.txt", [
+ "2023-07-18T20:14:49.128642814Z hello new line"
+ ]).then(() => {
+ cy.get('[data-cy=process-logs]', {timeout: 7000})
+ .should('not.contain', 'No logs yet')
+ .and('contain', 'hello new line');
+ });
+ });
+ });
+
+ it('filters process logs by event type', function() {
+ const nodeInfoLogs = [
+ 'Host Information',
+ 'Linux compute-99cb150b26149780de44b929577e1aed-19rgca8vobuvc4p 5.4.0-1059-azure #62~18.04.1-Ubuntu SMP Tue Sep 14 17:53:18 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux',
+ 'CPU Information',
+ 'processor : 0',
+ 'vendor_id : GenuineIntel',
+ 'cpu family : 6',
+ 'model : 79',
+ 'model name : Intel(R) Xeon(R) CPU E5-2673 v4 @ 2.30GHz'
+ ];
+ const crunchRunLogs = [
+ '2022-03-22T13:56:22.542417997Z using local keepstore process (pid 3733) at http://localhost:46837, writing logs to keepstore.txt in log collection',
+ '2022-03-22T13:56:26.237571754Z crunch-run 2.4.0~dev20220321141729 (go1.17.1) started',
+ '2022-03-22T13:56:26.244704134Z crunch-run process has uid=0(root) gid=0(root) groups=0(root)',
+ '2022-03-22T13:56:26.244862836Z Executing container \'zzzzz-dz642-1wokwvcct9s9du3\' using docker runtime',
+ '2022-03-22T13:56:26.245037738Z Executing on host \'compute-99cb150b26149780de44b929577e1aed-19rgca8vobuvc4p\'',
+ ];
+ const stdoutLogs = [
+ '2022-03-22T13:56:22.542417987Z Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec dui nisi, hendrerit porta sapien a, pretium dignissim purus.',
+ '2022-03-22T13:56:22.542417997Z Integer viverra, mauris finibus aliquet ultricies, dui mauris cursus justo, ut venenatis nibh ex eget neque.',
+ '2022-03-22T13:56:22.542418007Z In hac habitasse platea dictumst.',
+ '2022-03-22T13:56:22.542418027Z Fusce fringilla turpis id accumsan faucibus. Donec congue congue ex non posuere. In semper mi quis tristique rhoncus.',
+ '2022-03-22T13:56:22.542418037Z Interdum et malesuada fames ac ante ipsum primis in faucibus.',
+ '2022-03-22T13:56:22.542418047Z Quisque fermentum tortor ex, ut suscipit velit feugiat faucibus.',
+ '2022-03-22T13:56:22.542418057Z Donec vitae porta risus, at luctus nulla. Mauris gravida iaculis ipsum, id sagittis tortor egestas ac.',
+ '2022-03-22T13:56:22.542418067Z Maecenas condimentum volutpat nulla. Integer lacinia maximus risus eu posuere.',
+ '2022-03-22T13:56:22.542418077Z Donec vitae leo id augue gravida bibendum.',
+ '2022-03-22T13:56:22.542418087Z Nam libero libero, pretium ac faucibus elementum, mattis nec ex.',
+ '2022-03-22T13:56:22.542418097Z Nullam id laoreet nibh. Vivamus tellus metus, pretium quis justo ut, bibendum varius metus. Pellentesque vitae accumsan lorem, quis tincidunt augue.',
+ '2022-03-22T13:56:22.542418107Z Aliquam viverra nisi nulla, et efficitur dolor mattis in.',
+ '2022-03-22T13:56:22.542418117Z Sed at enim sit amet nulla tincidunt mattis. Aenean eget aliquet ex, non ultrices ex. Nulla ex tortor, vestibulum aliquam tempor ac, aliquam vel est.',
+ '2022-03-22T13:56:22.542418127Z Fusce auctor faucibus libero id venenatis. Etiam sodales, odio eu cursus efficitur, quam sem blandit ex, quis porttitor enim dui quis lectus. In id tincidunt felis.',
+ '2022-03-22T13:56:22.542418137Z Phasellus non ex quis arcu tempus faucibus molestie in sapien.',
+ '2022-03-22T13:56:22.542418147Z Duis tristique semper dolor, vitae pulvinar risus.',
+ '2022-03-22T13:56:22.542418157Z Aliquam tortor elit, luctus nec tortor eget, porta tristique nulla.',
+ '2022-03-22T13:56:22.542418167Z Nulla eget mollis ipsum.',
+ ];
+
+ createContainerRequest(
+ activeUser,
+ 'test_container_request',
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .then(function(containerRequest) {
+ cy.appendLog(adminUser.token, containerRequest.uuid, "node-info.txt", nodeInfoLogs).as('nodeInfoLogs');
+ cy.appendLog(adminUser.token, containerRequest.uuid, "crunch-run.txt", crunchRunLogs).as('crunchRunLogs');
+ cy.appendLog(adminUser.token, containerRequest.uuid, "stdout.txt", stdoutLogs).as('stdoutLogs');
+
+ cy.getAll('@stdoutLogs', '@nodeInfoLogs', '@crunchRunLogs').then(function() {
+ cy.loginAs(activeUser);
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ // 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)])
+ .and('contain', crunchRunLogs[Math.floor(Math.random() * crunchRunLogs.length)]);
+ // Select 'node-info' logs
+ cy.get('[data-cy=process-logs-filter]').click();
+ cy.get('body').contains('li', 'node-info').click();
+ cy.get('[data-cy=process-logs]')
+ .should('not.contain', stdoutLogs[Math.floor(Math.random() * stdoutLogs.length)])
+ .and('contain', nodeInfoLogs[Math.floor(Math.random() * nodeInfoLogs.length)])
+ .and('not.contain', crunchRunLogs[Math.floor(Math.random() * crunchRunLogs.length)]);
+ // Select 'stdout' logs
+ cy.get('[data-cy=process-logs-filter]').click();
+ cy.get('body').contains('li', 'stdout').click();
+ 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('not.contain', crunchRunLogs[Math.floor(Math.random() * crunchRunLogs.length)]);
+ });
+ });
+ });
+
+ it('sorts combined logs', function() {
+ const crName = 'test_container_request';
+ createContainerRequest(
+ activeUser,
+ crName,
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .then(function(containerRequest) {
+ cy.appendLog(adminUser.token, containerRequest.uuid, "node-info.txt", [
+ "3: nodeinfo 1",
+ "2: nodeinfo 2",
+ "1: nodeinfo 3",
+ "2: nodeinfo 4",
+ "3: nodeinfo 5",
+ ]).as('node-info');
+
+ cy.appendLog(adminUser.token, containerRequest.uuid, "stdout.txt", [
+ "2023-07-18T20:14:48.128642814Z first",
+ "2023-07-18T20:14:49.128642814Z third"
+ ]).as('stdout');
+
+ cy.appendLog(adminUser.token, containerRequest.uuid, "stderr.txt", [
+ "2023-07-18T20:14:48.528642814Z second"
+ ]).as('stderr');
+
+ cy.loginAs(activeUser);
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.get('[data-cy=process-details]').should('contain', crName);
+ cy.get('[data-cy=process-logs]')
+ .should('contain', 'No logs yet');
+
+ cy.getAll('@node-info', '@stdout', '@stderr').then(() => {
+ // Verify sorted main logs
+ cy.get('[data-cy=process-logs] pre', {timeout: 7000})
+ .eq(0).should('contain', '2023-07-18T20:14:48.128642814Z first');
+ cy.get('[data-cy=process-logs] pre')
+ .eq(1).should('contain', '2023-07-18T20:14:48.528642814Z second');
+ cy.get('[data-cy=process-logs] pre')
+ .eq(2).should('contain', '2023-07-18T20:14:49.128642814Z third');
+
+ // Switch to All logs
+ cy.get('[data-cy=process-logs-filter]').click();
+ cy.get('body').contains('li', 'All logs').click();
+ // Verify non-sorted lines were preserved
+ cy.get('[data-cy=process-logs] pre')
+ .eq(0).should('contain', '3: nodeinfo 1');
+ cy.get('[data-cy=process-logs] pre')
+ .eq(1).should('contain', '2: nodeinfo 2');
+ cy.get('[data-cy=process-logs] pre')
+ .eq(2).should('contain', '1: nodeinfo 3');
+ cy.get('[data-cy=process-logs] pre')
+ .eq(3).should('contain', '2: nodeinfo 4');
+ cy.get('[data-cy=process-logs] pre')
+ .eq(4).should('contain', '3: nodeinfo 5');
+ // Verify sorted logs
+ cy.get('[data-cy=process-logs] pre')
+ .eq(5).should('contain', '2023-07-18T20:14:48.128642814Z first');
+ cy.get('[data-cy=process-logs] pre')
+ .eq(6).should('contain', '2023-07-18T20:14:48.528642814Z second');
+ cy.get('[data-cy=process-logs] pre')
+ .eq(7).should('contain', '2023-07-18T20:14:49.128642814Z third');
+ });
+ });
+ });
+
+ it('correctly generates sniplines', function() {
+ const SNIPLINE = `================ ✀ ================ ✀ ========= Some log(s) were skipped ========= ✀ ================ ✀ ================`;
+ const crName = 'test_container_request';
+ createContainerRequest(
+ activeUser,
+ crName,
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .then(function(containerRequest) {
+
+ cy.appendLog(adminUser.token, containerRequest.uuid, "stdout.txt", [
+ 'X'.repeat(63999) + '_' +
+ 'O'.repeat(100) +
+ '_' + 'X'.repeat(63999)
+ ]).as('stdout');
+
+ cy.loginAs(activeUser);
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.get('[data-cy=process-details]').should('contain', crName);