diff --git a/.cypress/integration/flint_datasources/acceleration_table.spec.js b/.cypress/integration/flint_datasources/acceleration_table.spec.js new file mode 100644 index 0000000000..fefa8ea73e --- /dev/null +++ b/.cypress/integration/flint_datasources/acceleration_table.spec.js @@ -0,0 +1,236 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// + +import { + ACC_TABLE_TITLE, + ACC_TABLE_DESC, + UPDATE_AT_DESC, + LOCALIZED_UPDATE_TIMESTAMP_ACC, + REFRESH_BTN_DESC, + CREATE_ACC_BTN_DESC, + ACC_NAME, + ACC_STATUS, + ACC_TYPE, + ACC_DATABASE, + ACC_TABLE, + ACC_REFRESH_TYPE, + ACC_DESTINATION_INDEX, + ACC_ACTIONS_COL, + TYPE_MV, + TYPE_SI, + EMPTY_CONTENT, + ACTIVE_MV_NAME, + SKIP_INDEX_NAME, + ACTION_ICON_DEL, + ACTION_ICON_VAC, + ACTION_ICON_SYN, + REFRESH_TYPE_MANUAL, + DATABASE_NAME_DEFAULT, + TABLE_NAME_1, + STATUS_DEL, +} from '../../utils/flint-datasources/panel_constants'; + +Cypress.on('uncaught:exception', (err, runnable) => { + if (err.message.includes('ResizeObserver loop completed with undelivered notifications')) { + return false; + } +}); + +const goToAccelerationTable = () => { + cy.visit(`${Cypress.env('opensearchDashboards')}/app/datasources`); + cy.get('h1[data-test-subj="dataconnections-header"]').should('be.visible'); + cy.get('a[data-test-subj="mys3DataConnectionsLink"]').click(); + cy.get('button#acceleration_table').click(); +}; + +describe('Acceleration Table test', () => { + beforeEach(() => { + // Load the catalog cache data + const catalogCachePath = './.cypress/utils/flint-datasources/catalog-cache.json'; + cy.readFile(catalogCachePath).then((cache) => { + cy.visit(`${Cypress.env('opensearchDashboards')}`, { + onBeforeLoad: (win) => { + win.localStorage.setItem('async-query-catalog-cache', JSON.stringify(cache)); + }, + }); + }); + + // Load the accelerations cache data + const accelerationCachePath = './.cypress/utils/flint-datasources/accelerations-cache.json'; + cy.readFile(accelerationCachePath).then((cache) => { + cy.visit(`${Cypress.env('opensearchDashboards')}`, { + onBeforeLoad: (win) => { + win.localStorage.setItem('async-query-acclerations-cache', JSON.stringify(cache)); + }, + }); + }); + }); + + afterEach(() => { + cy.clearLocalStorage('async-query-catalog-cache'); + cy.clearLocalStorage('async-query-acclerations-cache'); + }); + + it('Navigates to Acceleration table and check header elements', () => { + goToAccelerationTable(); + + cy.contains('.euiFlexItem .euiText.euiText--medium', ACC_TABLE_TITLE).should( + 'contain.text', + ACC_TABLE_DESC + ); + + cy.contains('.euiTextColor--subdued', UPDATE_AT_DESC).should('exist'); + cy.contains('.euiTextColor--subdued', LOCALIZED_UPDATE_TIMESTAMP_ACC).should('exist'); + + cy.contains('.euiButton--primary', REFRESH_BTN_DESC).should('exist'); + cy.contains('.euiButton--primary.euiButton--fill', CREATE_ACC_BTN_DESC).should('exist'); + }); + + it('Navigates to Acceleration table and check table columns', () => { + goToAccelerationTable(); + + cy.get('th[data-test-subj="tableHeaderCell_indexName_0"]') + .contains('span', ACC_NAME) + .should('exist'); + + cy.get('th[data-test-subj="tableHeaderCell_status_1"]') + .contains('span', ACC_STATUS) + .should('exist'); + + cy.get('th[data-test-subj="tableHeaderCell_type_2"]') + .contains('span', ACC_TYPE) + .should('exist'); + + cy.get('th[data-test-subj="tableHeaderCell_database_3"]') + .contains('span', ACC_DATABASE) + .should('exist'); + + cy.get('th[data-test-subj="tableHeaderCell_table_4"]') + .contains('span', ACC_TABLE) + .should('exist'); + + cy.get('th[data-test-subj="tableHeaderCell_refreshType_5"]') + .contains('span', ACC_REFRESH_TYPE) + .should('exist'); + + cy.get('th[data-test-subj="tableHeaderCell_flintIndexName_6"]') + .contains('span', ACC_DESTINATION_INDEX) + .should('exist'); + + cy.get('th').contains('span[title="Actions"]', ACC_ACTIONS_COL).should('exist'); + }); + + it('Checks rows for "Materialized View" type and verifies table column content', () => { + goToAccelerationTable(); + + cy.get('tbody') + .find('tr') + .each(($row) => { + cy.wrap($row) + .find('td') + .eq(2) + .invoke('text') + .then((text) => { + if (text.includes(TYPE_MV)) { + cy.wrap($row).find('td').eq(4).should('contain.text', EMPTY_CONTENT); + } + }); + }); + }); + + it('Checks rows for "Skipping index" type and verifies Destination Index column content', () => { + goToAccelerationTable(); + + cy.get('tbody') + .find('tr') + .each(($row) => { + cy.wrap($row) + .find('td') + .eq(2) + .invoke('text') + .then((text) => { + if (text.includes(TYPE_SI)) { + cy.wrap($row).find('td').eq(6).should('contain.text', EMPTY_CONTENT); + } + }); + }); + }); + + it('Verifies Sync is enabled and Vacuum is disabled for specific row', () => { + goToAccelerationTable(); + + cy.get('tbody tr').contains('td', ACTIVE_MV_NAME).parent('tr').as('selectedRow'); + + cy.get('@selectedRow').find('td').eq(2).contains('div', TYPE_MV).should('exist'); + + cy.get('@selectedRow').find('td').eq(5).contains('div', REFRESH_TYPE_MANUAL).should('exist'); + + cy.get('@selectedRow').find('[data-test-subj="euiCollapsedItemActionsButton"]').click(); + + cy.get('.euiContextMenuPanel') + .should('be.visible') + .within(() => { + cy.contains('button', ACTION_ICON_SYN).should('be.visible').and('not.be.disabled'); + }); + + cy.get('.euiContextMenuPanel').within(() => { + cy.contains('button', ACTION_ICON_DEL).should('be.visible').and('not.be.disabled'); + }); + + cy.get('.euiContextMenuPanel').within(() => { + cy.contains('button', ACTION_ICON_VAC).should('be.visible').and('be.disabled'); + }); + + cy.get('body').click(0, 0); + }); + + it('Verifies actions for rows with specific criteria and ensures menu interaction', () => { + goToAccelerationTable(); + let criteriaMet = false; + + cy.get('tbody tr') + .each(($row) => { + const name = $row.find('td:eq(0) .euiLink').text().trim(); + const database = $row.find('td:eq(3) .euiText--small').text().trim(); + const table = $row.find('td:eq(4) .euiText--small').text().trim(); + const statusText = $row.find('td:eq(1) .euiHealth').text().trim(); + + cy.log( + `Extracted -> Name: '${name}', Database: '${database}', Table: '${table}', Status: '${statusText}'` + ); + + if ( + name === SKIP_INDEX_NAME && + database === DATABASE_NAME_DEFAULT && + table === TABLE_NAME_1 && + statusText.includes(STATUS_DEL) + ) { + criteriaMet = true; + console.log('Found row matching criteria'); + cy.wrap($row) + .find('[data-test-subj="euiCollapsedItemActionsButton"]') + .should('exist') + .click({ force: true }); + + cy.get('.euiContextMenuPanel') + .should('be.visible') + .within(() => { + cy.contains('button', ACTION_ICON_SYN).should('exist').and('be.disabled'); + cy.contains('button', ACTION_ICON_DEL).should('exist').and('be.disabled'); + cy.contains('button', ACTION_ICON_VAC).should('exist').and('not.be.disabled'); + }); + + cy.get('body').click(0, 0); + + return false; + } + }) + .then(() => { + expect(criteriaMet, 'Failed to find a row matching the specified criteria').to.be.true; + }); + }); +}); diff --git a/.cypress/integration/flint_datasources/associated_object_table.spec.js b/.cypress/integration/flint_datasources/associated_object_table.spec.js new file mode 100644 index 0000000000..b35cdaa5ca --- /dev/null +++ b/.cypress/integration/flint_datasources/associated_object_table.spec.js @@ -0,0 +1,171 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// + +import { + ASSO_TABLE_CALLOUT, + ASSO_TABLE_TITTLE, + ASSO_HEADER_DESC, + UPDATE_AT_DESC, + LOCALIZED_UPDATE_TIMESTAMP_AO, + REFRESH_BTN_DESC, + CREATE_ACC_BTN_DESC, + ASSO_NAME_COL, + ASSO_TYPE_COL, + ASSO_ACC_COL, + ASSO_ACTION_COL, + TABLE_NAME_1, + ACTION_ICON_DIS, + ACTION_ICON_ACC, + AO_TYPE_TABLE, + ASSO_TABLE_FILTER, + SKIP_INDEX_NAME, + ASSO_SEARCH_BAR_DEFAULT_INPUT, + ASSO_SEARCH_BAR_FILTER_INPUT, +} from '../../utils/flint-datasources/panel_constants'; + +Cypress.on('uncaught:exception', (err, runnable) => { + if (err.message.includes('ResizeObserver loop completed with undelivered notifications')) { + return false; + } +}); + +const goToAssociatedObjectTable = () => { + cy.visit(`${Cypress.env('opensearchDashboards')}/app/datasources`); + cy.get('h1[data-test-subj="dataconnections-header"]').should('be.visible'); + cy.get('a[data-test-subj="mys3DataConnectionsLink"]').click(); +}; + +describe('Associated Object Table test', () => { + beforeEach(() => { + // Load the catalog cache data + const catalogCachePath = './.cypress/utils/flint-datasources/catalog-cache.json'; + cy.readFile(catalogCachePath).then((cache) => { + cy.visit(`${Cypress.env('opensearchDashboards')}`, { + onBeforeLoad: (win) => { + win.localStorage.setItem('async-query-catalog-cache', JSON.stringify(cache)); + }, + }); + }); + + // Load the accelerations cache data + const accelerationCachePath = './.cypress/utils/flint-datasources/accelerations-cache.json'; + cy.readFile(accelerationCachePath).then((cache) => { + cy.visit(`${Cypress.env('opensearchDashboards')}`, { + onBeforeLoad: (win) => { + win.localStorage.setItem('async-query-acclerations-cache', JSON.stringify(cache)); + }, + }); + }); + }); + + afterEach(() => { + cy.clearLocalStorage('async-query-catalog-cache'); + cy.clearLocalStorage('async-query-acclerations-cache'); + }); + + it('Navigates to Associated objects table and check callout', () => { + goToAssociatedObjectTable(); + + cy.get('div.euiCallOut.euiCallOut--primary').should('exist'); + + cy.get('div.euiCallOut.euiCallOut--primary') + .find('span.euiCallOutHeader__title') + .contains(ASSO_TABLE_CALLOUT) + .should('exist'); + }); + + it('Navigates to Associated objects table and check header elements', () => { + goToAssociatedObjectTable(); + + cy.contains('.euiFlexItem .euiText.euiText--medium', ASSO_TABLE_TITTLE).should( + 'contain.text', + ASSO_HEADER_DESC + ); + + cy.contains('.euiTextColor--subdued', UPDATE_AT_DESC).should('exist'); + cy.contains('.euiTextColor--subdued', LOCALIZED_UPDATE_TIMESTAMP_AO).should('exist'); + + cy.contains('.euiButton--primary', REFRESH_BTN_DESC).should('exist'); + cy.contains('.euiButton--primary.euiButton--fill', CREATE_ACC_BTN_DESC).should('exist'); + }); + + it('Navigates to Associated objects table and check table elements', () => { + goToAssociatedObjectTable(); + + cy.contains('.euiTableCellContent__text', ASSO_NAME_COL) + .as('NameHeader') + .should('exist') + .parent() + .find('svg.euiIcon--medium.euiTableSortIcon') + .should('exist'); + + cy.contains('.euiTableCellContent__text', ASSO_TYPE_COL).should('exist'); + + cy.contains('.euiTableCellContent__text', ASSO_ACC_COL).should('exist'); + + cy.contains('.euiTableCellContent__text', ASSO_ACTION_COL) + .as('ActionsHeader') + .should('exist') + .parents('.euiTableCellContent') + .should('have.class', 'euiTableCellContent--alignRight'); + }); + + it('Navigates to Associated objects table and check table content', () => { + goToAssociatedObjectTable(); + + cy.get('tr.euiTableRow') + .contains('button', TABLE_NAME_1) + .parents('tr.euiTableRow') + .as('targetRow'); + + cy.get('@targetRow') + .find('td[data-test-subj="nameCell"]') + .contains('button', TABLE_NAME_1) + .should('exist'); + + cy.get('@targetRow').find('td').contains('div', AO_TYPE_TABLE).should('exist'); + + cy.get('@targetRow') + .find('div.euiTableCellContent--alignRight') + .within(() => { + cy.get('button.euiButtonIcon') + .eq(0) + .invoke('attr', 'aria-labelledby') + .then((labelId) => { + cy.get('button.euiButtonIcon').eq(0).should('exist'); + cy.get(`span#${labelId}`).should('have.text', ACTION_ICON_DIS); + }); + + cy.get('button.euiButtonIcon') + .eq(1) + .invoke('attr', 'aria-labelledby') + .then((labelId) => { + cy.get('button.euiButtonIcon').eq(1).should('exist'); + cy.get(`span#${labelId}`).should('have.text', ACTION_ICON_ACC); + }); + }); + }); + + it('Navigates to Associated objects table and check table filter logic', () => { + goToAssociatedObjectTable(); + + cy.contains(`[data-text=${ASSO_TABLE_FILTER}]`, ASSO_TABLE_FILTER).should('be.visible').click(); + + cy.contains('span.euiFlexItem.euiFilterSelectItem__content', SKIP_INDEX_NAME) + .should('be.visible') + .click(); + + cy.get(`input[type="search"][placeholder="${ASSO_SEARCH_BAR_DEFAULT_INPUT}"]`).should( + 'have.value', + ASSO_SEARCH_BAR_FILTER_INPUT + ); + + cy.get('tr.euiTableRow').each(($row) => { + cy.wrap($row).find('td[data-test-subj="nameCell"]').should('contain.text', SKIP_INDEX_NAME); + }); + }); +}); diff --git a/.cypress/utils/flint-datasources/accelerations-cache.json b/.cypress/utils/flint-datasources/accelerations-cache.json new file mode 100644 index 0000000000..67c5b4648c --- /dev/null +++ b/.cypress/utils/flint-datasources/accelerations-cache.json @@ -0,0 +1,120 @@ +{ + "version": "1.0", + "dataSources": [ + { + "name": "mys3", + "accelerations": [ + { + "flintIndexName": "flint_mys3_default_http_count_view", + "type": "materialized", + "database": "default", + "table": null, + "indexName": "http_count_view", + "autoRefresh": false, + "status": "active" + }, + { + "flintIndexName": "flint_mys3_default_http_count_view_2", + "type": "materialized", + "database": "default", + "table": null, + "indexName": "http_count_view_2", + "autoRefresh": true, + "status": "refreshing" + }, + { + "flintIndexName": "flint_mys3_default_http_logs_1_skipping_index", + "type": "skipping", + "database": "default", + "table": "http_logs_1", + "indexName": null, + "autoRefresh": false, + "status": "active" + }, + { + "flintIndexName": "flint_mys3_default_http_logs_covering2_index", + "type": "covering", + "database": "default", + "table": "http_logs", + "indexName": "covering2", + "autoRefresh": false, + "status": "active" + }, + { + "flintIndexName": "flint_mys3_default_http_logs_covering_index", + "type": "covering", + "database": "default", + "table": "http_logs", + "indexName": "covering", + "autoRefresh": true, + "status": "active" + }, + { + "flintIndexName": "flint_mys3_default_http_logs_coveringdummy_index", + "type": "covering", + "database": "default", + "table": "http_logs", + "indexName": "coveringdummy", + "autoRefresh": false, + "status": "active" + }, + { + "flintIndexName": "flint_mys3_default_http_logs_cv_1_index", + "type": "covering", + "database": "default", + "table": "http_logs", + "indexName": "cv_1", + "autoRefresh": false, + "status": "active" + }, + { + "flintIndexName": "flint_mys3_default_http_logs_cv_idx_index", + "type": "covering", + "database": "default", + "table": "http_logs", + "indexName": "cv_idx", + "autoRefresh": false, + "status": "active" + }, + { + "flintIndexName": "flint_mys3_default_http_logs_cvcv1_index", + "type": "covering", + "database": "default", + "table": "http_logs", + "indexName": "cvcv1", + "autoRefresh": true, + "status": "refreshing" + }, + { + "flintIndexName": "flint_mys3_default_http_logs_skipping_index", + "type": "skipping", + "database": "default", + "table": "http_logs", + "indexName": null, + "autoRefresh": false, + "status": "deleted" + }, + { + "flintIndexName": "flint_mys3_default_http_logs_status_clientip_and_day_index", + "type": "covering", + "database": "default", + "table": "http_logs", + "indexName": "status_clientip_and_day", + "autoRefresh": true, + "status": "refreshing" + }, + { + "flintIndexName": "flint_mys3_dummy3_default_http_logs_skipping_index", + "type": "skipping", + "database": "default", + "table": "http_logs", + "indexName": null, + "autoRefresh": false, + "status": "unavailable" + } + ], + "lastUpdated": "Thu, 21 Mar 2024 22:01:22 GMT", + "status": "Updated" + } + ] +} diff --git a/.cypress/utils/flint-datasources/catalog-cache.json b/.cypress/utils/flint-datasources/catalog-cache.json new file mode 100644 index 0000000000..64d077350a --- /dev/null +++ b/.cypress/utils/flint-datasources/catalog-cache.json @@ -0,0 +1,31 @@ +{ + "version": "1.0", + "dataSources": [ + { + "name": "mys3", + "lastUpdated": "Thu, 21 Mar 2024 22:01:13 GMT", + "status": "Updated", + "databases": [ + { + "name": "default", + "tables": [ + { + "name": "http_logs" + }, + { + "name": "http_logs_1" + }, + { + "name": "table_no_timestamp" + }, + { + "name": "table_struct" + } + ], + "lastUpdated": "Thu, 21 Mar 2024 22:01:18 GMT", + "status": "Updated" + } + ] + } + ] +} diff --git a/.cypress/utils/flint-datasources/panel_constants.js b/.cypress/utils/flint-datasources/panel_constants.js new file mode 100644 index 0000000000..642ea90ab5 --- /dev/null +++ b/.cypress/utils/flint-datasources/panel_constants.js @@ -0,0 +1,79 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +// Associated Object Table Callout +export const ASSO_TABLE_CALLOUT = + 'Accelerations recommended for tables. Setup acceleration or configure integrations'; + +// Associated Object Table Header +export const ASSO_TABLE_TITTLE = 'Associated objects'; +export const ASSO_HEADER_DESC = 'Manage objects associated with this data sources.'; +export const UPDATE_AT_DESC = 'Last updated at:'; +export const LOCALIZED_UPDATE_TIMESTAMP_AO = '3/21/2024, 3:01:18 PM'; + +export const REFRESH_BTN_DESC = 'Refresh'; +export const CREATE_ACC_BTN_DESC = 'Create acceleration'; + +// Associated Object Table Columns +export const ASSO_NAME_COL = 'Name'; +export const ASSO_TYPE_COL = 'Type'; +export const ASSO_ACC_COL = 'Accelerations'; +export const ASSO_ACTION_COL = 'Actions'; + +// Associated Object Table Filter +export const ASSO_TABLE_FILTER = 'Accelerations'; + +// Associated Object Table Search Bar +export const ASSO_SEARCH_BAR_DEFAULT_INPUT = 'Search for objects'; +export const ASSO_SEARCH_BAR_FILTER_INPUT = 'accelerations:skipping_index'; + +// Acceleration Table Header +export const ACC_TABLE_TITLE = 'Accelerations'; +export const ACC_TABLE_DESC = + 'Accelerations optimize query performance by indexing external data into OpenSearch.'; + +export const LOCALIZED_UPDATE_TIMESTAMP_ACC = '3/21/2024, 3:01:22 PM'; + +// Acceleration Table Columns / Flyout Fields +export const ACC_NAME = 'Name'; +export const ACC_STATUS = 'Status'; +export const ACC_TYPE = 'Type'; +export const ACC_DATABASE = 'Database'; +export const ACC_TABLE = 'Table'; +export const ACC_REFRESH_TYPE = 'Refresh Type'; +export const ACC_DESTINATION_INDEX = 'Destination Index'; +export const ACC_ACTIONS_COL = 'Actions'; + +// Acceleration Types +export const TYPE_MV = 'Materialized View'; +export const TYPE_SI = 'Skipping Index'; +export const TYPE_CI = 'Covering Index'; + +// Acceleration Status +export const STATUS_ACT = 'Active'; +export const STATUS_REF = 'Refreshing'; +export const STATUS_DEL = 'Deleted'; + +// Acceleration Refresh Types +export const REFRESH_TYPE_AUTO = 'Auto refresh'; +export const REFRESH_TYPE_MANUAL = 'Manual'; + +// Table Actions +export const ACTION_ICON_DIS = 'Discover'; +export const ACTION_ICON_ACC = 'Accelerate'; +export const ACTION_ICON_DEL = 'Delete'; +export const ACTION_ICON_VAC = 'Vacuum'; +export const ACTION_ICON_SYN = 'Sync'; + +// Table Content +export const EMPTY_CONTENT = '-'; +export const DATABASE_NAME_DEFAULT = 'default'; +export const TABLE_NAME_1 = 'http_logs'; +export const TABLE_NAME_2 = 'http_logs_1'; +export const TABLE_NAME_3 = 'table_no_timestamp'; +export const TABLE_NAME_4 = 'table_struct'; +export const AO_TYPE_TABLE = 'Table'; +export const SKIP_INDEX_NAME = 'skipping_index'; +export const ACTIVE_MV_NAME = 'http_count_view';