From db0dd47e445fa8bc03a08c87d3320bf452c6b4ec Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 25 Oct 2024 17:38:07 +0200 Subject: [PATCH] adds functional test for log rate analysis embeddable --- ...g_rate_analysis_embeddable_initializer.tsx | 3 +- x-pack/test/functional/apps/aiops/index.ts | 1 + .../log_rate_analysis_dashboard_embeddable.ts | 104 +++++++++++++++++ .../services/aiops/dashboard_embeddables.ts | 110 ++++++++++++++++++ .../test/functional/services/aiops/index.ts | 3 + .../services/aiops/log_rate_analysis_page.ts | 16 +++ 6 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 x-pack/test/functional/apps/aiops/log_rate_analysis_dashboard_embeddable.ts create mode 100644 x-pack/test/functional/services/aiops/dashboard_embeddables.ts diff --git a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/log_rate_analysis_embeddable_initializer.tsx b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/log_rate_analysis_embeddable_initializer.tsx index 0421add5f021e..bf53f07677739 100644 --- a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/log_rate_analysis_embeddable_initializer.tsx +++ b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/log_rate_analysis_embeddable_initializer.tsx @@ -153,7 +153,7 @@ export const LogRateAnalysisEmbeddableInitializer: FC< - + { setDataViewId(newId ?? ''); }} + data-test-subj="aiopsLogRateAnalysisEmbeddableDataViewSelector" /> {isDataViewTimeBased === false && ( <> diff --git a/x-pack/test/functional/apps/aiops/index.ts b/x-pack/test/functional/apps/aiops/index.ts index 8706d3d242c6b..75ad41f2e21fb 100644 --- a/x-pack/test/functional/apps/aiops/index.ts +++ b/x-pack/test/functional/apps/aiops/index.ts @@ -31,6 +31,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./log_rate_analysis')); loadTestFile(require.resolve('./log_rate_analysis_anomaly_table')); + loadTestFile(require.resolve('./log_rate_analysis_dashboard_embeddable')); loadTestFile(require.resolve('./change_point_detection')); loadTestFile(require.resolve('./log_pattern_analysis')); loadTestFile(require.resolve('./log_pattern_analysis_in_discover')); diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis_dashboard_embeddable.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis_dashboard_embeddable.ts new file mode 100644 index 0000000000000..331a89821335d --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis_dashboard_embeddable.ts @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EMBEDDABLE_LOG_RATE_ANALYSIS_TYPE } from '@kbn/aiops-log-rate-analysis/constants'; + +import { FtrProviderContext } from '../../ftr_provider_context'; +import { logRateAnalysisTestData } from './log_rate_analysis_test_data'; + +const testDataSetup = logRateAnalysisTestData[0]; +const testDataPanel = { + type: 'testData', + suiteSuffix: 'with multi metric job', + panelTitle: `AIOps log rate analysis for ${testDataSetup.sourceIndexOrSavedSearch}`, + dashboardTitle: `AIOps log rate analysis for ${ + testDataSetup.sourceIndexOrSavedSearch + } ${Date.now()}`, +}; +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects([ + 'common', + 'console', + 'dashboard', + 'header', + 'home', + 'security', + 'timePicker', + ]); + const aiops = getService('aiops'); + + // AIOps / Log Rate Analysis lives in the ML UI so we need some related services. + const ml = getService('ml'); + + const from = 'Apr 16, 2023 @ 00:39:02.912'; + const to = 'Jun 15, 2023 @ 21:45:26.749'; + + describe('log rate analysis in dashboard', function () { + before(async () => { + await aiops.logRateAnalysisDataGenerator.generateData(testDataSetup.dataGenerator); + + await ml.testResources.setKibanaTimeZoneToUTC(); + + await ml.securityUI.loginAsMlPowerUser(); + await ml.testResources.createDataViewIfNeeded( + testDataSetup.sourceIndexOrSavedSearch, + '@timestamp' + ); + + await PageObjects.common.setTime({ from, to }); + }); + + after(async () => { + await ml.testResources.deleteDataViewByTitle(testDataSetup.sourceIndexOrSavedSearch); + await aiops.logRateAnalysisDataGenerator.removeGeneratedData(testDataSetup.dataGenerator); + await PageObjects.common.unsetTime(); + }); + + describe(testDataPanel.suiteSuffix, function () { + before(async () => { + await PageObjects.dashboard.navigateToApp(); + }); + + after(async () => { + await ml.testResources.deleteDashboardByTitle(testDataPanel.dashboardTitle); + }); + + it('should open initializer flyout', async () => { + await PageObjects.dashboard.clickNewDashboard(); + await aiops.dashboardEmbeddables.assertDashboardIsEmpty(); + await aiops.dashboardEmbeddables.openEmbeddableInitializer( + EMBEDDABLE_LOG_RATE_ANALYSIS_TYPE + ); + }); + + it('should select data view', async () => { + await aiops.dashboardEmbeddables.assertLogRateAnalysisEmbeddableDataViewSelectorExists(); + await aiops.dashboardEmbeddables.selectLogRateAnalysisEmbeddableDataView( + testDataSetup.sourceIndexOrSavedSearch + ); + }); + + it('should create new log rate analysis panel', async () => { + await aiops.dashboardEmbeddables.clickLogRateAnalysisInitializerConfirmButtonEnabled(); + await PageObjects.timePicker.pauseAutoRefresh(); + await aiops.dashboardEmbeddables.assertDashboardPanelExists(testDataPanel.panelTitle); + await aiops.logRateAnalysisPage.assertAutoRunButtonExists(); + await PageObjects.dashboard.saveDashboard(testDataPanel.dashboardTitle); + }); + + it('should run log rate analysis', async () => { + await aiops.dashboardEmbeddables.assertDashboardPanelExists(testDataPanel.panelTitle); + await aiops.logRateAnalysisPage.clickAutoRunButton(); + // Wait for the analysis to finish + await aiops.logRateAnalysisPage.assertAnalysisComplete( + testDataSetup.analysisType, + testDataSetup.dataGenerator + ); + }); + }); + }); +} diff --git a/x-pack/test/functional/services/aiops/dashboard_embeddables.ts b/x-pack/test/functional/services/aiops/dashboard_embeddables.ts new file mode 100644 index 0000000000000..a24cec24734da --- /dev/null +++ b/x-pack/test/functional/services/aiops/dashboard_embeddables.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export function AiopsDashboardEmbeddablesProvider({ getService }: FtrProviderContext) { + const comboBox = getService('comboBox'); + const retry = getService('retry'); + const testSubjects = getService('testSubjects'); + const find = getService('find'); + const dashboardAddPanel = getService('dashboardAddPanel'); + + return { + async assertLogRateAnalysisEmbeddableInitializerExists() { + await retry.tryForTime(10 * 1000, async () => { + await testSubjects.existOrFail('aiopsLogRateAnalysisEmbeddableInitializer', { + timeout: 1000, + }); + }); + }, + + async assertLogRateAnalysisEmbeddableInitializerNotExists() { + await retry.tryForTime(10 * 1000, async () => { + await testSubjects.missingOrFail('aiopsLogRateAnalysisEmbeddableInitializer', { + timeout: 1000, + }); + }); + }, + + async assertInitializerConfirmButtonEnabled(subj: string) { + await retry.tryForTime(60 * 1000, async () => { + await testSubjects.existOrFail(subj); + await testSubjects.isEnabled(subj); + }); + }, + + async assertDashboardIsEmpty() { + await retry.tryForTime(60 * 1000, async () => { + await testSubjects.existOrFail('emptyDashboardWidget'); + }); + }, + + async assertDashboardPanelExists(title: string) { + await retry.tryForTime(5000, async () => { + await find.existsByLinkText(title); + }); + }, + + async assertLogsAiopsSectionExists(expectExist = true) { + await retry.tryForTime(60 * 1000, async () => { + await dashboardAddPanel.clickEditorMenuButton(); + await dashboardAddPanel.verifyEmbeddableFactoryGroupExists('logs-aiops', expectExist); + }); + }, + + async clickLogRateAnalysisInitializerConfirmButtonEnabled() { + const subj = 'aiopsLogRateAnalysisConfirmButton'; + await retry.tryForTime(60 * 1000, async () => { + await this.assertInitializerConfirmButtonEnabled(subj); + await testSubjects.clickWhenNotDisabledWithoutRetry(subj); + await this.assertLogRateAnalysisEmbeddableInitializerNotExists(); + }); + }, + + async openEmbeddableInitializer(mlEmbeddableType: 'aiopsLogRateAnalysisEmbeddable') { + const name = { + aiopsLogRateAnalysisEmbeddable: 'Log rate analysis', + }; + await retry.tryForTime(60 * 1000, async () => { + await dashboardAddPanel.clickEditorMenuButton(); + await testSubjects.existOrFail('dashboardPanelSelectionFlyout', { timeout: 2000 }); + + await dashboardAddPanel.verifyEmbeddableFactoryGroupExists('logs-aiops'); + + await dashboardAddPanel.clickAddNewPanelFromUIActionLink(name[mlEmbeddableType]); + await testSubjects.existOrFail('aiopsLogRateAnalysisControls', { timeout: 2000 }); + }); + }, + + async assertLogRateAnalysisEmbeddableDataViewSelectorExists() { + await testSubjects.existOrFail( + 'aiopsLogRateAnalysisEmbeddableDataViewSelector > comboBoxInput' + ); + }, + + async assertLogRateAnalysisEmbeddableDataViewSelection(dataViewValue: string) { + const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( + 'aiopsLogRateAnalysisEmbeddableDataViewSelector > comboBoxInput' + ); + expect(comboBoxSelectedOptions).to.eql( + [dataViewValue], + `Expected data view selection to be '${dataViewValue}' (got '${comboBoxSelectedOptions}')` + ); + }, + + async selectLogRateAnalysisEmbeddableDataView(dataViewValue: string) { + await comboBox.set( + 'aiopsLogRateAnalysisEmbeddableDataViewSelector > comboBoxInput', + dataViewValue + ); + await this.assertLogRateAnalysisEmbeddableDataViewSelection(dataViewValue); + }, + }; +} diff --git a/x-pack/test/functional/services/aiops/index.ts b/x-pack/test/functional/services/aiops/index.ts index 71de8c397c073..39abf21375f86 100644 --- a/x-pack/test/functional/services/aiops/index.ts +++ b/x-pack/test/functional/services/aiops/index.ts @@ -7,6 +7,7 @@ import type { FtrProviderContext } from '../../ftr_provider_context'; +import { AiopsDashboardEmbeddablesProvider } from './dashboard_embeddables'; import { LogRateAnalysisPageProvider } from './log_rate_analysis_page'; import { LogRateAnalysisResultsTableProvider } from './log_rate_analysis_results_table'; import { LogRateAnalysisResultsGroupsTableProvider } from './log_rate_analysis_results_groups_table'; @@ -16,6 +17,7 @@ import { ChangePointDetectionPageProvider } from './change_point_detection_page' import { MlTableServiceProvider } from '../ml/common_table_service'; export function AiopsProvider(context: FtrProviderContext) { + const dashboardEmbeddables = AiopsDashboardEmbeddablesProvider(context); const logRateAnalysisPage = LogRateAnalysisPageProvider(context); const logRateAnalysisResultsTable = LogRateAnalysisResultsTableProvider(context); const logRateAnalysisResultsGroupsTable = LogRateAnalysisResultsGroupsTableProvider(context); @@ -27,6 +29,7 @@ export function AiopsProvider(context: FtrProviderContext) { const changePointDetectionPage = ChangePointDetectionPageProvider(context, tableService); return { + dashboardEmbeddables, changePointDetectionPage, logRateAnalysisPage, logRateAnalysisResultsTable, diff --git a/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts b/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts index 66c4e64f05efe..0f7b14e3e8be7 100644 --- a/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts +++ b/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts @@ -266,6 +266,22 @@ export function LogRateAnalysisPageProvider({ getService, getPageObject }: FtrPr ); }, + async clickAutoRunButton() { + await testSubjects.clickWhenNotDisabledWithoutRetry( + 'aiopsLogRateAnalysisContentRunAnalysisButton' + ); + + await retry.tryForTime(30 * 1000, async () => { + await testSubjects.missingOrFail('aiopsLogRateAnalysisContentRunAnalysisButton'); + }); + }, + + async assertAutoRunButtonExists() { + await retry.tryForTime(5000, async () => { + await testSubjects.existOrFail('aiopsLogRateAnalysisContentRunAnalysisButton'); + }); + }, + async assertNoAutoRunButtonExists() { await testSubjects.existOrFail('aiopsLogRateAnalysisNoAutoRunContentRunAnalysisButton'); },