From d230bba9af49c2940aba9db078d75584019febc1 Mon Sep 17 00:00:00 2001 From: Chenyang Ji Date: Tue, 4 Feb 2025 15:28:52 -0800 Subject: [PATCH] Onboard query insights dashboards onto functional test repo (#1689) Signed-off-by: Chenyang Ji --- ...query-insights-dashboards-e2e-workflow.yml | 24 ++ .../sample_document.json | 43 ++++ .../1_top_queries.cy.js | 92 +++++++ .../2_query_details.cy.js | 148 +++++++++++ .../3_configurations.cy.js | 241 ++++++++++++++++++ cypress/support/index.js | 1 + cypress/utils/constants.js | 1 + .../query-insights-dashboards/commands.js | 131 ++++++++++ .../query-insights-dashboards/constants.js | 16 ++ site/index.html | 3 + site/js/dashboard.js | 10 + test_finder.sh | 1 + 12 files changed, 711 insertions(+) create mode 100644 .github/workflows/query-insights-dashboards-e2e-workflow.yml create mode 100644 cypress/fixtures/plugins/query-insights-dashboards/sample_document.json create mode 100644 cypress/integration/plugins/query-insights-dashboards/1_top_queries.cy.js create mode 100644 cypress/integration/plugins/query-insights-dashboards/2_query_details.cy.js create mode 100644 cypress/integration/plugins/query-insights-dashboards/3_configurations.cy.js create mode 100644 cypress/utils/plugins/query-insights-dashboards/commands.js create mode 100644 cypress/utils/plugins/query-insights-dashboards/constants.js diff --git a/.github/workflows/query-insights-dashboards-e2e-workflow.yml b/.github/workflows/query-insights-dashboards-e2e-workflow.yml new file mode 100644 index 000000000..7dfe64786 --- /dev/null +++ b/.github/workflows/query-insights-dashboards-e2e-workflow.yml @@ -0,0 +1,24 @@ +name: Query Insights Dashboards Release tests workflow in Bundled OpenSearch Dashboards +on: + pull_request: + branches: [ '**' ] +jobs: + changes: + runs-on: ubuntu-latest + outputs: + tests: ${{ steps.filter.outputs.tests }} + steps: + - uses: dorny/paths-filter@v2 + id: filter + with: + filters: | + tests: + - 'cypress/**/query-insights-dashboards/**' + + tests: + needs: changes + if: ${{ needs.changes.outputs.tests == 'true' }} + uses: ./.github/workflows/release-e2e-workflow-template.yml + with: + test-name: Query Insights Dashboards + test-command: env CYPRESS_NO_COMMAND_LOG=1 yarn cypress:run-with-security --browser chromium --spec 'cypress/integration/plugins/query-insights-dashboards/*' diff --git a/cypress/fixtures/plugins/query-insights-dashboards/sample_document.json b/cypress/fixtures/plugins/query-insights-dashboards/sample_document.json new file mode 100644 index 000000000..db4e65331 --- /dev/null +++ b/cypress/fixtures/plugins/query-insights-dashboards/sample_document.json @@ -0,0 +1,43 @@ +{ + "@timestamp": "2099-11-15T13:12:00", + "message": "this is document 0", + "user": { + "id": "user1", + "name": "John Doe", + "email": "john.doe@example.com", + "roles": ["admin", "editor"] + }, + "request": { + "method": "GET", + "url": "/api/v1/resource", + "status": 200, + "response_time_ms": 123, + "headers": { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", + "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5..." + } + }, + "location": { + "ip": "192.168.1.1", + "city": "Seattle", + "region": "Washington", + "country": "US" + }, + "application": { + "name": "OpenSearch Dashboard", + "version": "2.8.0", + "environment": "production" + }, + "event": { + "id": "event123", + "type": "user_action", + "outcome": "success", + "reason": null + }, + "tags": ["login", "dashboard", "analytics"], + "metrics": { + "cpu_usage": 2.4, + "memory_usage": 512, + "disk_space_remaining": 1048576 + } +} diff --git a/cypress/integration/plugins/query-insights-dashboards/1_top_queries.cy.js b/cypress/integration/plugins/query-insights-dashboards/1_top_queries.cy.js new file mode 100644 index 000000000..c2d19e6b0 --- /dev/null +++ b/cypress/integration/plugins/query-insights-dashboards/1_top_queries.cy.js @@ -0,0 +1,92 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import sampleDocument from '../../../fixtures/plugins/query-insights-dashboards/sample_document.json'; +import { QUERY_INSIGHTS_METRICS } from '../../../utils/constants'; + +// Name of the test index used in tests +const indexName = 'sample_index'; + +/** + Helper function to clean up the environment: + - Deletes the test index. + - Disables the top queries features. + */ +const clearAll = () => { + cy.deleteIndexByName(indexName); + cy.disableTopQueries(QUERY_INSIGHTS_METRICS.LATENCY); + cy.disableTopQueries(QUERY_INSIGHTS_METRICS.CPU); + cy.disableTopQueries(QUERY_INSIGHTS_METRICS.MEMORY); +}; + +describe('Query Insights Dashboard', () => { + // Setup before each test + beforeEach(() => { + clearAll(); + cy.createIndexByName(indexName, sampleDocument); + cy.enableTopQueries(QUERY_INSIGHTS_METRICS.LATENCY); + cy.enableTopQueries(QUERY_INSIGHTS_METRICS.CPU); + cy.enableTopQueries(QUERY_INSIGHTS_METRICS.MEMORY); + cy.searchOnIndex(indexName); + // wait for 1s to avoid same timestamp + cy.wait(1000); + cy.searchOnIndex(indexName); + cy.wait(1000); + cy.searchOnIndex(indexName); + // waiting for the query insights queue to drain + cy.wait(10000); + cy.navigateToOverview(); + }); + + /** + * Validate the main overview page loads correctly + */ + it('should display the main overview page', () => { + cy.get('.euiBasicTable').should('be.visible'); + cy.contains('Query insights - Top N queries'); + cy.url().should('include', '/queryInsights'); + + // should display the query table on the overview page + cy.get('.euiBasicTable').should('be.visible'); + cy.get('.euiTableHeaderCell').should('have.length.greaterThan', 0); + // should have top n queries displayed on the table + cy.get('.euiTableRow').should('have.length.greaterThan', 0); + }); + + it('should switch between tabs', () => { + // Click Configuration tab + cy.getElementByText('.euiTab', 'Configuration').click({ force: true }); + cy.contains('Query insights - Configuration'); + cy.url().should('include', '/configuration'); + + // Click back to Query Insights tab + cy.getElementByText('.euiTab', 'Top N queries').click({ force: true }); + cy.url().should('include', '/queryInsights'); + }); + + it('should filter queries', () => { + cy.get('.euiFieldSearch').should('be.visible'); + cy.get('.euiFieldSearch').type('sample_index'); + // Add assertions for filtered results + cy.get('.euiTableRow').should('have.length.greaterThan', 0); + }); + + it('should clear the search input and reset results', () => { + cy.get('.euiFieldSearch').type('random_string'); + cy.get('.euiTableRow').should('have.length.greaterThan', 0); + cy.get('.euiFieldSearch').clear(); + cy.get('.euiTableRow').should('have.length.greaterThan', 0); // Validate reset + }); + + it('should display a message when no top queries are found', () => { + clearAll(); // disable top n queries + // waiting for the query insights queue to drain + cy.wait(10000); + cy.reload(); + cy.contains('No items found'); + }); + + after(() => clearAll()); +}); diff --git a/cypress/integration/plugins/query-insights-dashboards/2_query_details.cy.js b/cypress/integration/plugins/query-insights-dashboards/2_query_details.cy.js new file mode 100644 index 000000000..61fee8de7 --- /dev/null +++ b/cypress/integration/plugins/query-insights-dashboards/2_query_details.cy.js @@ -0,0 +1,148 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import sampleDocument from '../../../fixtures/plugins/query-insights-dashboards/sample_document.json'; +import { QUERY_INSIGHTS_METRICS } from '../../../utils/constants'; + +const indexName = 'sample_index'; + +const clearAll = () => { + cy.deleteIndexByName(indexName); + cy.disableTopQueries(QUERY_INSIGHTS_METRICS.LATENCY); + cy.disableTopQueries(QUERY_INSIGHTS_METRICS.CPU); + cy.disableTopQueries(QUERY_INSIGHTS_METRICS.MEMORY); +}; + +describe('Top Queries Details Page', () => { + beforeEach(() => { + clearAll(); + cy.createIndexByName(indexName, sampleDocument); + cy.enableTopQueries(QUERY_INSIGHTS_METRICS.LATENCY); + cy.enableTopQueries(QUERY_INSIGHTS_METRICS.CPU); + cy.enableTopQueries(QUERY_INSIGHTS_METRICS.MEMORY); + cy.searchOnIndex(indexName); + cy.searchOnIndex(indexName); + cy.searchOnIndex(indexName); + // waiting for the query insights queue to drain + cy.wait(10000); + cy.navigateToOverview(); + cy.wait(10000); + cy.get('.euiTableRow').first().find('button').first().trigger('mouseover'); + cy.wait(1000); + cy.get('.euiTableRow').first().find('button').first().click(); // Navigate to details + cy.wait(1000); + }); + + it('should display correct details on the query details page', () => { + // cy.get('.euiBasicTable a').first().click(); // Navigate to details + cy.url().should('include', '/query-details'); + // Validate the page title + cy.get('h1').contains('Query details').should('be.visible'); + // Validate the summary section + cy.get('[data-test-subj="query-details-summary-section"]').should( + 'be.visible' + ); + // Validate the presence of latency chart + cy.get('[data-test-subj="query-details-latency-chart"]').should( + 'be.visible' + ); + // Validate the presence of query source details section + cy.get('[data-test-subj="query-details-source-section"]').should( + 'be.visible' + ); + }); + + /** + * Validate summary panel has valid labels + */ + it('the summary panel should display correctly', () => { + // Validate all field labels exist + const fieldLabels = [ + 'Timestamp', + 'Latency', + 'CPU Time', + 'Memory Usage', + 'Indices', + 'Search Type', + 'Coordinator Node ID', + 'Total Shards', + ]; + fieldLabels.forEach((label) => { + cy.get('.euiPanel').contains('h4', label).should('be.visible'); + }); + }); + + /** + * Validate each field in the summary panel has valid content + */ + it('should display correct values for all fields in the summary panel', () => { + cy.get('[data-test-subj="query-details-summary-section"]').within(() => { + // Validate Timestamp + cy.contains('h4', 'Timestamp') + .parent() + .next() + .invoke('text') + .should('match', /\w{3} \d{2}, \d{4} @ \d{1,2}:\d{2}:\d{2} [AP]M/); + // Validate Latency + cy.contains('h4', 'Latency') + .parent() + .next() + .invoke('text') + .should('match', /^\d+(\.\d{1,2})? ms$/); + // Validate CPU Time + cy.contains('h4', 'CPU Time') + .parent() + .next() + .invoke('text') + .should('match', /^\d+(\.\d+)? ms$/); + // Validate Memory Usage + cy.contains('h4', 'Memory Usage') + .parent() + .next() + .invoke('text') + .should('match', /^\d+(\.\d+)? B$/); + // Validate Indices + cy.contains('h4', 'Indices') + .parent() + .next() + .invoke('text') + .should('not.be.empty'); + // Validate Search Type + cy.contains('h4', 'Search Type') + .parent() + .next() + .invoke('text') + .should('equal', 'query then fetch'); + // Validate Coordinator Node ID + cy.contains('h4', 'Coordinator Node ID') + .parent() + .next() + .invoke('text') + .should('not.be.empty'); + // Validate Total Shards + cy.contains('h4', 'Total Shards') + .parent() + .next() + .invoke('text') + .then((text) => { + const shardCount = parseInt(text.trim(), 10); + expect(shardCount).to.be.a('number').and.to.be.greaterThan(0); + }); + }); + }); + + /** + * Validate the latency chart interaction + */ + it('should render the latency chart and allow interaction', () => { + // Ensure the chart is visible + cy.get('#latency').should('be.visible'); + cy.get('.plot-container').should('be.visible'); + // Simulate hover over the chart for a data point + cy.get('#latency').trigger('mousemove', { clientX: 100, clientY: 100 }); + }); + + after(() => clearAll()); +}); diff --git a/cypress/integration/plugins/query-insights-dashboards/3_configurations.cy.js b/cypress/integration/plugins/query-insights-dashboards/3_configurations.cy.js new file mode 100644 index 000000000..2b3d70b42 --- /dev/null +++ b/cypress/integration/plugins/query-insights-dashboards/3_configurations.cy.js @@ -0,0 +1,241 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { QUERY_INSIGHTS_METRICS } from '../../../utils/constants'; + +const clearAll = () => { + cy.disableTopQueries(QUERY_INSIGHTS_METRICS.LATENCY); + cy.disableTopQueries(QUERY_INSIGHTS_METRICS.CPU); + cy.disableTopQueries(QUERY_INSIGHTS_METRICS.MEMORY); +}; + +const toggleMetricEnabled = async () => { + cy.get('button[data-test-subj="top-n-metric-toggle"]').trigger('mouseover'); + cy.wait(1000); + cy.get('button[data-test-subj="top-n-metric-toggle"]').click({ force: true }); + cy.wait(1000); +}; + +describe('Query Insights Configurations Page', () => { + beforeEach(() => { + clearAll(); + cy.navigateToConfiguration(); + }); + + /** + * Validate the presence and structure of the Configuration page + */ + it('should display the Configuration page with correct structure', () => { + // Validate the page title + cy.get('h1') + .contains('Query insights - Configuration') + .should('be.visible'); + // Validate the tabs + cy.get('.euiTabs').should('be.visible'); + cy.get('.euiTab').should('have.length', 2); // Two tabs: 'Top N queries' and 'Configuration' + cy.contains('button', 'Top N queries').should('be.visible'); + cy.contains('button', 'Configuration').should( + 'have.class', + 'euiTab-isSelected' + ); + // Validate the panels + // 6 panels: Settings, Status, Group Settings, Group Status, Delete After Settings, Delete After Status + cy.get('.euiPanel').should('have.length', 6); + }); + + /** + * Validate the metric type dropdown has 3 metrics + */ + it('should display 3 metrics in the metric type drop down', () => { + // Validate default value + cy.get('select').first().find('option').should('have.length', 3); + const expectedMetrics = ['Latency', 'CPU', 'Memory']; + cy.get('select') + .first() + .find('option') + .each((option, index) => { + cy.wrap(option).should('have.text', expectedMetrics[index]); + }); + }); + + /** + * Validate the metric type dropdown + */ + it('should allow selecting a metric type', () => { + // Select the Metric Type dropdown + cy.get('select').first().should('be.visible'); + // Validate default value + cy.get('select').first().find(':selected').should('have.value', 'latency'); + // Change the selection to 'Memory' + cy.get('select').first().select('memory').should('have.value', 'memory'); + // Change the selection to 'CPU' + cy.get('select').first().select('cpu').should('have.value', 'cpu'); + }); + + /** + * Validate enabling/disabling metrics + */ + it('should allow enabling and disabling metrics', () => { + // Validate the switch for enabling/disabling metrics + cy.get('button[data-test-subj="top-n-metric-toggle"]') + .should('exist') + .and('have.attr', 'aria-checked', 'false') // Initially disabled) + .trigger('mouseover') + .click(); + cy.wait(1000); + + cy.get('button[data-test-subj="top-n-metric-toggle"]').should( + 'have.attr', + 'aria-checked', + 'true' + ); // After toggling, it should be enabled + // Re-enable the switch + cy.get('button[data-test-subj="top-n-metric-toggle"]') + .trigger('mouseover') + .click() + .should('have.attr', 'aria-checked', 'false'); + }); + + /** + * Validate the value of N (count) input + */ + it('should allow updating the value of N (count)', () => { + toggleMetricEnabled(); + // Locate the input for N + cy.get('input[type="number"]').should('have.attr', 'value', '10'); // Default 10 + // Change the value to 50 + cy.get('input[type="number"]') + .first() + .clear() + .type('50') + .should('have.value', '50'); + // Validate invalid input + cy.get('input[type="number"]').first().clear().type('200'); // Enter value above max limit + cy.get('.euiFormHelpText').should('contain.text', 'Max allowed limit 100'); + }); + + /** + * Validate the window size dropdowns + */ + it('should allow selecting a window size and unit', () => { + toggleMetricEnabled(); + // Validate default values + cy.get('select#timeUnit').should('have.value', 'MINUTES'); // Default unit is "Minute(s)" + cy.get('select#minutes').should('have.value', '5'); + // Test valid time unit selection + cy.get('select#timeUnit').select('HOURS').should('have.value', 'HOURS'); + cy.get('select#timeUnit').select('MINUTES').should('have.value', 'MINUTES'); + + // Test valid window size selection + cy.get('select#minutes').select('5'); + cy.get('select#minutes').should('have.value', '5'); + cy.get('select#minutes').select('10'); + cy.get('select#minutes').should('have.value', '10'); + cy.get('select#minutes').select('30'); + cy.get('select#minutes').should('have.value', '30'); + + // Validate constraints + cy.get('select#minutes').select('30'); // Select "30" minutes + cy.get('select#timeUnit') + .select('HOURS') + .then(() => { + cy.get('.euiFormHelpText').should( + 'contain.text', + 'Max allowed limit 24 hours' + ); // Ensure constraint message is shown + }); + }); + + /** + * Validate configuration status panel + */ + it('should display statuses for configuration metrics', () => { + // Validate the status panel header + cy.get('.euiPanel') + .eq(1) // Selects the second panel (index 1) + .within(() => { + cy.get('h2') + .contains('Statuses for configuration metrics') + .should('be.visible'); + }); + // Validate metric statuses (Latency, CPU Usage, Memory) + const metrics = ['Latency', 'CPU Usage', 'Memory']; + metrics.forEach((metric) => { + cy.get('.euiText').contains(metric).should('be.visible'); + cy.get('.euiHealth').contains('Disabled').should('be.visible'); + }); + }); + + /** + * Validate configuration settings panel for group by + */ + it('should display settings for configuration metrics for group by', () => { + cy.get('.euiPanel') + .eq(2) + .within(() => { + cy.get('h2') + .contains('Top n queries grouping configuration settings') + .should('be.visible'); + }); + }); + + /** + * Validate the group by drop-down has 2 options + */ + it('should display 2 metrics in the group by drop-down', () => { + cy.get('.euiPanel') + .eq(2) + .find('select') + .should('exist') + .then(($select) => { + cy.wrap($select).find('option').should('have.length', 2); + + const expectedMetrics = ['None', 'Similarity']; + + cy.wrap($select) + .find('option') + .each((option, index) => { + cy.wrap(option).should('have.text', expectedMetrics[index]); + }); + }); + }); + + /** + * Validate configuration status panel for group by + */ + it('should display configuration statuses for group by metrics', () => { + cy.get('.euiPanel') + .eq(3) + .within(() => { + cy.get('h2') + .should('be.visible') + .and('have.text', 'Statuses for group by'); + + const metrics = [{ name: 'Group By', status: 'Disabled' }]; + + metrics.forEach(({ name, status }) => { + cy.get('.euiText').contains(name).should('be.visible'); + cy.get('.euiHealth').contains(status).should('be.visible'); + }); + }); + }); + + /** + * Validate the save button, changes should be saved and redirect to overview + * After saving the status panel should show the correct status + */ + it('should allow saving the configuration', () => { + toggleMetricEnabled(); + cy.get('select#timeUnit').select('MINUTES'); + cy.get('select#minutes').select('5'); + cy.get('button[data-test-subj="save-config-button"]').click(); + cy.url().should('include', '/queryInsights'); + cy.navigateToConfiguration(); + cy.get('.euiHealth').contains('Enabled').should('be.visible'); + cy.get('.euiText').contains('Latency').should('be.visible'); + }); + + after(() => clearAll()); +}); diff --git a/cypress/support/index.js b/cypress/support/index.js index c6090f69c..c330e82ae 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -34,6 +34,7 @@ import '../utils/plugins/notifications-dashboards/commands'; import '../utils/plugins/dashboards-assistant/commands'; import '../utils/dashboards/console/commands'; import '../utils/dashboards/workspace-plugin/commands'; +import '../utils/plugins/query-insights-dashboards/commands'; import 'cypress-real-events'; diff --git a/cypress/utils/constants.js b/cypress/utils/constants.js index 3a601d669..a9c27637b 100644 --- a/cypress/utils/constants.js +++ b/cypress/utils/constants.js @@ -17,3 +17,4 @@ export * from './plugins/notifications-dashboards/constants'; export * from './plugins/security-dashboards-plugin/constants'; export * from './plugins/security-analytics-dashboards-plugin/constants'; export * from './plugins/ml-commons-dashboards/constants'; +export * from './plugins/query-insights-dashboards/constants'; diff --git a/cypress/utils/plugins/query-insights-dashboards/commands.js b/cypress/utils/plugins/query-insights-dashboards/commands.js new file mode 100644 index 000000000..535f997c5 --- /dev/null +++ b/cypress/utils/plugins/query-insights-dashboards/commands.js @@ -0,0 +1,131 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +const { + QUERY_INSIGHTS_OVERVIEW_PATH, + QUERY_INSIGHTS_CONFIGURATION_PATH, +} = require('./constants'); + +Cypress.Commands.add('getElementByText', (locator, text) => { + Cypress.log({ message: `Get element by text: ${text}` }); + return locator + ? cy.get(locator).filter(`:contains("${text}")`).should('be.visible') + : cy.contains(text).should('be.visible'); +}); + +Cypress.Commands.add('enableTopQueries', (metric) => { + cy.request({ + method: 'PUT', + url: `${Cypress.env('openSearchUrl')}/_cluster/settings`, + body: { + persistent: { + [`search.insights.top_queries.${metric}.enabled`]: true, + [`search.insights.top_queries.${metric}.window_size`]: '1m', + [`search.insights.top_queries.${metric}.top_n_size`]: 100, + }, + }, + failOnStatusCode: false, + }); +}); + +Cypress.Commands.add('disableTopQueries', (metric) => { + cy.request({ + method: 'PUT', + url: `${Cypress.env('openSearchUrl')}/_cluster/settings`, + body: { + persistent: { + [`search.insights.top_queries.${metric}.enabled`]: false, + }, + }, + failOnStatusCode: false, + }); +}); + +Cypress.Commands.add('enableGrouping', () => { + cy.request({ + method: 'PUT', + url: `${Cypress.env('openSearchUrl')}/_cluster/settings`, + body: { + persistent: { + 'search.insights.top_queries.latency.enabled': true, + 'search.insights.top_queries.cpu.enabled': true, + 'search.insights.top_queries.memory.enabled': true, + 'search.insights.top_queries.group_by': 'similarity', + 'search.insights.top_queries.max_groups_excluding_topn': 100, + 'search.insights.top_queries.grouping.attributes.field_name': true, + 'search.insights.top_queries.grouping.attributes.field_type': true, + 'search.insights.top_queries.latency.top_n_size': 5, + 'search.insights.top_queries.cpu.top_n_size': 5, + 'search.insights.top_queries.memory.top_n_size': 5, + 'search.insights.top_queries.latency.window_size': '1m', + 'search.insights.top_queries.cpu.window_size': '1m', + 'search.insights.top_queries.memory.window_size': '1m', + }, + }, + failOnStatusCode: false, + }); +}); + +Cypress.Commands.add('disableGrouping', () => { + cy.request({ + method: 'PUT', + url: `${Cypress.env('openSearchUrl')}/_cluster/settings`, + body: { + persistent: { + 'search.insights.top_queries.latency.enabled': false, + 'search.insights.top_queries.cpu.enabled': false, + 'search.insights.top_queries.memory.enabled': false, + 'search.insights.top_queries.group_by': 'none', + }, + }, + failOnStatusCode: false, + }); +}); + +Cypress.Commands.add('createIndexByName', (indexName, body = {}) => { + cy.request('POST', `${Cypress.env('openSearchUrl')}/${indexName}/_doc`, body); +}); + +Cypress.Commands.add('searchOnIndex', (indexName, body = {}) => { + cy.request( + 'GET', + `${Cypress.env('openSearchUrl')}/${indexName}/_search`, + body + ); +}); + +Cypress.Commands.add('deleteIndexByName', (indexName) => { + cy.request({ + method: 'DELETE', + url: `${Cypress.env('openSearchUrl')}/${indexName}`, + failOnStatusCode: false, + }); +}); + +Cypress.Commands.add( + 'qi_waitForPageLoad', + (fullUrl, { timeout = 60000, contains = null }) => { + Cypress.log({ + message: `Wait for url: ${fullUrl} to be loaded.`, + }); + cy.url({ timeout: timeout }).then(() => { + contains && cy.contains(contains).should('be.visible'); + }); + } +); + +Cypress.Commands.add('navigateToOverview', () => { + cy.visit(QUERY_INSIGHTS_OVERVIEW_PATH); + cy.qi_waitForPageLoad(QUERY_INSIGHTS_OVERVIEW_PATH, { + contains: 'Query insights - Top N queries', + }); +}); + +Cypress.Commands.add('navigateToConfiguration', () => { + cy.visit(QUERY_INSIGHTS_CONFIGURATION_PATH); + cy.qi_waitForPageLoad(QUERY_INSIGHTS_CONFIGURATION_PATH, { + contains: 'Query insights - Configuration', + }); +}); diff --git a/cypress/utils/plugins/query-insights-dashboards/constants.js b/cypress/utils/plugins/query-insights-dashboards/constants.js new file mode 100644 index 000000000..6966fdc35 --- /dev/null +++ b/cypress/utils/plugins/query-insights-dashboards/constants.js @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { BASE_PATH } from '../../base_constants'; + +export const QUERY_INSIGHTS_PLUGIN_NAME = 'query-insights-dashboards'; + +export const QUERY_INSIGHTS_OVERVIEW_PATH = `${BASE_PATH}/app/${QUERY_INSIGHTS_PLUGIN_NAME}#/queryInsights`; +export const QUERY_INSIGHTS_CONFIGURATION_PATH = `${BASE_PATH}/app/${QUERY_INSIGHTS_PLUGIN_NAME}#/configuration`; +export const QUERY_INSIGHTS_METRICS = { + LATENCY: 'latency', + CPU: 'cpu', + MEMORY: 'memory', +}; diff --git a/site/index.html b/site/index.html index c87d9c9cb..3a1df527b 100644 --- a/site/index.html +++ b/site/index.html @@ -182,6 +182,9 @@

Plugins:

+ diff --git a/site/js/dashboard.js b/site/js/dashboard.js index fd7013fc7..82539b91b 100644 --- a/site/js/dashboard.js +++ b/site/js/dashboard.js @@ -165,6 +165,16 @@ const plugins = { ], }, }, + 'query-insights-dashboards': { + name: 'queryInsightsDashboards', + default: { + videos: [ + '1_top_queries.cy.js', + '2_query_details.cy.js', + '3_configurations.cy.js', + ], + }, + }, }; // eslint-disable-next-line no-unused-vars diff --git a/test_finder.sh b/test_finder.sh index 248c039f7..9683121c7 100755 --- a/test_finder.sh +++ b/test_finder.sh @@ -25,6 +25,7 @@ OSD_COMPONENT_TEST_MAP=( "OpenSearch-Dashboards:opensearch-dashboards" "mlCommonsDashboards:ml-commons-dashboards" "securityAnalyticsDashboards:security-analytics-dashboards-plugin" "assistantDashboards:dashboards-assistant" + "queryInsightsDashboards:query-insights-dashboards" "OpenSearch-Dashboards-ci-group-1:OpenSearch-Dashboards-ci-group-1" "OpenSearch-Dashboards-ci-group-2:OpenSearch-Dashboards-ci-group-2" "OpenSearch-Dashboards-ci-group-3:OpenSearch-Dashboards-ci-group-3"