From b5a0786c0d4050a50115df15ea36549ff96a74b6 Mon Sep 17 00:00:00 2001 From: Lin Wang Date: Wed, 31 Jan 2024 10:01:44 +0800 Subject: [PATCH 01/17] feat: add CYPRESS_NO_COMMAND_LOG to release signoff workflows (#1009) Signed-off-by: Lin Wang --- .github/workflows/release-signoff-chrome.yml | 2 ++ .github/workflows/release-signoff-chromium-ad-only.yml | 2 ++ .github/workflows/release-signoff-chromium-ism-only.yml | 2 ++ .../workflows/release-signoff-chromium-tests-in-memory-0.yml | 2 ++ .../workflows/release-signoff-chromium-tests-in-memory-10.yml | 2 ++ .../workflows/release-signoff-chromium-tests-in-memory-20.yml | 2 ++ .../workflows/release-signoff-chromium-tests-in-memory-5.yml | 2 ++ .github/workflows/release-signoff-chromium.yml | 2 ++ .github/workflows/release-signoff-electron.yml | 2 ++ .github/workflows/release-signoff-firefox.yml | 2 ++ 10 files changed, 20 insertions(+) diff --git a/.github/workflows/release-signoff-chrome.yml b/.github/workflows/release-signoff-chrome.yml index 7fe376364..e6bdb4775 100644 --- a/.github/workflows/release-signoff-chrome.yml +++ b/.github/workflows/release-signoff-chrome.yml @@ -15,6 +15,8 @@ jobs: NODE_OPTIONS: '--max-old-space-size=6144 --dns-result-order=ipv4first' # 2.12 onwards security demo configuration require a custom admin password OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'myStrongPassword123!' + # Disable command log to unhang + CYPRESS_NO_COMMAND_LOG: 1 steps: - name: Checkout functional-test uses: actions/checkout@v2 diff --git a/.github/workflows/release-signoff-chromium-ad-only.yml b/.github/workflows/release-signoff-chromium-ad-only.yml index 02a9b1eb0..d4db844d9 100644 --- a/.github/workflows/release-signoff-chromium-ad-only.yml +++ b/.github/workflows/release-signoff-chromium-ad-only.yml @@ -15,6 +15,8 @@ jobs: NODE_OPTIONS: '--max-old-space-size=6144 --dns-result-order=ipv4first' # 2.12 onwards security demo configuration require a custom admin password OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'myStrongPassword123!' + # Disable command log to unhang + CYPRESS_NO_COMMAND_LOG: 1 steps: - name: Checkout functional-test uses: actions/checkout@v2 diff --git a/.github/workflows/release-signoff-chromium-ism-only.yml b/.github/workflows/release-signoff-chromium-ism-only.yml index 4abb54461..6f0d5d3d1 100644 --- a/.github/workflows/release-signoff-chromium-ism-only.yml +++ b/.github/workflows/release-signoff-chromium-ism-only.yml @@ -15,6 +15,8 @@ jobs: NODE_OPTIONS: '--max-old-space-size=6144 --dns-result-order=ipv4first' # 2.12 onwards security demo configuration require a custom admin password OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'myStrongPassword123!' + # Disable command log to unhang + CYPRESS_NO_COMMAND_LOG: 1 steps: - name: Checkout functional-test uses: actions/checkout@v2 diff --git a/.github/workflows/release-signoff-chromium-tests-in-memory-0.yml b/.github/workflows/release-signoff-chromium-tests-in-memory-0.yml index 100d8b487..674c34d36 100644 --- a/.github/workflows/release-signoff-chromium-tests-in-memory-0.yml +++ b/.github/workflows/release-signoff-chromium-tests-in-memory-0.yml @@ -15,6 +15,8 @@ jobs: NODE_OPTIONS: '--max-old-space-size=6144 --dns-result-order=ipv4first' # 2.12 onwards security demo configuration require a custom admin password OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'myStrongPassword123!' + # Disable command log to unhang + CYPRESS_NO_COMMAND_LOG: 1 steps: - name: Checkout functional-test uses: actions/checkout@v2 diff --git a/.github/workflows/release-signoff-chromium-tests-in-memory-10.yml b/.github/workflows/release-signoff-chromium-tests-in-memory-10.yml index d180e1a01..8501c9e80 100644 --- a/.github/workflows/release-signoff-chromium-tests-in-memory-10.yml +++ b/.github/workflows/release-signoff-chromium-tests-in-memory-10.yml @@ -15,6 +15,8 @@ jobs: NODE_OPTIONS: '--max-old-space-size=6144 --dns-result-order=ipv4first' # 2.12 onwards security demo configuration require a custom admin password OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'myStrongPassword123!' + # Disable command log to unhang + CYPRESS_NO_COMMAND_LOG: 1 steps: - name: Checkout functional-test uses: actions/checkout@v2 diff --git a/.github/workflows/release-signoff-chromium-tests-in-memory-20.yml b/.github/workflows/release-signoff-chromium-tests-in-memory-20.yml index 5114ca711..2a71090f6 100644 --- a/.github/workflows/release-signoff-chromium-tests-in-memory-20.yml +++ b/.github/workflows/release-signoff-chromium-tests-in-memory-20.yml @@ -15,6 +15,8 @@ jobs: NODE_OPTIONS: '--max-old-space-size=6144 --dns-result-order=ipv4first' # 2.12 onwards security demo configuration require a custom admin password OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'myStrongPassword123!' + # Disable command log to unhang + CYPRESS_NO_COMMAND_LOG: 1 steps: - name: Checkout functional-test uses: actions/checkout@v2 diff --git a/.github/workflows/release-signoff-chromium-tests-in-memory-5.yml b/.github/workflows/release-signoff-chromium-tests-in-memory-5.yml index 6a6c83d6f..66db12ab4 100644 --- a/.github/workflows/release-signoff-chromium-tests-in-memory-5.yml +++ b/.github/workflows/release-signoff-chromium-tests-in-memory-5.yml @@ -15,6 +15,8 @@ jobs: NODE_OPTIONS: '--max-old-space-size=6144 --dns-result-order=ipv4first' # 2.12 onwards security demo configuration require a custom admin password OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'myStrongPassword123!' + # Disable command log to unhang + CYPRESS_NO_COMMAND_LOG: 1 steps: - name: Checkout functional-test uses: actions/checkout@v2 diff --git a/.github/workflows/release-signoff-chromium.yml b/.github/workflows/release-signoff-chromium.yml index 2e01bf67b..405cec501 100644 --- a/.github/workflows/release-signoff-chromium.yml +++ b/.github/workflows/release-signoff-chromium.yml @@ -15,6 +15,8 @@ jobs: NODE_OPTIONS: '--max-old-space-size=6144 --dns-result-order=ipv4first' # 2.12 onwards security demo configuration require a custom admin password OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'myStrongPassword123!' + # Disable command log to unhang + CYPRESS_NO_COMMAND_LOG: 1 steps: - name: Checkout functional-test uses: actions/checkout@v2 diff --git a/.github/workflows/release-signoff-electron.yml b/.github/workflows/release-signoff-electron.yml index d81a4acea..2270882ef 100644 --- a/.github/workflows/release-signoff-electron.yml +++ b/.github/workflows/release-signoff-electron.yml @@ -15,6 +15,8 @@ jobs: NODE_OPTIONS: '--max-old-space-size=6144 --dns-result-order=ipv4first' # 2.12 onwards security demo configuration require a custom admin password OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'myStrongPassword123!' + # Disable command log to unhang + CYPRESS_NO_COMMAND_LOG: 1 steps: - name: Checkout functional-test uses: actions/checkout@v2 diff --git a/.github/workflows/release-signoff-firefox.yml b/.github/workflows/release-signoff-firefox.yml index add0895c9..340de6dc7 100644 --- a/.github/workflows/release-signoff-firefox.yml +++ b/.github/workflows/release-signoff-firefox.yml @@ -15,6 +15,8 @@ jobs: NODE_OPTIONS: '--max-old-space-size=6144 --dns-result-order=ipv4first' # 2.12 onwards security demo configuration require a custom admin password OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'myStrongPassword123!' + # Disable command log to unhang + CYPRESS_NO_COMMAND_LOG: 1 steps: - name: Checkout functional-test uses: actions/checkout@v2 From 10443bddc26164d8cf24878746fe47897f060c79 Mon Sep 17 00:00:00 2001 From: Rohit Ashiwal Date: Thu, 1 Feb 2024 09:56:28 +0530 Subject: [PATCH 02/17] ism-plugin: fix tests (#1030) Change ... 1. 'Close indices' to 'Close' 2. 'Open indices' to 'Open' 3. 'indices' to 'indexes' 4. Sample slack webhook to meet current validation ... to match current tech writing guidelines. Signed-off-by: Rohit Ashiwal --- .../index-management-dashboards-plugin/indices_spec.js | 4 ++-- .../managed_indices_spec.js | 10 +++++----- .../notification_settings.js | 2 +- .../index-management-dashboards-plugin/rollups_spec.js | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cypress/integration/plugins/index-management-dashboards-plugin/indices_spec.js b/cypress/integration/plugins/index-management-dashboards-plugin/indices_spec.js index ea255848d..723835d18 100644 --- a/cypress/integration/plugins/index-management-dashboards-plugin/indices_spec.js +++ b/cypress/integration/plugins/index-management-dashboards-plugin/indices_spec.js @@ -473,7 +473,7 @@ describe('Indices', () => { .click(); // Check for close index modal - cy.contains('Close indices'); + cy.contains('Close'); // Close confirm button should be disabled cy.get('[data-test-subj="Close Confirm button"]').should( @@ -525,7 +525,7 @@ describe('Indices', () => { .click(); // Check for open index modal - cy.contains('Open indices'); + cy.contains('Open'); cy.get('[data-test-subj="Open Confirm button"]').click(); diff --git a/cypress/integration/plugins/index-management-dashboards-plugin/managed_indices_spec.js b/cypress/integration/plugins/index-management-dashboards-plugin/managed_indices_spec.js index e6514a075..eefd530b0 100644 --- a/cypress/integration/plugins/index-management-dashboards-plugin/managed_indices_spec.js +++ b/cypress/integration/plugins/index-management-dashboards-plugin/managed_indices_spec.js @@ -58,13 +58,13 @@ describe('Managed indices', () => { }); // Confirm we got a remove policy toaster - cy.contains('Removed policy from 1 managed indices'); + cy.contains('Removed policy from 1 managed indexes'); // Wait some time for remove policy to execute before reload cy.wait(3000).reload(); // Confirm we are back to empty loading state, give 20 seconds as OSD takes a while to load - cy.contains('There are no existing managed indices.', { timeout: 20000 }); + cy.contains('There are no existing managed indexes.', { timeout: 20000 }); }); }); @@ -123,7 +123,7 @@ describe('Managed indices', () => { cy.get(`[data-test-subj="retryModalRetryButton"]`).click({ force: true }); // Confirm we got retry toaster - cy.contains('Retried 1 managed indices'); + cy.contains('Retried 1 managed indexes'); // Reload the page cy.reload(); @@ -249,10 +249,10 @@ describe('Managed indices', () => { }); // Confirm we got the change policy toaster - cy.contains('Changed policy on 1 indices'); + cy.contains('Changed policy on 1 indexes'); // Click back to Managed Indices page by clicking "Managed indices" breadcrumb - cy.contains('Policy managed indices').click(); + cy.contains('Policy managed indexes').click(); // Speed up execution of managed index cy.updateManagedIndexConfigStartTime(SAMPLE_INDEX); diff --git a/cypress/integration/plugins/index-management-dashboards-plugin/notification_settings.js b/cypress/integration/plugins/index-management-dashboards-plugin/notification_settings.js index d7562c14d..c1a22705d 100644 --- a/cypress/integration/plugins/index-management-dashboards-plugin/notification_settings.js +++ b/cypress/integration/plugins/index-management-dashboards-plugin/notification_settings.js @@ -66,7 +66,7 @@ describe('NotificationSettings', () => { config_type: 'slack', is_enabled: true, slack: { - url: 'https://sample-slack-webhook', + url: 'https://hooks.slack.com/services/sample-slack-webhook', }, }, }, diff --git a/cypress/integration/plugins/index-management-dashboards-plugin/rollups_spec.js b/cypress/integration/plugins/index-management-dashboards-plugin/rollups_spec.js index 9b2c6e616..4be179ce0 100644 --- a/cypress/integration/plugins/index-management-dashboards-plugin/rollups_spec.js +++ b/cypress/integration/plugins/index-management-dashboards-plugin/rollups_spec.js @@ -152,7 +152,7 @@ describe('Rollups', () => { cy.get('button').contains('Next').click({ force: true }); // Confirm that we got to step 4 of creation page - cy.contains('Job name and indices'); + cy.contains('Job name and indexes'); // Click the create button cy.get('button').contains('Create').click({ force: true }); From c644c39c1dde2abfff34cf20d79626279d48e4be Mon Sep 17 00:00:00 2001 From: Yulong Ruan Date: Fri, 2 Feb 2024 08:04:45 +0800 Subject: [PATCH 03/17] set time range before opening service and operations (#1023) Signed-off-by: Yulong Ruan --- .../1_trace_analytics_dashboard.spec.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/cypress/integration/plugins/observability-dashboards/1_trace_analytics_dashboard.spec.js b/cypress/integration/plugins/observability-dashboards/1_trace_analytics_dashboard.spec.js index b70a2ba27..33c685ef4 100644 --- a/cypress/integration/plugins/observability-dashboards/1_trace_analytics_dashboard.spec.js +++ b/cypress/integration/plugins/observability-dashboards/1_trace_analytics_dashboard.spec.js @@ -29,12 +29,13 @@ describe('Testing dashboard table', () => { }, }); setTimeFilter(); + }); + + it('Adds the percentile filters', () => { cy.get( '[data-test-subj="trace-groups-service-operation-accordian"]' ).click(); - }); - it('Adds the percentile filters', () => { cy.contains(' >= 95 percentile').click({ force: true }); cy.wait(delayTime); cy.contains(' >= 95 percentile').click({ force: true }); @@ -60,6 +61,9 @@ describe('Testing dashboard table', () => { it('Opens latency trend popover', () => { setTimeFilter(true); + cy.get( + '[data-test-subj="trace-groups-service-operation-accordian"]' + ).click(); cy.get('.euiButtonIcon[aria-label="Open popover"]').first().click(); cy.get('text.ytitle[data-unformatted="Hourly latency (ms)"]').should( 'exist' @@ -67,6 +71,9 @@ describe('Testing dashboard table', () => { }); it('Redirects to traces table with filter', () => { + cy.get( + '[data-test-subj="trace-groups-service-operation-accordian"]' + ).click(); cy.get('[data-test-subj="dashboard-table-traces-button"]') .contains('13') .click(); From 0cec7ed155426d092da3f4f207ef9ddcffb9ed8f Mon Sep 17 00:00:00 2001 From: Jialiang Liang Date: Thu, 1 Feb 2024 17:46:22 -0800 Subject: [PATCH 04/17] [Forwardport main] Fix datasources test cases' url assertion when security enabled (#1039) Signed-off-by: Ryan Liang Co-authored-by: Hailong Cui --- .../7_datasources_dashboard.spec.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cypress/integration/plugins/observability-dashboards/7_datasources_dashboard.spec.js b/cypress/integration/plugins/observability-dashboards/7_datasources_dashboard.spec.js index ac554e5d1..33bc4ec3f 100644 --- a/cypress/integration/plugins/observability-dashboards/7_datasources_dashboard.spec.js +++ b/cypress/integration/plugins/observability-dashboards/7_datasources_dashboard.spec.js @@ -56,10 +56,7 @@ describe('Integration tests for datasources plugin', () => { visitDatasourcesCreationPage(); cy.get(createS3Button).should('be.visible').click(); - cy.url().should( - 'include', - DATASOURCES_PATH.DATASOURCES_CONFIG_BASE + '/AmazonS3AWSGlue' - ); + cy.url().should('include', 'configure/AmazonS3AWSGlue'); cy.get('h1.euiTitle.euiTitle--medium') .should('be.visible') @@ -70,10 +67,7 @@ describe('Integration tests for datasources plugin', () => { visitDatasourcesCreationPage(); cy.get(createPrometheusButton).should('be.visible').click(); - cy.url().should( - 'include', - DATASOURCES_PATH.DATASOURCES_CONFIG_BASE + '/Prometheus' - ); + cy.url().should('include', 'configure/Prometheus'); cy.get('h4.euiTitle.euiTitle--medium') .should('be.visible') From afc3731d8f6983b3801e1c18bbd128faea3a9c43 Mon Sep 17 00:00:00 2001 From: tygao Date: Fri, 2 Feb 2024 09:47:04 +0800 Subject: [PATCH 05/17] add case for feedback (#1029) Signed-off-by: tygao --- .../dashboards-assistant/feedback_spec.js | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 cypress/integration/plugins/dashboards-assistant/feedback_spec.js diff --git a/cypress/integration/plugins/dashboards-assistant/feedback_spec.js b/cypress/integration/plugins/dashboards-assistant/feedback_spec.js new file mode 100644 index 000000000..8940646dc --- /dev/null +++ b/cypress/integration/plugins/dashboards-assistant/feedback_spec.js @@ -0,0 +1,60 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { BASE_PATH } from '../../../utils/constants'; + +if (Cypress.env('DASHBOARDS_ASSISTANT_ENABLED')) { + describe('Assistant feedback spec', () => { + before(() => { + // Set welcome screen tracking to false + localStorage.setItem('home:welcome:show', 'false'); + // Set new theme modal to false + localStorage.setItem('home:newThemeModal:show', 'false'); + }); + + beforeEach(() => { + // Visit ISM OSD + cy.visit(`${BASE_PATH}/app/home`); + + // Common text to wait for to confirm page loaded, give up to 60 seconds for initial load + cy.get(`input[placeholder="Ask question"]`, { timeout: 60000 }).should( + 'be.length', + 1 + ); + }); + + // clean up localStorage items + after(() => { + localStorage.removeItem('home:welcome:show'); + localStorage.removeItem('home:newThemeModal:show'); + }); + + describe('conversation feedback', () => { + it('display feedback button and able to interact', () => { + // input question + cy.wait(1000); + cy.get(`input[placeholder="Ask question"]`) + .click() + .type('What are the indices in my cluster?{enter}'); + + // should have a LLM Response + cy.contains('The indices in your cluster'); + + // should have a thumb up and a thumb down feedback button + cy.get(`[aria-label="feedback thumbs up"]`).should('be.length', 1); + cy.get(`[aria-label="feedback thumbs down"]`).should('be.length', 1); + // click thumb up button to feedback + cy.get(`[aria-label="feedback thumbs up"]`).click(); + // only thumb up button displays and thumb down button is hidden + cy.get(`[aria-label="feedback thumbs down"]`).should('be.length', 0); + cy.get(`[aria-label="feedback thumbs up"]`).should('be.length', 1); + // The type of clicked button should be primary. + cy.get(`[aria-label="feedback thumbs up"]`).should( + 'have.class', + 'euiButtonIcon--primary' + ); + }); + }); + }); +} From d1e54140662fd5225490f7a7d64ec1e085cb05d8 Mon Sep 17 00:00:00 2001 From: Lin Wang Date: Fri, 2 Feb 2024 09:47:22 +0800 Subject: [PATCH 06/17] feat: add cypress tests for conversation save to notebook (#1028) Signed-off-by: Lin Wang --- .../conversation_save_to_notebook_spec.js | 97 +++++++++++++++++++ .../plugins/dashboards-assistant/helpers.js | 16 +++ 2 files changed, 113 insertions(+) create mode 100644 cypress/integration/plugins/dashboards-assistant/conversation_save_to_notebook_spec.js create mode 100644 cypress/utils/plugins/dashboards-assistant/helpers.js diff --git a/cypress/integration/plugins/dashboards-assistant/conversation_save_to_notebook_spec.js b/cypress/integration/plugins/dashboards-assistant/conversation_save_to_notebook_spec.js new file mode 100644 index 000000000..6edf56490 --- /dev/null +++ b/cypress/integration/plugins/dashboards-assistant/conversation_save_to_notebook_spec.js @@ -0,0 +1,97 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { BASE_PATH } from '../../../utils/constants'; +import { setStorageItem } from '../../../utils/plugins/dashboards-assistant/helpers'; + +const QUESTION = 'What are the indices in my cluster?'; +const FINAL_ANSWER = + 'The indices in your cluster are the names listed in the response obtained from using a tool to get information about the OpenSearch indices.'; + +if (Cypress.env('DASHBOARDS_ASSISTANT_ENABLED')) { + describe('Assistant conversation save to notebook spec', () => { + let restoreShowHome; + let restoreNewThemeModal; + let restoreTenantSwitchModal; + + beforeEach(() => { + // Set welcome screen tracking to false + restoreShowHome = setStorageItem( + localStorage, + 'home:welcome:show', + 'false' + ); + // Hide new theme modal + restoreNewThemeModal = setStorageItem( + localStorage, + 'home:newThemeModal:show', + 'false' + ); + restoreTenantSwitchModal = setStorageItem( + sessionStorage, + 'opendistro::security::tenant::show_popup', + 'false' + ); + // Visit OSD + cy.visit(`${BASE_PATH}/app/home`); + // Common text to wait for to confirm page loaded, give up to 120 seconds for initial load + cy.get(`input[placeholder="Ask question"]`, { timeout: 120000 }).as( + 'chatInput' + ); + cy.get('@chatInput').should('be.length', 1); + + cy.wait(10000); + + cy.get('@chatInput').click().type(`${QUESTION}{enter}`); + + // should have a LLM Response + cy.contains(FINAL_ANSWER); + }); + + afterEach(() => { + if (restoreShowHome) { + restoreShowHome(); + } + if (restoreNewThemeModal) { + restoreNewThemeModal(); + } + if (restoreTenantSwitchModal) { + restoreTenantSwitchModal(); + } + }); + + it('show succeed toast after saved notebook', () => { + cy.get('button[aria-label="toggle chat context menu"]').click(); + cy.contains('Save to notebook').click(); + cy.get('input[aria-label="Notebook name input"]').type('test notebook'); + cy.get('button[data-test-subj="confirmSaveToNotebookButton"]').click(); + + cy.get('div[aria-label="Notification message list"]') + .contains('This conversation was saved as') + .should('be.visible'); + }); + + it('show conversation details in the created notebook page', () => { + cy.get('button[aria-label="toggle chat context menu"]').click(); + cy.contains('Save to notebook').click(); + cy.get('input[aria-label="Notebook name input"]').type('test notebook'); + cy.get('button[data-test-subj="confirmSaveToNotebookButton"]').click(); + + // Click created notebook link in current tab + cy.get('div[aria-label="Notification message list"]') + .contains('test notebook') + .invoke('removeAttr', 'target') + .as('testNotebookLink'); + + cy.wait(1000); + cy.get('@testNotebookLink').click(); + + cy.location('pathname').should('contains', 'app/observability-notebooks'); + + cy.waitForLoader(); + cy.contains(QUESTION).should('be.visible'); + cy.contains(FINAL_ANSWER).should('be.visible'); + }); + }); +} diff --git a/cypress/utils/plugins/dashboards-assistant/helpers.js b/cypress/utils/plugins/dashboards-assistant/helpers.js new file mode 100644 index 000000000..53093a530 --- /dev/null +++ b/cypress/utils/plugins/dashboards-assistant/helpers.js @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const setStorageItem = (storage, key, value) => { + const oldValue = storage.getItem(key); + storage.setItem(key, value); + return () => { + if (oldValue === null) { + storage.removeItem(key); + } else { + storage.setItem(key, oldValue); + } + }; +}; From b65c5de123a1aeec85a201605b8d5898d73dc1ee Mon Sep 17 00:00:00 2001 From: Lin Wang Date: Fri, 2 Feb 2024 10:03:21 +0800 Subject: [PATCH 07/17] feat: add test cases for assistant conversation history (#1010) * feat: add test cases for assistant conversation history Signed-off-by: Lin Wang * feat: move created history test below Signed-off-by: Lin Wang * rename coversation_history_spec to conversation_history_spec Signed-off-by: Lin Wang * Address pr comments Signed-off-by: Lin Wang * refactor: move setStorageItem to helpers and change to getElementByTestId Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang --- .../conversation_history_spec.js | 212 ++++++++++++++++++ .../plugins/dashboards-assistant/commands.js | 16 +- .../plugins/dashboards-assistant/constants.js | 7 + 3 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 cypress/integration/plugins/dashboards-assistant/conversation_history_spec.js diff --git a/cypress/integration/plugins/dashboards-assistant/conversation_history_spec.js b/cypress/integration/plugins/dashboards-assistant/conversation_history_spec.js new file mode 100644 index 000000000..0349481b9 --- /dev/null +++ b/cypress/integration/plugins/dashboards-assistant/conversation_history_spec.js @@ -0,0 +1,212 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { BASE_PATH } from '../../../utils/constants'; +import { setStorageItem } from '../../../utils/plugins/dashboards-assistant/helpers'; + +if (Cypress.env('DASHBOARDS_ASSISTANT_ENABLED')) { + describe('Assistant conversation history spec', () => { + let restoreShowHome; + let restoreNewThemeModal; + + before(() => { + // Set welcome screen tracking to false + restoreShowHome = setStorageItem( + localStorage, + 'home:welcome:show', + 'false' + ); + // Hide new theme modal + restoreNewThemeModal = setStorageItem( + localStorage, + 'home:newThemeModal:show', + 'false' + ); + // Visit OSD + cy.visit(`${BASE_PATH}/app/home`); + // Common text to wait for to confirm page loaded, give up to 60 seconds for initial load + cy.get(`input[placeholder="Ask question"]`, { timeout: 60000 }).should( + 'be.length', + 1 + ); + + // Open assistant flyout + // The flyout button will be detached and can't be clicked, add 10s delayed fix it. + cy.wait(10000); + cy.get('img[aria-label="toggle chat flyout icon"]').click(); + }); + after(() => { + if (restoreShowHome) { + restoreShowHome(); + } + if (restoreNewThemeModal) { + restoreNewThemeModal(); + } + // Close assistant flyout + cy.get('img[aria-label="toggle chat flyout icon"]').click(); + }); + + beforeEach(() => { + cy.get('.llm-chat-flyout', { timeout: 60000 }).should('be.visible'); + }); + + describe('panel operations', () => { + it('should toggle history list', () => { + cy.get('.llm-chat-flyout button[aria-label="history"]') + .should('be.visible') + .click(); + cy.get('.llm-chat-flyout-body') + .contains('Conversations') + .should('be.visible'); + + cy.get('.llm-chat-flyout button[aria-label="history"]') + .should('be.visible') + .click(); + cy.get('textarea[placeholder="Ask me anything..."]').should('exist'); + cy.get('.llm-chat-flyout-body') + .contains('Conversations') + .should('not.be.visible'); + }); + + it('should back to chat panel', () => { + cy.get('.llm-chat-flyout button[aria-label="history"]').click(); + cy.get('.llm-chat-flyout') + .contains('Conversations') + .should('be.visible'); + + cy.get('.llm-chat-flyout-body').contains('Back').click(); + cy.get('textarea[placeholder="Ask me anything..."]').should('exist'); + }); + + it('should hide back button in fullscreen mode', () => { + cy.get('.llm-chat-flyout button[aria-label="fullScreen"]').click(); + cy.get('.llm-chat-flyout button[aria-label="history"]').click(); + + cy.get('.llm-chat-flyout') + .contains('Conversations') + .should('be.visible'); + cy.get('textarea[placeholder="Ask me anything..."]').should('exist'); + cy.get('.llm-chat-flyout-body') + .contains('Back', { timeout: 3000 }) + .should('not.exist'); + + // Back to default mode + cy.get('.llm-chat-flyout button[aria-label="fullScreen"]').click(); + cy.get('.llm-chat-flyout button[aria-label="history"]').click(); + }); + }); + describe('history item operations', () => { + const conversations = []; + + before(() => { + // Create conversations data + cy.sendAssistantMessage({ + input: { + type: 'input', + content: 'What are the indices in my cluster?', + contentType: 'text', + }, + }).then((result) => { + if (result.status !== 200) { + throw result.body; + } + conversations.push(result.body); + }); + }); + + after(() => { + // Clear created conversations in tests + conversations.map(({ conversationId }) => + cy.deleteConversation(conversationId) + ); + }); + + it('should show created conversation in the history list', () => { + cy.get('.llm-chat-flyout button[aria-label="history"]').click(); + + cy.get('.llm-chat-flyout').contains('Conversations'); + conversations.forEach(({ conversationId }) => { + cy.getElementByTestId(`chatHistoryItem-${conversationId}`).should( + 'exist' + ); + }); + cy.contains('What are the indices in my cluster?'); + cy.get('.llm-chat-flyout button[aria-label="history"]').click(); + }); + + it('should load conversation in chat panel', () => { + cy.get('.llm-chat-flyout button[aria-label="history"]').click(); + + const conversationToLoad = conversations[0]; + + cy.getElementByTestId( + `chatHistoryItem-${conversationToLoad.conversationId}` + ) + .contains(conversationToLoad.title) + .click(); + cy.get('textarea[placeholder="Ask me anything..."]').should('exist'); + cy.get('div.llm-chat-bubble-panel-input').contains( + conversationToLoad.title + ); + }); + + it('should able to update conversation title', () => { + cy.get('.llm-chat-flyout button[aria-label="history"]').click(); + + const conversationToUpdate = conversations[0]; + const newTitle = 'New title'; + + cy.getElementByTestId( + `chatHistoryItem-${conversationToUpdate.conversationId}` + ) + .find('button[aria-label="Edit conversation name"]') + .click(); + cy.contains('Edit conversation name'); + + cy.get('input[aria-label="Conversation name input"').type(newTitle); + cy.getElementByTestId('confirmModalConfirmButton') + .contains('Confirm name') + .click(); + + conversationToUpdate.title = newTitle; + cy.getElementByTestId( + `chatHistoryItem-${conversationToUpdate.conversationId}` + ).contains(conversationToUpdate.title); + cy.contains('Edit conversation name', { timeout: 3000 }).should( + 'not.exist' + ); + + // Reset to chat panel + cy.get('.llm-chat-flyout button[aria-label="history"]').click(); + }); + + it('should able to delete conversation', () => { + cy.get('.llm-chat-flyout button[aria-label="history"]').click(); + + const conversationToDelete = conversations[0]; + + cy.getElementByTestId( + `chatHistoryItem-${conversationToDelete.conversationId}` + ) + .find('button[aria-label="Delete conversation"]') + .click(); + cy.getElementByTestId('confirmModalTitleText').contains( + 'Delete conversation' + ); + + cy.getElementByTestId('confirmModalConfirmButton') + .contains('Delete conversation') + .click(); + + cy.getElementByTestId( + `chatHistoryItem-${conversationToDelete.conversationId}` + ).should('not.exist'); + conversations.shift(); + + // Reset to chat panel + cy.get('.llm-chat-flyout button[aria-label="history"]').click(); + }); + }); + }); +} diff --git a/cypress/utils/plugins/dashboards-assistant/commands.js b/cypress/utils/plugins/dashboards-assistant/commands.js index 51df1be8a..8197c9d80 100644 --- a/cypress/utils/plugins/dashboards-assistant/commands.js +++ b/cypress/utils/plugins/dashboards-assistant/commands.js @@ -4,9 +4,10 @@ */ import FlowTemplateJSON from '../../../fixtures/plugins/dashboards-assistant/flow-template.json'; -import { BACKEND_BASE_PATH } from '../../constants'; -import { ML_COMMONS_API } from './constants'; +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'; Cypress.Commands.add('addAssistantRequiredSettings', () => { cy.request('PUT', `${BACKEND_BASE_PATH}/_cluster/settings`, clusterSettings); @@ -152,3 +153,14 @@ Cypress.Commands.add('stopDummyServer', () => { } }); }); + +Cypress.Commands.add('sendAssistantMessage', (body) => + apiRequest(`${BASE_PATH}${ASSISTANT_API.SEND_MESSAGE}`, 'POST', body) +); + +Cypress.Commands.add('deleteConversation', (conversationId) => + apiRequest( + `${BASE_PATH}${ASSISTANT_API.CONVERSATION}/${conversationId}`, + 'DELETE' + ) +); diff --git a/cypress/utils/plugins/dashboards-assistant/constants.js b/cypress/utils/plugins/dashboards-assistant/constants.js index 16592accb..c8340b5ed 100644 --- a/cypress/utils/plugins/dashboards-assistant/constants.js +++ b/cypress/utils/plugins/dashboards-assistant/constants.js @@ -15,3 +15,10 @@ export const ML_COMMONS_API = { CREATE_MODEL: `${ML_COMMONS_API_PREFIX}/models/_register`, CREATE_AGENT: `${ML_COMMONS_API_PREFIX}/agents/_register`, }; + +export const ASSISTANT_API_BASE = '/api/assistant'; + +export const ASSISTANT_API = { + SEND_MESSAGE: `${ASSISTANT_API_BASE}/send_message`, + CONVERSATION: `${ASSISTANT_API_BASE}/conversation`, +}; From ad6faec0038c1fd6bf27a9e36343edd1ffd02cc0 Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Fri, 2 Feb 2024 15:00:56 +0800 Subject: [PATCH 08/17] feat: add regenerate cases (#1027) * feat: add regenerate cases Signed-off-by: SuZhou-Joe * feat: optimize cases Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhou-Joe --- .../chatbot_agent_framework_spec.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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 82e26c306..3999826f2 100644 --- a/cypress/integration/plugins/dashboards-assistant/chatbot_agent_framework_spec.js +++ b/cypress/integration/plugins/dashboards-assistant/chatbot_agent_framework_spec.js @@ -39,6 +39,23 @@ if (Cypress.env('DASHBOARDS_ASSISTANT_ENABLED')) { // should have a suggestion section cy.get(`[aria-label="chat suggestions"]`).should('be.length', 1); + + // Click regenerate button + cy.get(`button[title="regenerate message"]`).click(); + + // The previous message and the regenerate button should be gone + cy.get(`button[title="regenerate message"]`).should('be.length', 0); + + // suggestions should be gone + cy.get(`[aria-label="chat suggestions"]`).should('be.length', 0); + + // The regenrate message should be there + cy.contains( + 'The indices in your cluster are the names listed in the response obtained from using a tool to get information about the OpenSearch indices.' + ); + + // should have a suggestion section + cy.get(`[aria-label="chat suggestions"]`).should('be.length', 1); }); }); }); From a844c23837830641a3273778c96179d3c5099bc4 Mon Sep 17 00:00:00 2001 From: Manasvini B Suryanarayana Date: Fri, 2 Feb 2024 12:21:29 -0800 Subject: [PATCH 09/17] Add remote cypress orchestrator integration with intestest script (#988) Signed-off-by: manasvinibs --- .github/workflows/remote-cypress-workflow.yml | 12 +- integtest.sh | 119 ++++++++++++++++-- poll_remote_workflow.sh | 30 +++-- remoteCypress.sh | 96 +++++++------- remote_cypress_manifest.json | 31 +++++ 5 files changed, 210 insertions(+), 78 deletions(-) create mode 100644 remote_cypress_manifest.json diff --git a/.github/workflows/remote-cypress-workflow.yml b/.github/workflows/remote-cypress-workflow.yml index 9e75fdef9..cf6c24c8b 100644 --- a/.github/workflows/remote-cypress-workflow.yml +++ b/.github/workflows/remote-cypress-workflow.yml @@ -18,7 +18,8 @@ on: branch_ref: description: 'Test branch name or commit reference id' required: true - +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: trigger-cypress: runs-on: ubuntu-latest @@ -27,10 +28,9 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v2 - - - name: Run Bash Script - env: - GITHUB_SECRET_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Run Remote Cypress Orchestrator Script + if: github.event_name == 'workflow_dispatch' run: | + echo "Executing remoteCypress script for workflow_dispatch event" ./remoteCypress.sh -r "${{ github.event.inputs.repo }}" -w "${{ github.event.inputs.workflow_name }}" -o "${{ github.event.inputs.os_url }}" -d "${{ github.event.inputs.osd_url }}" -b "${{ github.event.inputs.branch_ref }}" - diff --git a/integtest.sh b/integtest.sh index cd97c1da7..31375e896 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 @@ -102,17 +111,111 @@ echo -e "Test Files List:" echo $TEST_FILES | tr ',' '\n' echo "BROWSER_PATH: $BROWSER_PATH" +# Can be used as Jenkins environment variable set for the orchestrator feature flag, default: true +ORCHESTRATOR_FEATURE_FLAG=${ORCHESTRATOR_FEATURE_FLAG:-true} + +# Read inputs from the manifest file for remote cypress orchestrator +REMOTE_MANIFEST_FILE="remote_cypress_manifest.json" + +# PID file to store remote cypress workflow background processes IDs when run in parallel +pid_file="process_ids.txt" + +run_remote_cypress() { + local repo="$1" + local workflow_name="$2" + local os_url="$3" + local osd_url="$4" + local branch_ref="$5" + + # Call the remoteCypress.sh script with the required arguments + source remoteCypress.sh -r "$repo" -w "$workflow_name" -o "$os_url" -d "$osd_url" -b "$branch_ref" & + bg_process_pid=$! + echo "PID for the repo $repo is : $bg_process_pid" + echo "$bg_process_pid" >> "$pid_file" +} + +# Helper function to extract information from a component and return a tuple +get_component_info() { + local component="$1" + local repo workflow_name os_url osd_url branch_ref release_version os arch + + release_version=$(jq -r '.build.version' "$REMOTE_MANIFEST_FILE") + repo=$(echo "$component" | jq -r '.["repository"]') + workflow_name=$(echo "$component" | jq -r '.["workflow-name"]') + os=$(echo "$component" | jq -r '.["operating-system"]') + arch=$(echo "$component" | jq -r '.["arch"]') + branch_ref=$(echo "$component" | jq -r '.["ref"]') + + + # Check if OS and Arch are defined + if [ -n "$os" ] && [ -n "$arch" ]; then + os_url="https://ci.opensearch.org/ci/dbc/distribution-build-opensearch/$release_version/latest/$os/$arch/tar/dist/opensearch/opensearch-$release_version-$os-$arch.tar.gz" + osd_url="https://ci.opensearch.org/ci/dbc/distribution-build-opensearch-dashboards/$release_version/latest/$os/$arch/tar/dist/opensearch-dashboards/opensearch-dashboards-$release_version-$os-$arch.tar.gz" + else + # Default to linux-x64 if not defined in the manifest + os_url="https://ci.opensearch.org/ci/dbc/distribution-build-opensearch/$release_version/latest/linux/x64/tar/dist/opensearch/opensearch-$release_version-linux-x64.tar.gz" + osd_url="https://ci.opensearch.org/ci/dbc/distribution-build-opensearch-dashboards/$release_version/latest/linux/x64/tar/dist/opensearch-dashboards/opensearch-dashboards-$release_version-linux-x64.tar.gz" + fi + + echo "$repo" "$workflow_name" "$os_url" "$osd_url" "$branch_ref" +} + +# Wait for all processes to finish +wait_file() { + while read -r pid; do + wait "$pid" + done < "$pid_file" +} + +if [[ $REMOTE_CYPRESS_ENABLED = "true" && $ORCHESTRATOR_FEATURE_FLAG = 'true' ]]; then + # Parse the JSON file to iterate over the components array + components=$(jq -c '.components[]' "$REMOTE_MANIFEST_FILE") + echo "Components: $components" + + + for component in $components; do + read -r repo workflow_name os_url osd_url branch_ref <<< "$(get_component_info "$component")" + + echo "Processing for the component: $component" + echo "repo: $repo" + echo "workflow_name: $workflow_name" + echo "os_url: $os_url" + echo "osd_url: $osd_url" + echo "branch_ref: $branch_ref" + + # Call the function for each component + run_remote_cypress "$repo" "$workflow_name" "$os_url" "$osd_url" "$branch_ref" + done + + wait_file + log_directory="/tmp/logfiles" + + # Read log files in tmp folder and put the output to CI + find "$log_directory" -type f -name "*.txt" | while IFS= read -r log_file; do + if [ -f "$log_file" ]; then + echo "Log content for file: $log_file" + cat "$log_file" + else + echo "Log file not found: $log_file" + fi + done + + # Delete the temporary log files and folder after writing to CI + rm -rf "$log_directory" +fi +rm "$pid_file" + ## WARNING: THIS LOGIC NEEDS TO BE THE LAST IN THIS FILE! ## # Cypress returns back the test failure count in the error code # The CI outputs the error code as test failure count. # # 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" ] -then - echo "run security enabled tests" - yarn cypress:run-with-security --browser "$BROWSER_PATH" --spec "$TEST_FILES" + +if [ $SECURITY_ENABLED = "true" ]; then + echo "Running 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 + echo "Running security disabled tests" + yarn cypress:run-without-security --browser "$BROWSER_PATH" --spec "$TEST_FILES" +fi diff --git a/poll_remote_workflow.sh b/poll_remote_workflow.sh index e3d575d23..362d7e0c5 100644 --- a/poll_remote_workflow.sh +++ b/poll_remote_workflow.sh @@ -1,10 +1,11 @@ #!/bin/bash -# Accessing the secret as an environment variable using GitHub actions while invoking this script -GITHUB_TOKEN=$GITHUB_SECRET_TOKEN +set -e + REPO="$1" UNIQUE_WORKFLOW_ID="$2" API_URL="$3" +exitcode=2 # Function to check the status of the remote github workflow by constantly polling the workflow-run check_remote_workflow_status() { @@ -52,12 +53,13 @@ check_remote_workflow_status() { -H "Accept: application/vnd.github.v3+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "https://api.github.com/repos/$REPO/actions/runs/$run_id") - echo "Workflow run details: $run_details" - + # Extract status and conclusion from the run details status=$(echo "$run_details" | jq -r ".status") conclusion=$(echo "$run_details" | jq -r ".conclusion") + echo "Workflow run status: $status" + # Check if the status indicates that the workflow is complete if [[ "$status" == "completed" ]]; then echo "Workflow completed with status: $status" @@ -65,7 +67,8 @@ check_remote_workflow_status() { # Check if it was successful if [[ $conclusion == "success" ]]; then echo "Remote workflow completed successfully." - return 0 # Success + exitcode=0 # Success + break; elif [[ $conclusion == "failure" ]]; then echo "Remote workflow completed with errors. Conclusion: $conclusion" @@ -75,13 +78,15 @@ check_remote_workflow_status() { "$jobs_url") # Parse the workflow to find any failures in the test - failures=$(echo "$run_details" | jq -r '.jobs[] | select(.conclusion == "failure") | .name') + failures=$(echo "$job_details" | jq -r '.jobs[] | select(.conclusion == "failure") | .name') echo "Test failures: $failures" - return 1 # Failure + exitcode=1 # Failure + break; else echo "Remote workflow completed with unexpected conclusion. Conclusion: $conclusion" - return 1 # Failure + exitcode=1 # Failure + break; fi else echo "Remote workflow is still running. Waiting..." @@ -91,13 +96,12 @@ check_remote_workflow_status() { done else echo "No matching workflow run object found even after retries. Exiting..." - return 1 # Failure + exitcode=1 # Failure fi - echo "Remote workflow didn't complete within the specified time." - return 1 # Failure + if [ "$exitcode" -eq 2 ]; then + echo "Remote workflow didn't complete within the specified time." + fi } check_remote_workflow_status - -exit 0 \ No newline at end of file diff --git a/remoteCypress.sh b/remoteCypress.sh index a2de652af..f1c1ce67e 100755 --- a/remoteCypress.sh +++ b/remoteCypress.sh @@ -53,61 +53,55 @@ while getopts ":h:r:w:o:d:b:i:" opt; do esac done -# Check if required arguments are provided -if [[ -z "$REPO" || -z "$WORKFLOW_NAME" || -z "$OS_URL" || -z "$OSD_URL" || -z "$BRANCH_REF" ]]; then - echo "Error: Missing required arguments. See usage below." - usage - exit 1 -fi +log_directory="/tmp/logfiles/${REPO}" +mkdir -p "$log_directory" +log_file="$log_directory/logfile.txt" -# Accessing the secret as an environment variable using Github actions while invoking this script -GITHUB_TOKEN=$GITHUB_SECRET_TOKEN -# This is to uniquely identify each execution workflow. This ID has to be appended to the workflow_run -# name in the component repository yaml file for polling purpose. -UNIQUE_WORKFLOW_ID=$(uuidgen) -echo "Unique Execution ID: $UNIQUE_WORKFLOW_ID" -# For now we are using Github action API to trigger github workflows in plugins component -# ToDo: We can explore other test runners such as Jenkins to integrate with. -API_URL="https://api.github.com/repos/$REPO/actions/workflows/$WORKFLOW_NAME" -PAYLOAD="{\"ref\": \"$BRANCH_REF\",\"inputs\":{\"build_id\":\"$BUILD_ID\", \"OS_URL\":\"$OS_URL\", \"OSD_URL\":\"$OSD_URL\", \"UNIQUE_ID\":\"$UNIQUE_WORKFLOW_ID\"}}" - -# Maximum number of retries for triggering the remote runner -MAX_RETRIES=3 - -# Trigger the remote GitHub workflow using curl and the PAT token -trigger_remote_workflow() { - curl -L -X POST -H "Authorization: Bearer $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github.v3+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - -w "%{http_code}" \ - "$API_URL/dispatches" -d "$PAYLOAD" -} - -echo "Triggering the remote GitHub workflow for Cypress tests in the repository: $REPO" +# Check if required arguments are provided +if [[ -n "$REPO" && -n "$WORKFLOW_NAME" && -n "$OS_URL" && -n "$OSD_URL" && -n "$BRANCH_REF" ]]; then + # This is to uniquely identify each execution workflow. This ID has to be appended to the workflow_run + # name in the component repository yaml file for polling purpose. + UNIQUE_WORKFLOW_ID=$(uuidgen) + echo "Unique Execution ID: $UNIQUE_WORKFLOW_ID" + # For now we are using Github action API to trigger github workflows in plugins component + # ToDo: We can explore other test runners such as Jenkins to integrate with. + API_URL="https://api.github.com/repos/$REPO/actions/workflows/$WORKFLOW_NAME" + PAYLOAD="{\"ref\": \"$BRANCH_REF\",\"inputs\":{\"build_id\":\"$BUILD_ID\", \"OS_URL\":\"$OS_URL\", \"OSD_URL\":\"$OSD_URL\", \"UNIQUE_ID\":\"$UNIQUE_WORKFLOW_ID\"}}" -# Attempt to trigger the remote workflow with retries -for ((i = 1; i <= MAX_RETRIES; i++)); do - echo "Attempting to trigger the remote workflow (Attempt $i)" - status_code=$(trigger_remote_workflow) - echo "status_code: $status_code" + # Trigger the remote GitHub workflow using curl and the PAT token + trigger_remote_workflow() { + curl -L -X POST -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + -w "%{http_code}" \ + "$API_URL/dispatches" -d "$PAYLOAD" + } - if [[ $status_code -ge 200 && $status_code -lt 300 ]]; then - echo "Remote workflow triggered successfully." - break - else - echo "Failed to trigger the remote workflow. Retrying..." - sleep 10 # Adds a delay between retries - fi + echo "Triggering the remote GitHub workflow for Cypress tests in the repository: $REPO" - if [ $i -eq $MAX_RETRIES ]; then - echo "Maximum number of retries reached. Exiting." - exit 1 - fi -done + status_code=$(trigger_remote_workflow) + echo "status_code: $status_code" + if [[ $status_code -ge 200 && $status_code -lt 300 ]]; then + echo "Remote workflow triggered successfully." + + source poll_remote_workflow.sh "$REPO" "$UNIQUE_WORKFLOW_ID" "$API_URL" > "$log_file" 2>&1 + echo "Return code: $exitcode" -# Check the status of the remote workflow -source ./poll_remote_workflow.sh "$REPO" "$UNIQUE_WORKFLOW_ID" "$API_URL" -echo "Return code: $?" + if [ "$exitcode" -eq 0 ]; then + echo "Remote workflow for the repo $REPO completed successfully. EXIT CODE 0 " >> "$log_file" + elif [ "$exitcode" -eq 1 ]; then + echo "Remote workflow for the repo $REPO completed with errors. EXIT CODE 1 " >> "$log_file" + else + echo "Remote workflow for the repo $REPO did not complete within the specified time. EXIT CODE 2 " >> "$log_file" + fi -exit 0 + else + echo "Failed to trigger the remote workflow. Exiting." + echo "Failed to trigger the remote workflow for repo $REPO : EXIT CODE 1 " >> "$log_file" + fi +else + echo "Error: Missing required arguments. See usage below." + usage + echo "Remote workflow for the repo $REPO did not start due to missing arguments. EXIT CODE 1 " >> "$log_file" +fi diff --git a/remote_cypress_manifest.json b/remote_cypress_manifest.json new file mode 100644 index 000000000..2f1271a9a --- /dev/null +++ b/remote_cypress_manifest.json @@ -0,0 +1,31 @@ +{ + "schema-version": "1.0", + "build": { + "name": "OpenSearch Dashboards Functional Test", + "version": "3.0.0" + }, + "ci": { + "image": { + } + }, + "components": [ + { + "name": "OpenSearch-Dashboards", + "repository": "opensearch-project/OpenSearch-Dashboards", + "workflow-name": "", + "ref": "", + "operating-system": "linux", + "arch": "x64", + "integ-test": { + "test-configs": [ + "with-security", + "without-security" + ], + "additional-cluster-configs": { + "vis_builder.enabled": true, + "data_source.enabled": true + } + } + } + ] +} From abb5701777f3e500ff069174cf15a5173b77d7e3 Mon Sep 17 00:00:00 2001 From: Sean Li Date: Sat, 3 Feb 2024 22:39:38 -0800 Subject: [PATCH 10/17] fixing panels tests (#1006) Signed-off-by: Sean Li --- .../observability-dashboards/4_panels.spec.js | 23 +++++++++++-------- .../observability-dashboards/constants.js | 4 ++-- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/cypress/integration/plugins/observability-dashboards/4_panels.spec.js b/cypress/integration/plugins/observability-dashboards/4_panels.spec.js index de7d458d8..ef76d26ee 100644 --- a/cypress/integration/plugins/observability-dashboards/4_panels.spec.js +++ b/cypress/integration/plugins/observability-dashboards/4_panels.spec.js @@ -6,14 +6,14 @@ /// import { - PANEL_DELAY as delay, TEST_PANEL, + TEST_PANEL_COPY, 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 +22,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,19 +35,20 @@ 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"]') + cy.get('.euiCheckbox__input[title="Select this row"]', { + timeout: PANELS_TIMEOUT, + }) .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') @@ -55,6 +57,9 @@ describe('Testing panels table', () => { .contains('Duplicate') .trigger('mouseover') .click(); - cy.wait(delay); + cy.intercept('POST', '/api/saved_objects/*').as('createDashboard'); + cy.wait('@createDashboard'); + + cy.contains(TEST_PANEL_COPY); }); }); diff --git a/cypress/utils/plugins/observability-dashboards/constants.js b/cypress/utils/plugins/observability-dashboards/constants.js index 72487eb8b..88fd5c3f0 100644 --- a/cypress/utils/plugins/observability-dashboards/constants.js +++ b/cypress/utils/plugins/observability-dashboards/constants.js @@ -202,9 +202,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 +240,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#`); From 94a5d3c4dc0f57c9b0c327066400067eb2f06754 Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Mon, 5 Feb 2024 17:38:29 +0800 Subject: [PATCH 11/17] fix: flaky tests in discover.spec.js (#1033) * fix: manually set global as default tenant Signed-off-by: SuZhou-Joe * fix: add delay to ensure the input is right Signed-off-by: SuZhou-Joe * feat: add some comment Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhou-Joe --- .../apps/data_explorer/discover.spec.js | 11 +++++++++++ cypress/utils/dashboards/commands.js | 10 ++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) 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..711ed3f5c 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( 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( From 7b1a0e11bb61efa4464e915d16df77dce6524f69 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Mon, 5 Feb 2024 18:26:26 -0500 Subject: [PATCH 12/17] Improve bash checking in test_finder.sh for all OSes (#1058) Signed-off-by: Peter Zhu --- test_finder.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 From 2f5d2f0c9e66575d793ffb45bfa9f9fbcdbb9577 Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Tue, 6 Feb 2024 14:37:26 +0800 Subject: [PATCH 13/17] Comply with the root agent id config change in dashboards-assistant (#1053) (#1062) * feat: update agent id into config index Signed-off-by: SuZhou-Joe * feat: enable agent framework Signed-off-by: SuZhou-Joe * feat: update url Signed-off-by: SuZhou-Joe * feat: update settings Signed-off-by: SuZhou-Joe * feat: test in security disabled Signed-off-by: SuZhou-Joe * feat: run without security Signed-off-by: SuZhou-Joe * feat: optimize config retrieve logic Signed-off-by: SuZhou-Joe * feat: enable run when security enabled Signed-off-by: SuZhou-Joe * feat: enable run when security enabled Signed-off-by: SuZhou-Joe * feat: add some comment Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhou-Joe (cherry picked from commit 7625e0074a4e684ce521f71503756b4b6aa23910) --- .../assistant-release-e2e-workflow.yml | 14 +++- .../cluster_settings.json | 1 + .../dashboards-assistant/security-cert.js | 70 +++++++++++++++++++ .../chatbot_agent_framework_spec.js | 15 ++-- cypress/support/index.js | 2 +- .../plugins/dashboards-assistant/commands.js | 45 +++++++++++- .../plugins/dashboards-assistant/constants.js | 2 + 7 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 cypress/fixtures/plugins/dashboards-assistant/security-cert.js 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/plugins/dashboards-assistant/chatbot_agent_framework_spec.js b/cypress/integration/plugins/dashboards-assistant/chatbot_agent_framework_spec.js index 3999826f2..0092c13ce 100644 --- a/cypress/integration/plugins/dashboards-assistant/chatbot_agent_framework_spec.js +++ b/cypress/integration/plugins/dashboards-assistant/chatbot_agent_framework_spec.js @@ -26,11 +26,14 @@ if (Cypress.env('DASHBOARDS_ASSISTANT_ENABLED')) { describe('Interact with Agent framework', () => { it('toggle Chatbot and enable to interact', () => { - // input question - cy.wait(1000); - cy.get(`input[placeholder="Ask question"]`) - .click() - .type('What are the indices in my cluster?{enter}'); + // The header may render multiple times, wait for UI to be stable + cy.wait(5000); + + // enable to toggle and show Chatbot + cy.get(`img[aria-label="toggle chat flyout icon"]`).click(); + + // click suggestions to generate response + cy.contains('What are the indices in my cluster?').click(); // should have a LLM Response cy.contains( @@ -39,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(); @@ -56,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/support/index.js b/cypress/support/index.js index d747f9873..0182652b7 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/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'; From 607560defc1db1e235f47b4578b41c89b3c39c77 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Tue, 6 Feb 2024 14:25:39 -0500 Subject: [PATCH 14/17] Disable video recording in Windows due to ffmpeg crash (#1069) * Disable video recording in Windows due to ffmpeg crash Signed-off-by: Peter Zhu * Remove test params Signed-off-by: Peter Zhu --------- Signed-off-by: Peter Zhu --- integtest.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/integtest.sh b/integtest.sh index 31375e896..9ee983ae8 100644 --- a/integtest.sh +++ b/integtest.sh @@ -202,8 +202,8 @@ if [[ $REMOTE_CYPRESS_ENABLED = "true" && $ORCHESTRATOR_FEATURE_FLAG = 'true' ] # Delete the temporary log files and folder after writing to CI rm -rf "$log_directory" + rm "$pid_file" fi -rm "$pid_file" ## WARNING: THIS LOGIC NEEDS TO BE THE LAST IN THIS FILE! ## # Cypress returns back the test failure count in the error code @@ -212,7 +212,14 @@ rm "$pid_file" # 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" ]; then +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 "Running security enabled tests" yarn cypress:run-with-security --browser "$BROWSER_PATH" --spec "$TEST_FILES" else From 2eec70b4d91560409322bb667c339425f9112b70 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 08:40:22 +0800 Subject: [PATCH 15/17] notebooks add index refresh, remove SQL check in paragraph (#1065) (#1067) Signed-off-by: Shenoy Pratik (cherry picked from commit f45cdf7650be6866c93924bd385df307e7ca9635) Co-authored-by: Shenoy Pratik --- .../6_notebooks.spec.js | 42 ++++++++++--------- .../observability-dashboards/constants.js | 1 + 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/cypress/integration/plugins/observability-dashboards/6_notebooks.spec.js b/cypress/integration/plugins/observability-dashboards/6_notebooks.spec.js index 49a4dc7e9..46e54e28a 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', () => { diff --git a/cypress/utils/plugins/observability-dashboards/constants.js b/cypress/utils/plugins/observability-dashboards/constants.js index 88fd5c3f0..0e9edd4f7 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 From b544a74ea96966aecf62dcb33c0217efebea1493 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 08:53:09 +0800 Subject: [PATCH 16/17] Fix dashboards observability and reporting test CI issue (#1057) (#1063) * remove one reporting test Signed-off-by: Eric * remove one panel test Signed-off-by: Eric * fix liniting issue Signed-off-by: Eric --------- Signed-off-by: Eric (cherry picked from commit f871b2011095122faaa4558556d831a290a4ef15) Co-authored-by: Eric Wei --- .../observability-dashboards/4_panels.spec.js | 23 ------------------- .../reports-dashboards/04-download.spec.js | 18 --------------- 2 files changed, 41 deletions(-) diff --git a/cypress/integration/plugins/observability-dashboards/4_panels.spec.js b/cypress/integration/plugins/observability-dashboards/4_panels.spec.js index ef76d26ee..2c03c7df1 100644 --- a/cypress/integration/plugins/observability-dashboards/4_panels.spec.js +++ b/cypress/integration/plugins/observability-dashboards/4_panels.spec.js @@ -7,7 +7,6 @@ import { TEST_PANEL, - TEST_PANEL_COPY, BASE_PATH, PANELS_TIMEOUT, } from '../../../utils/constants'; @@ -40,26 +39,4 @@ describe('Testing panels table', () => { cy.contains(TEST_PANEL).should('exist'); }); - - it('Duplicates a panel', () => { - cy.get('.euiCheckbox__input[title="Select this row"]', { - timeout: PANELS_TIMEOUT, - }) - .eq(0) - .trigger('mouseover') - .click(); - cy.get('.euiButton__text').contains('Actions').trigger('mouseover').click(); - cy.get('.euiContextMenuItem__text') - .contains('Duplicate') - .trigger('mouseover') - .click(); - cy.get('.euiButton__text') - .contains('Duplicate') - .trigger('mouseover') - .click(); - cy.intercept('POST', '/api/saved_objects/*').as('createDashboard'); - cy.wait('@createDashboard'); - - cy.contains(TEST_PANEL_COPY); - }); }); diff --git a/cypress/integration/plugins/reports-dashboards/04-download.spec.js b/cypress/integration/plugins/reports-dashboards/04-download.spec.js index e94e7be66..418255be7 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); From 34a26307c685a405e958da16976416793e7bd59a Mon Sep 17 00:00:00 2001 From: Anan Zhuang Date: Tue, 6 Feb 2024 18:46:08 -0800 Subject: [PATCH 17/17] Enable cypress tests to run datagrid table in Discover (#1074) * allow switch table * make sure the DatePickerMenu is open * update switchDiscoverTable to accomadate changing from toggle to button * skip saved queries * fixed flaky tests and missing ones --------- Signed-off-by: Anan Zhuang --- .../apps/data_explorer/date_nanos.spec.js | 1 + .../data_explorer/date_nanos_mixed.spec.js | 1 + .../apps/data_explorer/discover.spec.js | 12 ++++++ .../apps/data_explorer/doc_navigation.spec.js | 1 + .../apps/data_explorer/doc_table.spec.js | 1 + .../apps/data_explorer/field_data.spec.js | 11 +++++ .../index_pattern_with_encoded_id.spec.js | 1 + .../index_pattern_without_field.spec.js | 2 + .../apps/data_explorer/large_string.spec.js | 12 +++++- .../apps/data_explorer/saved_queries.spec.js | 8 +++- .../dashboards/data_explorer/commands.js | 43 +++++++++++++++++++ .../utils/dashboards/data_explorer/index.d.ts | 4 +- 12 files changed, 94 insertions(+), 3 deletions(-) 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 711ed3f5c..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 @@ -62,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(); }); @@ -70,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); @@ -146,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); }); @@ -259,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') @@ -276,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/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