diff --git a/.github/workflows/assistant-release-e2e-workflow.yml b/.github/workflows/assistant-release-e2e-workflow.yml index 952fd4cdd..d17d60889 100644 --- a/.github/workflows/assistant-release-e2e-workflow.yml +++ b/.github/workflows/assistant-release-e2e-workflow.yml @@ -15,11 +15,21 @@ jobs: tests: - 'cypress/**/dashboards-assistant/**' - tests: + tests-with-security: needs: changes if: ${{ needs.changes.outputs.tests == 'true' }} uses: ./.github/workflows/release-e2e-workflow-template.yml with: test-name: dashboards assistant test-command: env CYPRESS_DASHBOARDS_ASSISTANT_ENABLED=true yarn cypress:run-with-security --browser chromium --spec 'cypress/integration/plugins/dashboards-assistant/*' - osd-serve-args: --assistant.chat.enabled=true --assistant.chat.rootAgentName="Cypress test agent" + osd-serve-args: --assistant.chat.enabled=true + + tests-without-security: + needs: changes + if: ${{ needs.changes.outputs.tests == 'true' }} + uses: ./.github/workflows/release-e2e-workflow-template.yml + with: + test-name: dashboards assistant + test-command: env CYPRESS_DASHBOARDS_ASSISTANT_ENABLED=true yarn cypress:run-without-security --browser chromium --spec 'cypress/integration/plugins/dashboards-assistant/*' + osd-serve-args: --assistant.chat.enabled=true + security-enabled: false diff --git a/cypress/fixtures/plugins/dashboards-assistant/cluster_settings.json b/cypress/fixtures/plugins/dashboards-assistant/cluster_settings.json index 29e65ef6f..3ce0026db 100644 --- a/cypress/fixtures/plugins/dashboards-assistant/cluster_settings.json +++ b/cypress/fixtures/plugins/dashboards-assistant/cluster_settings.json @@ -2,6 +2,7 @@ "persistent": { "plugins.ml_commons.only_run_on_ml_node": false, "plugins.ml_commons.memory_feature_enabled": true, + "plugins.ml_commons.agent_framework_enabled": true, "plugins.ml_commons.trusted_connector_endpoints_regex": [ "^http://127.0.0.1:3000$" ] diff --git a/cypress/fixtures/plugins/dashboards-assistant/security-cert.js b/cypress/fixtures/plugins/dashboards-assistant/security-cert.js new file mode 100644 index 000000000..7120b6606 --- /dev/null +++ b/cypress/fixtures/plugins/dashboards-assistant/security-cert.js @@ -0,0 +1,70 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * This file should be somewhere else like plugins/security but as assistant is the only consumer of the content + * Would be better to keep within the directory of dashboards-assistant. + */ + +export const certPublicKeyContent = ` +-----BEGIN CERTIFICATE----- +MIIEmDCCA4CgAwIBAgIUZjrlDPP8azRDPZchA/XEsx0X2iYwDQYJKoZIhvcNAQEL +BQAwgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFt +cGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEwHwYDVQQLDBhFeGFtcGxl +IENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1wbGUgQ29tIEluYy4gUm9v +dCBDQTAeFw0yMzA4MjkyMDA2MzdaFw0zMzA4MjYyMDA2MzdaME0xCzAJBgNVBAYT +AmRlMQ0wCwYDVQQHDAR0ZXN0MQ8wDQYDVQQKDAZjbGllbnQxDzANBgNVBAsMBmNs +aWVudDENMAsGA1UEAwwEa2lyazCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAJVcOAQlCiuB9emCljROAXnlsPbG7PE3kNz2sN+BbGuw686Wgyl3uToVHvVs +paMmLUqm1KYz9wMSWTIBZgpJ9hYaIbGxD4RBb7qTAJ8Q4ddCV2f7T4lxao/6ixI+ +O0l/BG9E3mRGo/r0w+jtTQ3aR2p6eoxaOYbVyEMYtFI4QZTkcgGIPGxm05y8xonx +vV5pbSW9L7qAVDzQC8EYGQMMI4ccu0NcHKWtmTYJA/wDPE2JwhngHwbcIbc4cDz6 +cG0S3FmgiKGuuSqUy35v/k3y7zMHQSdx7DSR2tzhH/bBL/9qGvpT71KKrxPtaxS0 +bAqPcEkKWDo7IMlGGW7LaAWfGg8CAwEAAaOCASswggEnMAwGA1UdEwEB/wQCMAAw +DgYDVR0PAQH/BAQDAgXgMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMCMIHPBgNVHSME +gccwgcSAFBeH36Ba62YSp9XQ+LoSRTy3KwCcoYGVpIGSMIGPMRMwEQYKCZImiZPy +LGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEZMBcGA1UECgwQRXhh +bXBsZSBDb20gSW5jLjEhMB8GA1UECwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENB +MSEwHwYDVQQDDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0GCFHfkrz782p+T9k0G +xGeM4+BrehWKMB0GA1UdDgQWBBSjMS8tgguX/V7KSGLoGg7K6XMzIDANBgkqhkiG +9w0BAQsFAAOCAQEANMwD1JYlwAh82yG1gU3WSdh/tb6gqaSzZK7R6I0L7slaXN9m +y2ErUljpTyaHrdiBFmPhU/2Kj2r+fIUXtXdDXzizx/JdmueT0nG9hOixLqzfoC9p +fAhZxM62RgtyZoaczQN82k1/geMSwRpEndFe3OH7arkS/HSbIFxQhAIy229eWe5d +1bUzP59iu7f3r567I4ob8Vy7PP+Ov35p7Vv4oDHHwgsdRzX6pvL6mmwVrQ3BfVec +h9Dqprr+ukYmjho76g6k5cQuRaB6MxqldzUg+2E7IHQP8MCF+co51uZq2nl33mtp +RGr6JbdHXc96zsLTL3saJQ8AWEfu1gbTVrwyRA== +-----END CERTIFICATE----- +`; + +export const certPrivateKeyContent = ` +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCVXDgEJQorgfXp +gpY0TgF55bD2xuzxN5Dc9rDfgWxrsOvOloMpd7k6FR71bKWjJi1KptSmM/cDElky +AWYKSfYWGiGxsQ+EQW+6kwCfEOHXQldn+0+JcWqP+osSPjtJfwRvRN5kRqP69MPo +7U0N2kdqenqMWjmG1chDGLRSOEGU5HIBiDxsZtOcvMaJ8b1eaW0lvS+6gFQ80AvB +GBkDDCOHHLtDXBylrZk2CQP8AzxNicIZ4B8G3CG3OHA8+nBtEtxZoIihrrkqlMt+ +b/5N8u8zB0Encew0kdrc4R/2wS//ahr6U+9Siq8T7WsUtGwKj3BJClg6OyDJRhlu +y2gFnxoPAgMBAAECggEAP5TOycDkx+megAWVoHV2fmgvgZXkBrlzQwUG/VZQi7V4 +ZGzBMBVltdqI38wc5MtbK3TCgHANnnKgor9iq02Z4wXDwytPIiti/ycV9CDRKvv0 +TnD2hllQFjN/IUh5n4thHWbRTxmdM7cfcNgX3aZGkYbLBVVhOMtn4VwyYu/Mxy8j +xClZT2xKOHkxqwmWPmdDTbAeZIbSv7RkIGfrKuQyUGUaWhrPslvYzFkYZ0umaDgQ +OAthZew5Bz3OfUGOMPLH61SVPuJZh9zN1hTWOvT65WFWfsPd2yStI+WD/5PU1Doo +1RyeHJO7s3ug8JPbtNJmaJwHe9nXBb/HXFdqb976yQKBgQDNYhpu+MYSYupaYqjs +9YFmHQNKpNZqgZ4ceRFZ6cMJoqpI5dpEMqToFH7tpor72Lturct2U9nc2WR0HeEs +/6tiptyMPTFEiMFb1opQlXF2ae7LeJllntDGN0Q6vxKnQV+7VMcXA0Y8F7tvGDy3 +qJu5lfvB1mNM2I6y/eMxjBuQhwKBgQC6K41DXMFro0UnoO879pOQYMydCErJRmjG +/tZSy3Wj4KA/QJsDSViwGfvdPuHZRaG9WtxdL6kn0w1exM9Rb0bBKl36lvi7o7xv +M+Lw9eyXMkww8/F5d7YYH77gIhGo+RITkKI3+5BxeBaUnrGvmHrpmpgRXWmINqr0 +0jsnN3u0OQKBgCf45vIgItSjQb8zonLz2SpZjTFy4XQ7I92gxnq8X0Q5z3B+o7tQ +K/4rNwTju/sGFHyXAJlX+nfcK4vZ4OBUJjP+C8CTjEotX4yTNbo3S6zjMyGQqDI5 +9aIOUY4pb+TzeUFJX7If5gR+DfGyQubvvtcg1K3GHu9u2l8FwLj87sRzAoGAflQF +RHuRiG+/AngTPnZAhc0Zq0kwLkpH2Rid6IrFZhGLy8AUL/O6aa0IGoaMDLpSWUJp +nBY2S57MSM11/MVslrEgGmYNnI4r1K25xlaqV6K6ztEJv6n69327MS4NG8L/gCU5 +3pEm38hkUi8pVYU7in7rx4TCkrq94OkzWJYurAkCgYATQCL/rJLQAlJIGulp8s6h +mQGwy8vIqMjAdHGLrCS35sVYBXG13knS52LJHvbVee39AbD5/LlWvjJGlQMzCLrw +F7oILW5kXxhb8S73GWcuMbuQMFVHFONbZAZgn+C9FW4l7XyRdkrbR1MRZ2km8YMs +/AHmo368d4PSNRMMzLHw8Q== +-----END PRIVATE KEY----- +`; diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/data_source_selector.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/data_source_selector.spec.js new file mode 100644 index 000000000..3b5916d0f --- /dev/null +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/data_source_selector.spec.js @@ -0,0 +1,90 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + MiscUtils, + TestFixtureHandler, +} from '@opensearch-dashboards-test/opensearch-dashboards-test-library'; +import { CURRENT_TENANT } from '../../../../../utils/commands'; + +const miscUtils = new MiscUtils(cy); +const testFixtureHandler = new TestFixtureHandler( + cy, + Cypress.env('openSearchUrl') +); + +describe('Data source selector', () => { + before(() => { + CURRENT_TENANT.newTenant = 'global'; + testFixtureHandler.importJSONMapping( + 'cypress/fixtures/dashboard/opensearch_dashboards/data_explorer/index_pattern_without_timefield/mappings.json.txt' + ); + testFixtureHandler.importJSONDoc( + 'cypress/fixtures/dashboard/opensearch_dashboards/data_explorer/index_pattern_without_timefield/data.json.txt' + ); + + miscUtils.visitPage('app/data-explorer/discover#/'); + cy.waitForLoader(); + }); + + after(() => { + testFixtureHandler.clearJSONMapping( + 'cypress/fixtures/dashboard/opensearch_dashboards/data_explorer/index_pattern_without_timefield/mappings.json.txt' + ); + cy.deleteSavedObjectByType('index-pattern'); + }); + + it('displays all data sources by default', () => { + cy.get('[data-test-subj="dataExplorerDSSelect"]').click(); + cy.get('.euiComboBoxOptionsList').should('exist'); + cy.get('.euiComboBoxOption__content').should('have.length', 2); + }); + + it('filters options based on user input', () => { + cy.get('[data-test-subj="dataExplorerDSSelect"] input').type('without', { + force: true, + }); + cy.get('.euiComboBoxOption__content').should('have.length', 1); + cy.get('.euiComboBoxOption__content') + .first() + .should('contain', 'without-timefield'); + }); + + it('updates the visual length of the dropdown based on filtered results', () => { + cy.get('[data-test-subj="dataExplorerDSSelect"] input').clear({ + force: true, + }); + cy.get('[data-test-subj="dataExplorerDSSelect"] input').type( + 'without-timefield', + { + force: true, + } + ); + cy.get('.euiComboBoxOptionsList').then(($listAfterFilter) => { + const heightAfterFilter = $listAfterFilter.height(); + cy.get('[data-test-subj="dataExplorerDSSelect"] input').clear({ + force: true, + }); + cy.get('.euiComboBoxOptionsList').should(($listAll) => { + expect($listAll.height()).to.be.greaterThan(heightAfterFilter); + }); + }); + }); + + it('selects the correct option when clicked', () => { + cy.get('[data-test-subj="dataExplorerDSSelect"] input').type( + 'with-timefield', + { + force: true, + } + ); + + cy.contains('.euiComboBoxOption__content', 'with-timefield').click(); + cy.get('[data-test-subj="dataExplorerDSSelect"] .euiComboBoxPill').should( + 'contain', + 'with-timefield' + ); + }); +}); diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/date_nanos.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/date_nanos.spec.js index b17c78124..5a0dc3659 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/date_nanos.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/date_nanos.spec.js @@ -34,6 +34,7 @@ describe('date_nanos', () => { }); miscUtils.visitPage('app/data-explorer/discover#/'); cy.waitForLoader(); + cy.switchDiscoverTable('new'); cy.setTopNavDate(fromTime, toTime); cy.waitForSearch(); diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/date_nanos_mixed.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/date_nanos_mixed.spec.js index 07e48047f..b56b2ab54 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/date_nanos_mixed.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/date_nanos_mixed.spec.js @@ -31,6 +31,7 @@ describe('date_nanos_mixed', () => { }); miscUtils.visitPage('app/data-explorer/discover#/'); cy.waitForLoader(); + cy.switchDiscoverTable('new'); const fromTime = 'Jan 1, 2019 @ 00:00:00.000'; const toTime = 'Jan 1, 2019 @ 23:59:59.999'; diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/discover.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/discover.spec.js index 760ad48b3..a11258d08 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/discover.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/discover.spec.js @@ -26,6 +26,17 @@ const indexSet = [ describe('discover app', { scrollBehavior: false }, () => { before(() => { + if (Cypress.env('SECURITY_ENABLED')) { + /** + * Security plugin is using private tenant as default. + * So here we'd need to set global tenant as default manually. + */ + cy.changeDefaultTenant({ + multitenancy_enabled: true, + private_tenant_enabled: true, + default_tenant: 'global', + }); + } CURRENT_TENANT.newTenant = 'global'; // import logstash functional testFixtureHandler.importJSONDocIfNeeded( @@ -51,6 +62,7 @@ describe('discover app', { scrollBehavior: false }, () => { `app/data-explorer/discover#/?_g=(filters:!(),time:(from:'2015-09-19T13:31:44.000Z',to:'2015-09-24T01:31:44.000Z'))` ); cy.waitForLoader(); + cy.switchDiscoverTable('new'); cy.waitForSearch(); }); @@ -59,6 +71,9 @@ describe('discover app', { scrollBehavior: false }, () => { describe('save search', () => { const saveSearch1 = 'Save Search # 1'; const saveSearch2 = 'Modified Save Search # 1'; + beforeEach(() => { + cy.switchDiscoverTable('new'); + }); it('should show correct time range string by timepicker', function () { cy.verifyTimeConfig(DE_DEFAULT_START_TIME, DE_DEFAULT_END_TIME); @@ -135,6 +150,7 @@ describe('discover app', { scrollBehavior: false }, () => { const toTime = 'Jun 12, 1999 @ 11:21:04.000'; before(() => { + cy.switchDiscoverTable('new'); cy.setTopNavDate(fromTime, toTime); }); @@ -248,6 +264,10 @@ describe('discover app', { scrollBehavior: false }, () => { }); describe('refresh interval', function () { + beforeEach(() => { + cy.switchDiscoverTable('new'); + }); + it('should refetch when autofresh is enabled', () => { cy.getElementByTestId('openInspectorButton').click(); cy.getElementByTestId('inspectorPanel') @@ -265,12 +285,15 @@ describe('discover app', { scrollBehavior: false }, () => { .should('be.visible') .clear() .type('2'); + + cy.makeDatePickerMenuOpen(); cy.getElementByTestId('superDatePickerToggleRefreshButton').click(); // Let auto refresh run cy.wait(100); // Close the auto refresh + cy.makeDatePickerMenuOpen(); cy.getElementByTestId('superDatePickerToggleRefreshButton').click(); // Check the timestamp of the last request, it should be different than the first timestamp diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/doc_navigation.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/doc_navigation.spec.js index 40ad4c7d9..9901acf4e 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/doc_navigation.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/doc_navigation.spec.js @@ -46,6 +46,7 @@ describe('doc link in discover', () => { `app/data-explorer/discover#/?_g=(filters:!(),time:(from:'2015-09-19T13:31:44.000Z',to:'2015-09-24T01:31:44.000Z'))` ); cy.waitForLoader(); + cy.switchDiscoverTable('new'); cy.waitForSearch(); }); diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/doc_table.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/doc_table.spec.js index e79c33fb3..8b49c671c 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/doc_table.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/doc_table.spec.js @@ -46,6 +46,7 @@ describe('discover doc table', () => { `app/data-explorer/discover#/?_g=(filters:!(),time:(from:'2015-09-19T13:31:44.000Z',to:'2015-09-24T01:31:44.000Z'))` ); cy.waitForLoader(); + cy.switchDiscoverTable('new'); cy.waitForSearch(); }); diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/field_data.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/field_data.spec.js index 2cbf475ae..6f350710c 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/field_data.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/field_data.spec.js @@ -46,12 +46,17 @@ describe('discover tab', () => { `app/data-explorer/discover#/?_g=(filters:!(),time:(from:'2015-09-19T13:31:44.000Z',to:'2015-09-24T01:31:44.000Z'))` ); cy.waitForLoader(); + cy.switchDiscoverTable('new'); cy.waitForSearch(); }); after(() => {}); describe('field data', function () { + before(() => { + cy.switchDiscoverTable('new'); + }); + it('search php should show the correct hit count', function () { const expectedHitCount = '445'; cy.setTopNavQuery('php'); @@ -65,12 +70,18 @@ describe('discover tab', () => { }); it('search type:apache should show the correct hit count', () => { + // add this line to address flakiness in Cypress: + // ensures stable switching to the new Discover table format. + cy.switchDiscoverTable('new'); const expectedHitCount = '11,156'; cy.setTopNavQuery('type:apache'); cy.verifyHitCount(expectedHitCount); }); it('doc view should show Time and _source columns', function () { + // add this line to address flakiness in Cypress: + // ensures stable switching to the new Discover table format. + cy.switchDiscoverTable('new'); cy.getElementByTestId('dataGridHeaderCell-@timestamp').should( 'be.visible' ); diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/index_pattern_with_encoded_id.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/index_pattern_with_encoded_id.spec.js index 6d99eecc5..8e4d4766f 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/index_pattern_with_encoded_id.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/index_pattern_with_encoded_id.spec.js @@ -36,6 +36,7 @@ describe('index pattern with encoded id', () => { // Go to the Discover page miscUtils.visitPage('app/data-explorer/discover#/'); + cy.switchDiscoverTable('new'); cy.setTopNavDate(DE_DEFAULT_START_TIME, DE_DEFAULT_END_TIME); cy.waitForLoader(); }); diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/index_pattern_without_field.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/index_pattern_without_field.spec.js index bc09964e2..5eeb2a57e 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/index_pattern_without_field.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/index_pattern_without_field.spec.js @@ -33,6 +33,7 @@ describe('index pattern without field spec', () => { // Go to the Discover page miscUtils.visitPage('app/data-explorer/discover#/'); cy.waitForLoader(); + cy.switchDiscoverTable('new'); }); after(() => { @@ -49,6 +50,7 @@ describe('index pattern without field spec', () => { it('should display a timepicker after switching to an index pattern with timefield', () => { const indexName = 'with-timefield'; + cy.switchDiscoverTable('new'); cy.getElementByTestId('comboBoxToggleListButton') .should('be.visible') .click(); diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/large_string.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/large_string.spec.js index 825bcbd60..c2a1fc1a2 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/large_string.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/large_string.spec.js @@ -44,6 +44,7 @@ describe('test large strings', () => { // Go to the Discover page miscUtils.visitPage('app/data-explorer/discover#/'); cy.waitForLoader(); + cy.switchDiscoverTable('new'); const ExpectedDoc = 'Project Gutenberg EBook of Hamlet'; @@ -56,7 +57,7 @@ describe('test large strings', () => { }); describe('test large data', function () { - it('search Newsletter should show the correct hit count', function () { + it('search Newsletter should show the correct hit count in legacy table', function () { cy.log('test Newsletter keyword is searched'); const expectedHitCount = '1'; const query = 'Newsletter'; @@ -64,6 +65,15 @@ describe('test large strings', () => { cy.verifyHitCount(expectedHitCount); }); + it('search Newsletter should show the correct hit count in datagrid table', function () { + cy.log('test Newsletter keyword is searched'); + cy.switchDiscoverTable('new'); + const expectedHitCount = '1'; + const query = 'Newsletter'; + cy.setTopNavQuery(query); + cy.verifyHitCount(expectedHitCount); + }); + // flaky when looking for the highlighted mark it.skip('the search term Newsletter should be highlighted in the field data', function () { cy.log('Newsletter appears only once'); diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/saved_queries.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/saved_queries.spec.js index 8173db2cb..f6b5bf711 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/saved_queries.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/data_explorer/saved_queries.spec.js @@ -24,7 +24,7 @@ const indexSet = [ 'logstash-2015.09.20', ]; -describe('saved queries saved objects', () => { +describe.skip('saved queries saved objects', () => { const fromTime = 'Sep 20, 2015 @ 08:00:00.000'; const toTime = 'Sep 21, 2015 @ 08:00:00.000'; before(() => { @@ -50,6 +50,8 @@ describe('saved queries saved objects', () => { // Go to the Discover page miscUtils.visitPage('app/data-explorer/discover#/'); + cy.waitForLoader(); + cy.switchDiscoverTable('new'); // Set time filter cy.setTopNavDate(fromTime, toTime); @@ -62,6 +64,10 @@ describe('saved queries saved objects', () => { }); describe('saved query management component functionality', function () { + beforeEach(() => { + cy.switchDiscoverTable('new'); + }); + it('should show the saved query management component when there are no saved queries', () => { cy.getElementByTestId('saved-query-management-popover-button').click(); cy.getElementByTestId('saved-query-management-popover') diff --git a/cypress/integration/plugins/custom-import-map-dashboards/1_import_vector_map_tab.spec.js b/cypress/integration/plugins/custom-import-map-dashboards/1_import_vector_map_tab.spec.js index 9fb5bb5be..0099d7960 100644 --- a/cypress/integration/plugins/custom-import-map-dashboards/1_import_vector_map_tab.spec.js +++ b/cypress/integration/plugins/custom-import-map-dashboards/1_import_vector_map_tab.spec.js @@ -7,10 +7,12 @@ import { BASE_PATH } from '../../../utils/constants'; import { MiscUtils } from '@opensearch-dashboards-test/opensearch-dashboards-test-library'; +import { CURRENT_TENANT } from '../../../utils/commands'; const miscUtils = new MiscUtils(cy); describe('Verify the presence of import custom map tab in region map plugin', () => { before(() => { + CURRENT_TENANT.newTenant = 'global'; cy.deleteAllIndices(); miscUtils.addSampleData(); @@ -25,8 +27,11 @@ describe('Verify the presence of import custom map tab in region map plugin', () }); it('checks import custom map tab is present', () => { + cy.wait(10000); // Click on "Import Vector Map" tab, which is part of customImportMap plugin - cy.contains('Import Vector Map').click({ force: true }); + cy.contains('Import Vector Map', { timeout: 120000 }) + .should('be.visible') + .click({ force: true }); }); after(() => { diff --git a/cypress/integration/plugins/custom-import-map-dashboards/2_opensearchMapLayer.spec.js b/cypress/integration/plugins/custom-import-map-dashboards/2_opensearchMapLayer.spec.js index 2435691aa..f2536f73b 100644 --- a/cypress/integration/plugins/custom-import-map-dashboards/2_opensearchMapLayer.spec.js +++ b/cypress/integration/plugins/custom-import-map-dashboards/2_opensearchMapLayer.spec.js @@ -4,13 +4,16 @@ */ import { BASE_PATH } from '../../../utils/constants'; +import { CURRENT_TENANT } from '../../../utils/commands'; describe('Default OpenSearch base map layer', () => { before(() => { + CURRENT_TENANT.newTenant = 'global'; cy.visit(`${BASE_PATH}/app/home#/tutorial_directory/sampleData`, { retryOnStatusCodeFailure: true, timeout: 60000, }); + cy.wait(5000); cy.get('div[data-test-subj="sampleDataSetCardflights"]', { timeout: 60000, }) @@ -20,8 +23,9 @@ describe('Default OpenSearch base map layer', () => { }); it('check if default OpenSearch map layer can be open', () => { - cy.visit(`${BASE_PATH}/app/maps-dashboards`); - cy.contains('Create map').click(); + cy.wait(10000); + cy.visit(`${BASE_PATH}/app/maps-dashboards/create`); + cy.wait(10000); cy.get('[data-test-subj="layerControlPanel"]').should( 'contain', 'Default map' @@ -46,6 +50,7 @@ describe('Default OpenSearch base map layer', () => { after(() => { cy.visit(`${BASE_PATH}/app/home#/tutorial_directory`); + cy.wait(5000); cy.get('button[data-test-subj="removeSampleDataSetflights"]') .should('be.visible') .click(); diff --git a/cypress/integration/plugins/custom-import-map-dashboards/3_add_saved_object.spec.js b/cypress/integration/plugins/custom-import-map-dashboards/3_add_saved_object.spec.js index fc448a292..2d8b29495 100644 --- a/cypress/integration/plugins/custom-import-map-dashboards/3_add_saved_object.spec.js +++ b/cypress/integration/plugins/custom-import-map-dashboards/3_add_saved_object.spec.js @@ -4,13 +4,16 @@ */ import { BASE_PATH } from '../../../utils/constants'; +import { CURRENT_TENANT } from '../../../utils/commands'; describe('Add flights dataset saved object', () => { before(() => { + CURRENT_TENANT.newTenant = 'global'; cy.visit(`${BASE_PATH}/app/home#/tutorial_directory/sampleData`, { retryOnStatusCodeFailure: true, timeout: 60000, }); + cy.wait(5000); cy.get('div[data-test-subj="sampleDataSetCardflights"]', { timeout: 60000, }) @@ -21,19 +24,25 @@ describe('Add flights dataset saved object', () => { after(() => { cy.visit(`${BASE_PATH}/app/home#/tutorial_directory`); - cy.get('button[data-test-subj="removeSampleDataSetflights"]') + cy.wait(5000); + cy.get('button[data-test-subj="removeSampleDataSetflights"]', { + timeout: 120000, + }) .should('be.visible') .click(); }); it('check if maps saved object of flights dataset can be found and open', () => { + cy.wait(10000); cy.visit(`${BASE_PATH}/app/maps-dashboards`); - cy.contains( - '[Flights] Flights Status on Maps Destination Location' - ).click(); + cy.wait(10000); + cy.contains('[Flights] Flights Status on Maps Destination Location', { + timeout: 120000, + }).click(); cy.get('[data-test-subj="layerControlPanel"]').should( 'contain', - 'Flights On Time' + 'Flights On Time', + { timeout: 120000 } ); }); }); diff --git a/cypress/integration/plugins/custom-import-map-dashboards/4_documentsLayer.spec.js b/cypress/integration/plugins/custom-import-map-dashboards/4_documentsLayer.spec.js index ce677b147..65b637d18 100644 --- a/cypress/integration/plugins/custom-import-map-dashboards/4_documentsLayer.spec.js +++ b/cypress/integration/plugins/custom-import-map-dashboards/4_documentsLayer.spec.js @@ -4,13 +4,16 @@ */ import { BASE_PATH } from '../../../utils/constants'; +import { CURRENT_TENANT } from '../../../utils/commands'; describe('Documents layer', () => { before(() => { + CURRENT_TENANT.newTenant = 'global'; cy.visit(`${BASE_PATH}/app/home#/tutorial_directory/sampleData`, { retryOnStatusCodeFailure: true, timeout: 60000, }); + cy.wait(5000); cy.get('div[data-test-subj="sampleDataSetCardflights"]', { timeout: 60000, }) @@ -22,15 +25,20 @@ describe('Documents layer', () => { const uniqueName = 'saved-map-' + Date.now().toString(); it('Add new documents layer with configuration', () => { - cy.visit(`${BASE_PATH}/app/maps-dashboards`); - cy.contains('Create map').click(); - cy.get("button[data-test-subj='addLayerButton']").click(); - cy.contains('Documents').click(); - cy.contains('Select data source', { timeout: 60000 }).click({ + cy.wait(10000); + cy.visit(`${BASE_PATH}/app/maps-dashboards/create`); + cy.wait(10000); + cy.get("button[data-test-subj='addLayerButton']", { + timeout: 120000, + }).click(); + cy.contains('Documents', { timeout: 120000 }).click(); + cy.contains('Select data source', { timeout: 120000 }).click({ force: true, }); - cy.wait(5000).contains('opensearch_dashboards_sample_data_flights').click(); - cy.contains('Select data field', { timeout: 60000 }).click({ + cy.contains('opensearch_dashboards_sample_data_flights', { + timeout: 120000, + }).click(); + cy.contains('Select data field', { timeout: 120000 }).click({ force: true, }); cy.wait(5000).contains('DestLocation').click(); @@ -65,8 +73,13 @@ describe('Documents layer', () => { }); it('Open saved map with documents layer', () => { + cy.wait(30000); cy.visit(`${BASE_PATH}/app/maps-dashboards`); - cy.get('[data-test-subj="mapListingPage"]').should('contain', uniqueName); + cy.wait(10000); + cy.get('[data-test-subj="mapListingPage"]', { timeout: 120000 }).should( + 'contain', + uniqueName + ); cy.contains(uniqueName).click(); cy.get('[data-test-subj="layerControlPanel"]').should( 'contain', @@ -76,6 +89,7 @@ describe('Documents layer', () => { after(() => { cy.visit(`${BASE_PATH}/app/home#/tutorial_directory`); + cy.wait(5000); cy.get('button[data-test-subj="removeSampleDataSetflights"]') .should('be.visible') .click(); diff --git a/cypress/integration/plugins/dashboards-assistant/chatbot_agent_framework_spec.js b/cypress/integration/plugins/dashboards-assistant/chatbot_agent_framework_spec.js index 6e24d1b69..0092c13ce 100644 --- a/cypress/integration/plugins/dashboards-assistant/chatbot_agent_framework_spec.js +++ b/cypress/integration/plugins/dashboards-assistant/chatbot_agent_framework_spec.js @@ -27,7 +27,7 @@ if (Cypress.env('DASHBOARDS_ASSISTANT_ENABLED')) { describe('Interact with Agent framework', () => { it('toggle Chatbot and enable to interact', () => { // The header may render multiple times, wait for UI to be stable - cy.wait(10000); + cy.wait(5000); // enable to toggle and show Chatbot cy.get(`img[aria-label="toggle chat flyout icon"]`).click(); @@ -42,6 +42,7 @@ if (Cypress.env('DASHBOARDS_ASSISTANT_ENABLED')) { // should have a suggestion section cy.get(`[aria-label="chat suggestions"]`).should('be.length', 1); + cy.contains('suggestion1'); // Click regenerate button cy.get(`button[title="regenerate message"]`).click(); @@ -59,6 +60,7 @@ if (Cypress.env('DASHBOARDS_ASSISTANT_ENABLED')) { // should have a suggestion section cy.get(`[aria-label="chat suggestions"]`).should('be.length', 1); + cy.contains('suggestion2'); }); }); }); diff --git a/cypress/integration/plugins/gantt-chart-dashboards/gantt_ui.spec.js b/cypress/integration/plugins/gantt-chart-dashboards/gantt_ui.spec.js index 29251e3c2..914ada7c3 100644 --- a/cypress/integration/plugins/gantt-chart-dashboards/gantt_ui.spec.js +++ b/cypress/integration/plugins/gantt-chart-dashboards/gantt_ui.spec.js @@ -11,7 +11,7 @@ import { BASE_PATH } from '../../../utils/constants'; dayjs.extend(customParseFormat); -const delay = 100; +const delay = 5000; const GANTT_VIS_NAME = 'A test gantt chart ' + Math.random().toString(36).substring(2); const Y_LABEL = 'A unique label for Y-axis'; @@ -57,6 +57,7 @@ describe('Dump test data', () => { describe('Save a gantt chart', () => { beforeEach(() => { cy.visit(`${BASE_PATH}/app/visualize#`); + cy.wait(delay); }); it('Creates and saves a gantt chart', () => { @@ -83,8 +84,10 @@ describe('Save a gantt chart', () => { describe('Render and configure a gantt chart', () => { beforeEach(() => { + cy.wait(delay); cy.visit(`${BASE_PATH}/app/visualize#`); cy.contains(GANTT_VIS_NAME).click({ force: true }); + cy.wait(delay); }); it('Renders no data message', () => { @@ -114,7 +117,7 @@ describe('Render and configure a gantt chart', () => { cy.wait(delay); cy.get('.traces').should('have.length', DEFAULT_SIZE); - + cy.wait(delay); cy.get('.euiButton__text').contains('Save').click({ force: true }); cy.wait(delay); cy.get('button[data-test-subj="confirmSaveSavedObjectButton"]').click({ @@ -128,6 +131,7 @@ describe('Configure panel settings', () => { cy.visit(`${BASE_PATH}/app/visualize#`); cy.contains(GANTT_VIS_NAME).click({ force: true }); cy.contains('Panel settings').click({ force: true }); + cy.wait(delay); }); it('Changes y-axis label', () => { @@ -244,7 +248,7 @@ describe('Configure panel settings', () => { describe('Add gantt chart to dashboard', () => { it('Adds gantt chart to dashboard', () => { cy.visit(`${BASE_PATH}/app/dashboards#/create`); - + cy.wait(delay); cy.contains('Add an existing').click({ force: true }); cy.wait(delay); cy.get('input[data-test-subj="savedObjectFinderSearchInput"]') diff --git a/cypress/integration/plugins/observability-dashboards/4_panels.spec.js b/cypress/integration/plugins/observability-dashboards/4_panels.spec.js index de7d458d8..2c03c7df1 100644 --- a/cypress/integration/plugins/observability-dashboards/4_panels.spec.js +++ b/cypress/integration/plugins/observability-dashboards/4_panels.spec.js @@ -6,14 +6,13 @@ /// import { - PANEL_DELAY as delay, TEST_PANEL, BASE_PATH, + PANELS_TIMEOUT, } from '../../../utils/constants'; const moveToPanelHome = () => { cy.visit(`${BASE_PATH}/app/observability-dashboards#`); - cy.wait(delay * 3); }; describe('Testing panels table', () => { @@ -22,11 +21,12 @@ describe('Testing panels table', () => { }); it('Creates a panel and redirects to the panel', () => { - cy.get('.euiButton__text') + // Extending timeout so page completely loads + cy.get('.euiButton__text', { timeout: PANELS_TIMEOUT }) .contains('Create Dashboard') .trigger('mouseover') .click(); - cy.wait(delay); + cy.location('href').should('include', 'create'); cy.get('input.euiFieldText').focus().type(TEST_PANEL, { delay: 50, }); @@ -34,27 +34,9 @@ describe('Testing panels table', () => { .contains(/^Create$/) .trigger('mouseover') .click(); - cy.wait(delay); + cy.intercept('POST', '/api/saved_objects/*').as('createDashboard'); + cy.wait('@createDashboard'); cy.contains(TEST_PANEL).should('exist'); }); - - it('Duplicates a panel', () => { - cy.get('.euiCheckbox__input[title="Select this row"]') - .eq(0) - .trigger('mouseover') - .click(); - cy.wait(delay); - cy.get('.euiButton__text').contains('Actions').trigger('mouseover').click(); - cy.wait(delay); - cy.get('.euiContextMenuItem__text') - .contains('Duplicate') - .trigger('mouseover') - .click(); - cy.get('.euiButton__text') - .contains('Duplicate') - .trigger('mouseover') - .click(); - cy.wait(delay); - }); }); diff --git a/cypress/integration/plugins/observability-dashboards/6_notebooks.spec.js b/cypress/integration/plugins/observability-dashboards/6_notebooks.spec.js index 49a4dc7e9..8c6ebd3d8 100644 --- a/cypress/integration/plugins/observability-dashboards/6_notebooks.spec.js +++ b/cypress/integration/plugins/observability-dashboards/6_notebooks.spec.js @@ -6,16 +6,18 @@ /// import { - SAMPLE_SQL_QUERY, TEST_NOTEBOOK, SAMPLE_URL, BASE_PATH, delayTime, MARKDOWN_TEXT, + OBSERVABILITY_INDEX_NAME, } from '../../../utils/constants'; import { skipOn } from '@cypress/skip-test'; +let loadedOnce = 0; + const moveToNotebookHome = () => { cy.visit(`${BASE_PATH}/app/observability-notebooks#/`); }; @@ -25,8 +27,25 @@ const moveToTestNotebook = () => { timeout: delayTime * 3, }); - // Reload page to load notebooks if they are not flushed in OpenSearch index yet. - cy.reload(); + // Force refresh the observablity index and reload page to load notebooks. + if (loadedOnce === 0) { + cy.request({ + method: 'POST', + failOnStatusCode: false, + form: false, + url: 'api/console/proxy', + headers: { + 'content-type': 'application/json;charset=UTF-8', + 'osd-xsrf': true, + }, + qs: { + path: `${OBSERVABILITY_INDEX_NAME}/_refresh`, + method: 'POST', + }, + }); + cy.reload(); + loadedOnce = 1; + } cy.get('.euiTableCellContent') .contains(TEST_NOTEBOOK, { @@ -77,23 +96,6 @@ describe('Testing notebook actions', () => { cy.get('code').contains('POST').should('exist'); cy.get('td').contains('b2').should('exist'); }); - - it('Adds a SQL query paragraph', () => { - cy.get('button[data-test-subj="AddParagraphButton"]').click(); - cy.get('button[data-test-subj="AddCodeBlockBtn"]').click(); - - cy.get('textarea[data-test-subj="editorArea-1"]').clear(); - cy.get('textarea[data-test-subj="editorArea-1"]').focus(); - cy.get('textarea[data-test-subj="editorArea-1"]').type(SAMPLE_SQL_QUERY); - cy.get('button[data-test-subj="runRefreshBtn-1"]').click(); - - cy.get('textarea[data-test-subj="editorArea-1"]').should('not.exist'); - cy.get('div[data-test-subj="queryOutputText"]') - .contains('select 1') - .should('exist'); - - cy.get('.euiDataGrid__overflow').should('exist'); - }); }); describe('Test reporting integration if plugin installed', () => { @@ -113,7 +115,7 @@ describe('Test reporting integration if plugin installed', () => { cy.get('button.euiContextMenuItem:nth-child(1)') .contains('Download PDF') .click(); - cy.get('#downloadInProgressLoadingModal').should('exist'); + cy.get('body').contains('Please continue report generation in the new tab'); }); it('Create in-context PNG report from notebook', () => { @@ -121,7 +123,7 @@ describe('Test reporting integration if plugin installed', () => { cy.get('button.euiContextMenuItem:nth-child(2)') .contains('Download PNG') .click(); - cy.get('#downloadInProgressLoadingModal').should('exist'); + cy.get('body').contains('Please continue report generation in the new tab'); }); it('Create on-demand report definition from context menu', () => { diff --git a/cypress/integration/plugins/observability-dashboards/7_integrations.spec.js b/cypress/integration/plugins/observability-dashboards/7_integrations.spec.js new file mode 100644 index 000000000..2baefcff6 --- /dev/null +++ b/cypress/integration/plugins/observability-dashboards/7_integrations.spec.js @@ -0,0 +1,108 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// + +import { BASE_PATH } from '../../../utils/base_constants'; + +const moveToAvailableNginxIntegration = () => { + cy.visit(`${BASE_PATH}/app/integrations#/available/nginx`); +}; + +const moveToAddedIntegrations = () => { + cy.visit(`${BASE_PATH}/app/integrations#/installed`); +}; + +const createSamples = () => { + moveToAvailableNginxIntegration(); + cy.get('[data-test-subj="try-it-button"]').click(); + cy.get('.euiToastHeader__title').should('contain', 'successfully'); +}; + +const integrationsTeardown = () => { + // Delete all integration instances + cy.request({ + method: 'GET', + form: false, + url: `api/integrations/store`, + headers: { + 'content-type': 'application/json;charset=UTF-8', + 'osd-xsrf': true, + }, + }).then((response) => { + for (const instance of response.body.data.hits) { + cy.request({ + method: 'DELETE', + url: `/api/integrations/store/${instance.id}`, + headers: { + 'content-type': 'application/json;charset=UTF-8', + 'osd-xsrf': true, + }, + }); + } + }); + // Also clean up indices + cy.request({ + method: 'POST', + form: false, + url: 'api/console/proxy', + headers: { + 'content-type': 'application/json;charset=UTF-8', + 'osd-xsrf': true, + }, + qs: { + path: `ss4o_logs-nginx-*`, // All tests work with ss4o nginx data + method: 'DELETE', + }, + body: '{}', + }); +}; + +describe('Add nginx integration instance flow', () => { + beforeEach(() => { + createSamples(); + }); + + afterEach(() => { + integrationsTeardown(); + }); + + it('Navigates to nginx page and triggers the adds the instance flow', () => { + const testInstanceName = 'test_integration_cypress'; + moveToAvailableNginxIntegration(); + cy.get('[data-test-subj="add-integration-button"]').click(); + cy.get('[data-test-subj="new-instance-name"]').should( + 'have.value', + 'nginx Integration' + ); + cy.get('[data-test-subj="create-instance-button"]').should('be.disabled'); + // Modifies the name of the integration + cy.get('[data-test-subj="new-instance-name"]').clear(); + cy.get('[data-test-subj="new-instance-name"]').type(testInstanceName); + // Validates the created sample index + cy.get('[data-test-subj="data-source-name"]').type( + 'ss4o_logs-nginx-sample-sample{enter}' + ); + cy.get('[data-test-subj="create-instance-button"]').click(); + cy.get('[data-test-subj="eventHomePageTitle"]').should( + 'contain', + testInstanceName + ); + }); + + it('Navigates to installed integrations page and verifies that installed integration exists', () => { + const sampleName = 'nginx-sample'; + moveToAddedIntegrations(); + cy.contains(sampleName).should('exist'); + cy.get('input[type="search"]').eq(0).focus(); + cy.get('input[type="search"]').eq(0).type(`${sampleName}{enter}`); + cy.get('.euiTableRow').should('have.length', 1); //Filters correctly to the test integration instance + cy.get(`[data-test-subj="${sampleName}IntegrationLink"]`).click(); + cy.get('[data-test-subj="eventHomePageTitle"]').should( + 'contain', + sampleName + ); + }); +}); diff --git a/cypress/integration/plugins/query-workbench-dashboards/ui.spec.js b/cypress/integration/plugins/query-workbench-dashboards/ui.spec.js index cb3be70b4..62b65282c 100644 --- a/cypress/integration/plugins/query-workbench-dashboards/ui.spec.js +++ b/cypress/integration/plugins/query-workbench-dashboards/ui.spec.js @@ -189,7 +189,7 @@ describe('Test and verify SQL downloads', () => { it(title, () => { cy.request({ method: 'POST', - form: false, + form: true, url: url, headers: { 'content-type': 'application/json;charset=UTF-8', diff --git a/cypress/integration/plugins/reports-dashboards/04-download.spec.js b/cypress/integration/plugins/reports-dashboards/04-download.spec.js index e94e7be66..3ab6bd1a3 100644 --- a/cypress/integration/plugins/reports-dashboards/04-download.spec.js +++ b/cypress/integration/plugins/reports-dashboards/04-download.spec.js @@ -27,24 +27,6 @@ describe('Cypress', () => { cy.wait(3000); }); - it('Download from reporting homepage', () => { - cy.visit(`${BASE_PATH}/app/reports-dashboards#/`, { - waitForGetTenant: true, - }); - cy.location('pathname', { timeout: TIMEOUT }).should( - 'include', - '/reports-dashboards' - ); - - cy.wait(12500); - cy.get('[id="landingPageOnDemandDownload"]') - .contains('CSV') - .click({ force: true }); - cy.get('.euiToastHeader__title') - .contains('Successfully downloaded report') - .should('exist'); - }); - it('Download pdf from in-context menu', () => { cy.visit(`${BASE_PATH}/app/dashboards#`); cy.wait(5000); @@ -91,9 +73,7 @@ describe('Cypress', () => { cy.wait(5000); // open saved search list - cy.get( - 'button.euiButtonEmpty:nth-child(3) > span:nth-child(1) > span:nth-child(1)' - ).click({ force: true }); + cy.get('[data-test-subj="discoverOpenButton"]').click({ force: true }); cy.wait(5000); // click first entry diff --git a/cypress/integration/plugins/security-analytics-dashboards-plugin/2_rules.spec.js b/cypress/integration/plugins/security-analytics-dashboards-plugin/2_rules.spec.js index 4b6fa5774..b1831cfc9 100644 --- a/cypress/integration/plugins/security-analytics-dashboards-plugin/2_rules.spec.js +++ b/cypress/integration/plugins/security-analytics-dashboards-plugin/2_rules.spec.js @@ -517,7 +517,7 @@ describe('Rules', () => { ); toastShouldExist(); getSelectionPanelByIndex(0).within(() => - getMapValueField().type('FieldValue') + getMapValueField().type('FieldValue', { force: true }) ); // selection map list field @@ -528,7 +528,7 @@ describe('Rules', () => { toastShouldExist(); getSelectionPanelByIndex(0).within(() => { getListRadioField().click({ force: true }); - getMapListField().type('FieldValue'); + getMapListField().type('FieldValue', { force: true }); }); // condition field diff --git a/cypress/support/index.js b/cypress/support/index.js index 56efee283..ef28be2d7 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -65,7 +65,7 @@ if (Cypress.env('ENDPOINT_WITH_PROXY')) { if (Cypress.env('DASHBOARDS_ASSISTANT_ENABLED')) { before(() => { cy.addAssistantRequiredSettings(); - cy.registerRootAgent(); + cy.readOrRegisterRootAgent(); cy.startDummyServer(); }); after(() => { diff --git a/cypress/utils/dashboards/commands.js b/cypress/utils/dashboards/commands.js index fd88e643e..4be5cca40 100644 --- a/cypress/utils/dashboards/commands.js +++ b/cypress/utils/dashboards/commands.js @@ -79,7 +79,10 @@ Cypress.Commands.add('setTopNavDate', (start, end, submit = true) => { cy.getElementByTestId('superDatePickerAbsoluteDateInput', opts) .click(opts) .clear(opts) - .type(start, opts); + .type(start, { + ...opts, + delay: 0, // add a delay here, cypress sometimes fails to type all the content into the input. + }); // Click end date cy.getElementByTestId('superDatePickerendDatePopoverButton', opts) @@ -96,7 +99,10 @@ Cypress.Commands.add('setTopNavDate', (start, end, submit = true) => { .last(opts) .click(opts) .clear(opts) - .type(end, opts); + .type(end, { + ...opts, + delay: 0, // add a delay here, cypress sometimes fails to type all the content into the input. + }); // Close popup cy.getElementByTestId('superDatePickerendDatePopoverButton', opts).click( diff --git a/cypress/utils/dashboards/data_explorer/commands.js b/cypress/utils/dashboards/data_explorer/commands.js index 968558b89..8170089d6 100644 --- a/cypress/utils/dashboards/data_explorer/commands.js +++ b/cypress/utils/dashboards/data_explorer/commands.js @@ -133,3 +133,46 @@ Cypress.Commands.add('deleteSaveQuery', (name) => { }); cy.getElementByTestId('confirmModalConfirmButton').click(); }); + +Cypress.Commands.add('switchDiscoverTable', (name) => { + cy.getElementByTestId('datagridTableButton') + .then(($button) => { + const buttonText = $button.text(); + + if (name === 'new' && buttonText.includes('Try new Discover')) { + cy.wrap($button).click(); + } + if (name === 'legacy' && buttonText.includes('Use legacy Discover')) { + cy.wrap($button).click(); + } + cy.waitForLoader(); + }) + .then(() => { + checkForElementVisibility(); + }); +}); + +Cypress.Commands.add('makeDatePickerMenuOpen', () => { + cy.get( + '[class="euiFormControlLayout euiFormControlLayout--group euiSuperDatePicker"]' + ).then(($popover) => { + // Check if the popover does not have the 'euiPopover-isOpen' class + if (!$popover.hasClass('euiPopover-isOpen')) { + // If not open, click the button to open the quick menu + cy.getElementByTestId('superDatePickerToggleQuickMenuButton').click(); + } + }); +}); + +function checkForElementVisibility() { + cy.getElementsByTestIds('queryInput') + .should('be.visible') + .then(($element) => { + if ($element.is(':visible')) { + return; + } else { + cy.wait(500); // Wait for half a second before checking again + checkForElementVisibility(); // Recursive call + } + }); +} diff --git a/cypress/utils/dashboards/data_explorer/index.d.ts b/cypress/utils/dashboards/data_explorer/index.d.ts index ef7c5980d..bc71c6ade 100644 --- a/cypress/utils/dashboards/data_explorer/index.d.ts +++ b/cypress/utils/dashboards/data_explorer/index.d.ts @@ -15,6 +15,8 @@ declare namespace Cypress { saveQuery(name: string, description: string): Chainable; loadSaveQuery(name: string): Chainable; clearSaveQuery(): Chainable; - deleteSaveQuery(name: string):Chainable; + deleteSaveQuery(name: string): Chainable; + switchDiscoverTable(name: string): Chainable; + makeDatePickerMenuOpen(): Chainable; } } \ No newline at end of file diff --git a/cypress/utils/plugins/dashboards-assistant/commands.js b/cypress/utils/plugins/dashboards-assistant/commands.js index 8197c9d80..10a9d7e90 100644 --- a/cypress/utils/plugins/dashboards-assistant/commands.js +++ b/cypress/utils/plugins/dashboards-assistant/commands.js @@ -3,11 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { get } from 'lodash'; import FlowTemplateJSON from '../../../fixtures/plugins/dashboards-assistant/flow-template.json'; import { BACKEND_BASE_PATH, BASE_PATH } from '../../constants'; import { ML_COMMONS_API, ASSISTANT_API } from './constants'; import clusterSettings from '../../../fixtures/plugins/dashboards-assistant/cluster_settings.json'; import { apiRequest } from '../../helpers'; +import { + certPrivateKeyContent, + certPublicKeyContent, +} from '../../../fixtures/plugins/dashboards-assistant/security-cert'; Cypress.Commands.add('addAssistantRequiredSettings', () => { cy.request('PUT', `${BACKEND_BASE_PATH}/_cluster/settings`, clusterSettings); @@ -20,10 +25,23 @@ const agentParameters = { rootAgentId: '', }; +Cypress.Commands.add('readOrRegisterRootAgent', () => { + cy.request({ + url: `${BACKEND_BASE_PATH}${ML_COMMONS_API.AGENT_CONFIG}`, + method: 'GET', + failOnStatusCode: false, + }).then((resp) => { + const agentId = get(resp, 'body.configuration.agent_id'); + if (agentId) { + cy.log(`Already initialized agent: ${agentId}, skip the initialize step`); + } else { + cy.log(`Agent id not initialized yet, set up agent`); + return cy.registerRootAgent(); + } + }); +}); + Cypress.Commands.add('registerRootAgent', () => { - // ML needs 10 seconds to initialize its master key - // The ML encryption master key has not been initialized yet. Please retry after waiting for 10 seconds. - cy.wait(10000); /** * TODO use flow framework if the plugin get integrate in the future. */ @@ -112,9 +130,30 @@ Cypress.Commands.add('registerRootAgent', () => { }) .then((resp) => { agentParameters.rootAgentId = resp.body.agent_id; + return cy.putRootAgentId(agentParameters.rootAgentId); }); }); +Cypress.Commands.add('putRootAgentId', (agentId) => { + if (Cypress.env('SECURITY_ENABLED')) { + // The .plugins-ml-config index is a system index and need to call the API by using certificate file + return cy.exec( + `curl -k --cert <(cat < { return; /** diff --git a/cypress/utils/plugins/dashboards-assistant/constants.js b/cypress/utils/plugins/dashboards-assistant/constants.js index c8340b5ed..b9e45f285 100644 --- a/cypress/utils/plugins/dashboards-assistant/constants.js +++ b/cypress/utils/plugins/dashboards-assistant/constants.js @@ -14,6 +14,8 @@ export const ML_COMMONS_API = { CREATE_CONNECTOR: `${ML_COMMONS_API_PREFIX}/connectors/_create`, CREATE_MODEL: `${ML_COMMONS_API_PREFIX}/models/_register`, CREATE_AGENT: `${ML_COMMONS_API_PREFIX}/agents/_register`, + UPDATE_ROOT_AGENT_CONFIG: `/.plugins-ml-config/_doc/os_chat`, + AGENT_CONFIG: `${ML_COMMONS_API_PREFIX}/config/os_chat`, }; export const ASSISTANT_API_BASE = '/api/assistant'; diff --git a/cypress/utils/plugins/observability-dashboards/constants.js b/cypress/utils/plugins/observability-dashboards/constants.js index 402c68d42..6f9cf3d18 100644 --- a/cypress/utils/plugins/observability-dashboards/constants.js +++ b/cypress/utils/plugins/observability-dashboards/constants.js @@ -4,6 +4,7 @@ */ import { BASE_PATH } from '../../base_constants'; +export const OBSERVABILITY_INDEX_NAME = '.opensearch-observability'; export const delayTime = 1500; //Datasources API Constants @@ -202,9 +203,8 @@ export const landOnPanels = () => { * Panel Constants */ -export const PANEL_DELAY = 100; - export const TEST_PANEL = 'Test Panel'; +export const TEST_PANEL_COPY = 'Test Panel (copy)'; export const SAMPLE_PANEL = '[Logs] Web traffic Panel'; export const SAMPLE_VISUALIZATIONS_NAMES = [ @@ -241,6 +241,7 @@ export const PPL_FILTER = export const TYPING_DELAY = 1500; export const TIMEOUT_DELAY = Cypress.env('SECURITY_ENABLED') ? 60000 : 30000; +export const PANELS_TIMEOUT = 120000; export const moveToHomePage = () => { cy.visit(`${BASE_PATH}/app/observability-applications#`); diff --git a/integtest.sh b/integtest.sh index cd97c1da7..2a4499726 100644 --- a/integtest.sh +++ b/integtest.sh @@ -19,11 +19,12 @@ function usage() { echo -e "-t TEST_COMPONENTS\t(OpenSearch-Dashboards reportsDashboards etc.), optional, specify test components, separate with space, else test everything." echo -e "-v VERSION\t, no defaults, indicates the OpenSearch version to test." echo -e "-o OPTION\t, no defaults, determine the TEST_TYPE value among(default, manifest) in test_finder.sh, optional." + echo -e "-r REMOTE_CYPRESS_ENABLED\t(true | false), defaults to true. Feature flag set to specify remote cypress orchestrator runs are enabled or not." echo -e "-h\tPrint this message." echo "--------------------------------------------------------------------------" } -while getopts ":hb:p:s:c:t:v:o:" arg; do +while getopts ":hb:p:s:c:t:v:o:r:" arg; do case $arg in h) usage @@ -50,6 +51,9 @@ while getopts ":hb:p:s:c:t:v:o:" arg; do o) OPTION=$OPTARG ;; + r) + REMOTE_CYPRESS_ENABLED=$OPTARG + ;; :) echo "-${OPTARG} requires an argument" usage @@ -78,6 +82,11 @@ then SECURITY_ENABLED="true" fi +if [ -z "$REMOTE_CYPRESS_ENABLED" ] +then + REMOTE_CYPRESS_ENABLED="true" +fi + if [ -z "$CREDENTIAL" ] then # Starting in 2.12.0, security demo configuration script requires an initial admin password @@ -108,11 +117,19 @@ echo "BROWSER_PATH: $BROWSER_PATH" # # We need to ensure the cypress tests are the last execute process to # the error code gets passed to the CI. -if [ $SECURITY_ENABLED = "true" ] + +if [ "$OSTYPE" = "msys" ] || [ "$OSTYPE" = "cygwin" ] || [ "$OSTYPE" = "win32" ]; then + echo "Disable video recording in Windows due to ffmpeg missing libs in Windows Docker Container" + echo "TODO: https://github.com/opensearch-project/opensearch-dashboards-functional-test/issues/1068" + jq '. + {"video": false}' cypress.json > cypress_new.json # jq does not allow reading and writing on same file + mv -v cypress_new.json cypress.json +fi + +if [ "$SECURITY_ENABLED" = "true" ] then echo "run security enabled tests" yarn cypress:run-with-security --browser "$BROWSER_PATH" --spec "$TEST_FILES" else echo "run security disabled tests" yarn cypress:run-without-security --browser "$BROWSER_PATH" --spec "$TEST_FILES" -fi \ No newline at end of file +fi diff --git a/package.json b/package.json index d1af653f2..3b210f8a9 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "osd:ciGroup3": "echo \"apps/vis-augmenter/*.js\"", "osd:ciGroup4": "echo \"dashboard_sample_data_with_datasource_spec.js,dashboard_sanity_test_spec.js\"", "osd:ciGroup5": "echo \"datasource-management-plugin/*.js\"", - "osd:ciGroup6": "echo \"apps/data_explorer/aaa_before.spec.js,apps/data_explorer/date_nanos_mixed.spec.js,apps/data_explorer/date_nanos.spec.js,apps/data_explorer/discover_histogram.spec.js,apps/data_explorer/discover.spec.js,apps/data_explorer/zzz_after.spec.js\"", + "osd:ciGroup6": "echo \"apps/data_explorer/aaa_before.spec.js,apps/data_explorer/data_source_selector.spec.js,apps/data_explorer/date_nanos_mixed.spec.js,apps/data_explorer/date_nanos.spec.js,apps/data_explorer/discover_histogram.spec.js,apps/data_explorer/discover.spec.js,apps/data_explorer/zzz_after.spec.js\"", "osd:ciGroup7": "echo \"apps/data_explorer/aaa_before.spec.js,apps/data_explorer/doc_navigation.spec.js,apps/data_explorer/doc_table.spec.js,apps/data_explorer/errors.spec.js,apps/data_explorer/field_data.spec.js,apps/data_explorer/zzz_after.spec.js\"", "osd:ciGroup8": "echo \"apps/data_explorer/aaa_before.spec.js,apps/data_explorer/field_visualize.spec.js,apps/data_explorer/filter_editor.spec.js,apps/data_explorer/index_pattern_with_encoded_id.spec.js,apps/data_explorer/index_pattern_without_field.spec.js,apps/data_explorer/zzz_after.spec.js\"", "osd:ciGroup9": "echo \"apps/data_explorer/aaa_before.spec.js,apps/data_explorer/inspector.spec.js,apps/data_explorer/large_string.spec.js,apps/data_explorer/saved_queries.spec.js,apps/data_explorer/shared_links.spec.js,apps/data_explorer/sidebar.spec.js,apps/data_explorer/source_filter.spec.js,apps/data_explorer/zzz_after.spec.js\"", diff --git a/test_finder.sh b/test_finder.sh index 35b9c5238..535b42624 100755 --- a/test_finder.sh +++ b/test_finder.sh @@ -29,7 +29,13 @@ if [ -z $TEST_TYPE ]; then [ -f $OSD_BUILD_MANIFEST ] && TEST_TYPE="manifest" || TEST_TYPE="default" fi -[ ! `echo $SHELL | grep 'bash'` ] && echo "You must run this script with bash as other shells like zsh will fail the script, exit in 10" && sleep 10 && exit 1 +if [ `echo $OSTYPE | grep -i 'linux'` ] || [ `echo $OSTYPE | grep -i 'darwin'` ] +then + [ ! `echo $SHELL | grep -i 'bash'` ] && echo "You must run this script with bash as other shells like zsh will fail the script, exit in 10!" && sleep 10 && exit 1 +else + [ ! `readlink /proc/$$/exe | grep -i 'bash'` ] && echo "You must run this script with bash as other shells like zsh will fail the script, exit in 10!!" && sleep 10 && exit 1 +fi + # Checks if build manifest in parent directory of current directory under local-test-cluster/opensearch-dashboards-* # When the test script executed in the CI, it scales up OpenSearch Dashboards under local-test-cluster with a