From 4dc27867a9758a6f08bde018f6cf2cc4223bebda Mon Sep 17 00:00:00 2001 From: Quynh Nguyen Date: Wed, 27 Oct 2021 17:30:18 -0500 Subject: [PATCH 1/5] [ML] Add tests for anomaly charts embeddable migrations --- .../anomaly_charts_dashboard_embeddables.ts | 57 +++++++++++++++++-- .../functional/services/ml/test_resources.ts | 13 +++++ 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/x-pack/test/functional/apps/ml/embeddables/anomaly_charts_dashboard_embeddables.ts b/x-pack/test/functional/apps/ml/embeddables/anomaly_charts_dashboard_embeddables.ts index 1c47893dbafd0..0b2529d38db31 100644 --- a/x-pack/test/functional/apps/ml/embeddables/anomaly_charts_dashboard_embeddables.ts +++ b/x-pack/test/functional/apps/ml/embeddables/anomaly_charts_dashboard_embeddables.ts @@ -42,6 +42,7 @@ const testDataList = [ panelTitle: `ML anomaly charts for ${JOB_CONFIG.job_id}`, jobConfig: JOB_CONFIG, datafeedConfig: DATAFEED_CONFIG, + dashboardTitle: `ML anomaly charts for fq_multi_1_ae ${Date.now()}`, expected: { influencers: [ { @@ -59,7 +60,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const ml = getService('ml'); const PageObjects = getPageObjects(['common', 'timePicker', 'dashboard']); - describe('anomaly charts', function () { + describe('anomaly charts in dashboard', function () { this.tags(['mlqa']); before(async () => { @@ -69,6 +70,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await ml.securityUI.loginAsMlPowerUser(); }); + after(async () => { + await ml.api.cleanMlIndices(); + }); + for (const testData of testDataList) { describe(testData.suiteSuffix, function () { before(async () => { @@ -79,12 +84,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToApp('dashboard'); }); - after(async () => { - await ml.api.cleanMlIndices(); - }); - it('can open job selection flyout', async () => { - await PageObjects.dashboard.clickCreateDashboardPrompt(); + await PageObjects.dashboard.clickNewDashboard(); await ml.dashboardEmbeddables.assertDashboardIsEmpty(); await ml.dashboardEmbeddables.openJobSelectionFlyout(); }); @@ -109,8 +110,52 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.timePicker.pauseAutoRefresh(); await ml.dashboardEmbeddables.assertAnomalyChartsSeverityThresholdControlExists(); await ml.dashboardEmbeddables.assertAnomalyChartsExists(); + await PageObjects.dashboard.saveDashboard(testData.dashboardTitle); }); }); } + + describe('supports migrations', function () { + const panelTitle = `Saved ML anomaly charts for fq_multi_1_ae`; + const dashboardSavedObject = { + attributes: { + title: `ML anomaly charts 7.15 dashboard ${Date.now()}`, + description: '', + panelsJSON: `[{"version":"7.15.2","type":"ml_anomaly_charts","gridData":{"x":0,"y":0,"w":36,"h":20,"i":"ffcdb1ed-0079-41ee-8dda-3f6c138182ab"},"panelIndex":"ffcdb1ed-0079-41ee-8dda-3f6c138182ab","embeddableConfig":{"jobIds":["fq_multi_1_ae"],"maxSeriesToPlot":6,"severityThreshold":0,"enhancements":{}},"title":"${panelTitle}"}]`, + optionsJSON: '{"useMargins":true,"syncColors":false,"hidePanelTitles":false}', + timeRestore: true, + timeTo: '2016-02-11T00:00:00.000Z', + timeFrom: '2016-02-07T00:00:00.000Z', + refreshInterval: { + pause: true, + value: 0, + }, + kibanaSavedObjectMeta: { + searchSourceJSON: '{"query":{"query":"","language":"kuery"},"filter":[]}', + }, + }, + coreMigrationVersion: '7.15.2', + }; + + before(async () => { + await ml.testResources.createDashboardSavedObject( + dashboardSavedObject.attributes.title, + dashboardSavedObject + ); + await PageObjects.common.navigateToApp('dashboard'); + }); + + it('loads saved dashboard from version 7.15', async () => { + await PageObjects.dashboard.loadSavedDashboard(dashboardSavedObject.attributes.title); + await ml.dashboardEmbeddables.assertDashboardPanelExists(panelTitle); + await PageObjects.timePicker.setAbsoluteRange( + 'Feb 7, 2016 @ 00:00:00.000', + 'Feb 11, 2016 @ 00:00:00.000' + ); + await PageObjects.timePicker.pauseAutoRefresh(); + await ml.dashboardEmbeddables.assertAnomalyChartsSeverityThresholdControlExists(); + await ml.dashboardEmbeddables.assertAnomalyChartsExists(); + }); + }); }); } diff --git a/x-pack/test/functional/services/ml/test_resources.ts b/x-pack/test/functional/services/ml/test_resources.ts index 65a892d124edb..129ef223b6a1f 100644 --- a/x-pack/test/functional/services/ml/test_resources.ts +++ b/x-pack/test/functional/services/ml/test_resources.ts @@ -128,6 +128,19 @@ export function MachineLearningTestResourcesProvider({ getService }: FtrProvider return createResponse.id; }, + async createDashboardSavedObject(title: string, body: object): Promise { + log.debug(`Creating dashboard with title '${title}'`); + + const createResponse = await supertest + .post(`/api/saved_objects/${SavedObjectType.DASHBOARD}`) + .set(COMMON_REQUEST_HEADERS) + .send(body) + .then((res: any) => res.body); + + log.debug(` > Created with id '${createResponse.id}'`); + return createResponse.id; + }, + async createIndexPatternIfNeeded(title: string, timeFieldName?: string): Promise { const indexPatternId = await this.getIndexPatternId(title); if (indexPatternId !== undefined) { From eee3561c7c72a1cd85b7c65f4abc412935bd366f Mon Sep 17 00:00:00 2001 From: Quynh Nguyen Date: Mon, 1 Nov 2021 16:00:08 -0500 Subject: [PATCH 2/5] [ML] Broaden tests for anomaly swimlane as well --- .../anomaly_charts_dashboard_embeddables.ts | 78 +---------- .../anomaly_embeddables_migration.ts | 121 ++++++++++++++++++ .../apps/ml/embeddables/constants.ts | 41 ++++++ .../functional/apps/ml/embeddables/index.ts | 1 + .../services/ml/dashboard_embeddables.ts | 12 +- .../functional/services/ml/test_resources.ts | 8 +- 6 files changed, 184 insertions(+), 77 deletions(-) create mode 100644 x-pack/test/functional/apps/ml/embeddables/anomaly_embeddables_migration.ts create mode 100644 x-pack/test/functional/apps/ml/embeddables/constants.ts diff --git a/x-pack/test/functional/apps/ml/embeddables/anomaly_charts_dashboard_embeddables.ts b/x-pack/test/functional/apps/ml/embeddables/anomaly_charts_dashboard_embeddables.ts index 0b2529d38db31..66a32a888b77a 100644 --- a/x-pack/test/functional/apps/ml/embeddables/anomaly_charts_dashboard_embeddables.ts +++ b/x-pack/test/functional/apps/ml/embeddables/anomaly_charts_dashboard_embeddables.ts @@ -6,38 +6,11 @@ */ import { FtrProviderContext } from '../../../ftr_provider_context'; -import { Job, Datafeed } from '../../../../../plugins/ml/common/types/anomaly_detection_jobs'; - -// @ts-expect-error not full interface -const JOB_CONFIG: Job = { - job_id: `fq_multi_1_ae`, - description: - 'mean/min/max(responsetime) partition=airline on farequote dataset with 1h bucket span', - groups: ['farequote', 'automated', 'multi-metric'], - analysis_config: { - bucket_span: '1h', - influencers: ['airline'], - detectors: [ - { function: 'mean', field_name: 'responsetime', partition_field_name: 'airline' }, - { function: 'min', field_name: 'responsetime', partition_field_name: 'airline' }, - { function: 'max', field_name: 'responsetime', partition_field_name: 'airline' }, - ], - }, - data_description: { time_field: '@timestamp' }, - analysis_limits: { model_memory_limit: '20mb' }, - model_plot_config: { enabled: true }, -}; - -// @ts-expect-error not full interface -const DATAFEED_CONFIG: Datafeed = { - datafeed_id: 'datafeed-fq_multi_1_ae', - indices: ['ft_farequote'], - job_id: 'fq_multi_1_ae', - query: { bool: { must: [{ match_all: {} }] } }, -}; +import { JOB_CONFIG, DATAFEED_CONFIG, ML_EMBEDDABLE_TYPES } from './constants'; const testDataList = [ { + type: 'testData', suiteSuffix: 'with multi metric job', panelTitle: `ML anomaly charts for ${JOB_CONFIG.job_id}`, jobConfig: JOB_CONFIG, @@ -87,7 +60,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('can open job selection flyout', async () => { await PageObjects.dashboard.clickNewDashboard(); await ml.dashboardEmbeddables.assertDashboardIsEmpty(); - await ml.dashboardEmbeddables.openJobSelectionFlyout(); + await ml.dashboardEmbeddables.openAnomalyJobSelectionFlyout( + ML_EMBEDDABLE_TYPES.ANOMALY_CHARTS + ); }); it('can select jobs', async () => { @@ -114,48 +89,5 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); } - - describe('supports migrations', function () { - const panelTitle = `Saved ML anomaly charts for fq_multi_1_ae`; - const dashboardSavedObject = { - attributes: { - title: `ML anomaly charts 7.15 dashboard ${Date.now()}`, - description: '', - panelsJSON: `[{"version":"7.15.2","type":"ml_anomaly_charts","gridData":{"x":0,"y":0,"w":36,"h":20,"i":"ffcdb1ed-0079-41ee-8dda-3f6c138182ab"},"panelIndex":"ffcdb1ed-0079-41ee-8dda-3f6c138182ab","embeddableConfig":{"jobIds":["fq_multi_1_ae"],"maxSeriesToPlot":6,"severityThreshold":0,"enhancements":{}},"title":"${panelTitle}"}]`, - optionsJSON: '{"useMargins":true,"syncColors":false,"hidePanelTitles":false}', - timeRestore: true, - timeTo: '2016-02-11T00:00:00.000Z', - timeFrom: '2016-02-07T00:00:00.000Z', - refreshInterval: { - pause: true, - value: 0, - }, - kibanaSavedObjectMeta: { - searchSourceJSON: '{"query":{"query":"","language":"kuery"},"filter":[]}', - }, - }, - coreMigrationVersion: '7.15.2', - }; - - before(async () => { - await ml.testResources.createDashboardSavedObject( - dashboardSavedObject.attributes.title, - dashboardSavedObject - ); - await PageObjects.common.navigateToApp('dashboard'); - }); - - it('loads saved dashboard from version 7.15', async () => { - await PageObjects.dashboard.loadSavedDashboard(dashboardSavedObject.attributes.title); - await ml.dashboardEmbeddables.assertDashboardPanelExists(panelTitle); - await PageObjects.timePicker.setAbsoluteRange( - 'Feb 7, 2016 @ 00:00:00.000', - 'Feb 11, 2016 @ 00:00:00.000' - ); - await PageObjects.timePicker.pauseAutoRefresh(); - await ml.dashboardEmbeddables.assertAnomalyChartsSeverityThresholdControlExists(); - await ml.dashboardEmbeddables.assertAnomalyChartsExists(); - }); - }); }); } diff --git a/x-pack/test/functional/apps/ml/embeddables/anomaly_embeddables_migration.ts b/x-pack/test/functional/apps/ml/embeddables/anomaly_embeddables_migration.ts new file mode 100644 index 0000000000000..e3321ddc93f3a --- /dev/null +++ b/x-pack/test/functional/apps/ml/embeddables/anomaly_embeddables_migration.ts @@ -0,0 +1,121 @@ +/* + * 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 { FtrProviderContext } from '../../../ftr_provider_context'; +import { JOB_CONFIG, DATAFEED_CONFIG, ML_EMBEDDABLE_TYPES } from './constants'; + +const testDataList = [ + { + type: ML_EMBEDDABLE_TYPES.ANOMALY_SWIMLANE, + panelTitle: 'ML anomaly swim lane', + dashboardSavedObject: { + attributes: { + title: `7.15.2 ML anomaly swimlane dashboard ${Date.now()}`, + description: '', + panelsJSON: `[{"version":"7.15.2","type":"ml_anomaly_swimlane","gridData":{"x":0,"y":0,"w":24,"h":15,"i":"c177ed0a-dea0-40f8-8980-cfb0c6bc13a8"},"panelIndex":"c177ed0a-dea0-40f8-8980-cfb0c6bc13a8","embeddableConfig":{"jobIds":["fq_multi_1_ae"],"swimlaneType":"viewBy","viewBy":"airline","enhancements":{}},"title":"ML anomaly swim lane"}]`, + optionsJSON: '{"useMargins":true,"syncColors":false,"hidePanelTitles":false}', + timeRestore: true, + timeTo: '2016-02-11T00:00:00.000Z', + timeFrom: '2016-02-07T00:00:00.000Z', + refreshInterval: { + pause: true, + value: 0, + }, + kibanaSavedObjectMeta: { + searchSourceJSON: '{"query":{"query":"","language":"kuery"},"filter":[]}', + }, + }, + coreMigrationVersion: '7.15.2', + }, + }, + { + type: ML_EMBEDDABLE_TYPES.ANOMALY_CHARTS, + panelTitle: 'ML anomaly charts', + dashboardSavedObject: { + attributes: { + title: `7.15.2 ML anomaly charts dashboard ${Date.now()}`, + description: '', + panelsJSON: + '[{"version":"7.15.2","type":"ml_anomaly_charts","gridData":{"x":0,"y":0,"w":38,"h":21,"i":"1155890b-c19c-4d98-8153-50e6434612f1"},"panelIndex":"1155890b-c19c-4d98-8153-50e6434612f1","embeddableConfig":{"jobIds":["fq_multi_1_ae"],"maxSeriesToPlot":6,"severityThreshold":0,"enhancements":{}},"title":"ML anomaly charts"}]', + optionsJSON: '{"useMargins":true,"syncColors":false,"hidePanelTitles":false}', + timeRestore: true, + timeTo: '2016-02-11T00:00:00.000Z', + timeFrom: '2016-02-07T00:00:00.000Z', + refreshInterval: { + pause: true, + value: 0, + }, + kibanaSavedObjectMeta: { + searchSourceJSON: '{"query":{"query":"","language":"kuery"},"filter":[]}', + }, + }, + coreMigrationVersion: '7.15.2', + }, + }, +]; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const ml = getService('ml'); + const PageObjects = getPageObjects(['common', 'timePicker', 'dashboard']); + + describe('anomaly embeddables migration in Dashboard', function () { + this.tags(['mlqa']); + + before(async () => { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); + await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.setKibanaTimeZoneToUTC(); + await ml.securityUI.loginAsMlPowerUser(); + + await ml.api.createAndRunAnomalyDetectionLookbackJob(JOB_CONFIG, DATAFEED_CONFIG); + await PageObjects.common.navigateToApp('dashboard'); + }); + + after(async () => { + await ml.api.cleanMlIndices(); + }); + + for (const testData of testDataList) { + const { dashboardSavedObject, panelTitle, type } = testData; + describe(`loads saved dashboard from version ${dashboardSavedObject.coreMigrationVersion}`, function () { + before(async () => { + await ml.testResources.createDashboardSavedObject( + dashboardSavedObject.attributes.title, + dashboardSavedObject, + true + ); + await PageObjects.common.navigateToApp('dashboard'); + }); + + after(async () => { + await ml.testResources.deleteDashboardByTitle(dashboardSavedObject.attributes.title); + }); + + it(`loads saved dashboard from version ${dashboardSavedObject.coreMigrationVersion}`, async () => { + await PageObjects.dashboard.loadSavedDashboard(dashboardSavedObject.attributes.title); + + await ml.dashboardEmbeddables.assertDashboardPanelExists(panelTitle); + await PageObjects.timePicker.setAbsoluteRange( + 'Feb 7, 2015 @ 00:00:00.000', + 'Feb 11, 2016 @ 00:00:00.000' + ); + await PageObjects.timePicker.pauseAutoRefresh(); + + if (type === ML_EMBEDDABLE_TYPES.ANOMALY_CHARTS) { + await ml.dashboardEmbeddables.assertAnomalyChartsSeverityThresholdControlExists(); + await ml.dashboardEmbeddables.assertAnomalyChartsExists(); + } + + if (type === ML_EMBEDDABLE_TYPES.ANOMALY_SWIMLANE) { + await ml.dashboardEmbeddables.assertAnomalySwimlaneExists(); + } + }); + }); + } + }); +} diff --git a/x-pack/test/functional/apps/ml/embeddables/constants.ts b/x-pack/test/functional/apps/ml/embeddables/constants.ts new file mode 100644 index 0000000000000..f315b7ee44dc8 --- /dev/null +++ b/x-pack/test/functional/apps/ml/embeddables/constants.ts @@ -0,0 +1,41 @@ +/* + * 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 { Datafeed, Job } from '../../../../../plugins/ml/common/types/anomaly_detection_jobs'; + +// @ts-expect-error not full interface +export const JOB_CONFIG: Job = { + job_id: `fq_multi_1_ae`, + description: + 'mean/min/max(responsetime) partition=airline on farequote dataset with 1h bucket span', + groups: ['farequote', 'automated', 'multi-metric'], + analysis_config: { + bucket_span: '1h', + influencers: ['airline'], + detectors: [ + { function: 'mean', field_name: 'responsetime', partition_field_name: 'airline' }, + { function: 'min', field_name: 'responsetime', partition_field_name: 'airline' }, + { function: 'max', field_name: 'responsetime', partition_field_name: 'airline' }, + ], + }, + data_description: { time_field: '@timestamp' }, + analysis_limits: { model_memory_limit: '20mb' }, + model_plot_config: { enabled: true }, +}; + +// @ts-expect-error not full interface +export const DATAFEED_CONFIG: Datafeed = { + datafeed_id: 'datafeed-fq_multi_1_ae', + indices: ['ft_farequote'], + job_id: 'fq_multi_1_ae', + query: { bool: { must: [{ match_all: {} }] } }, +}; + +export const ML_EMBEDDABLE_TYPES = { + ANOMALY_SWIMLANE: 'ml_anomaly_swimlane', + ANOMALY_CHARTS: 'ml_anomaly_charts', +} as const; diff --git a/x-pack/test/functional/apps/ml/embeddables/index.ts b/x-pack/test/functional/apps/ml/embeddables/index.ts index dc059a1862c80..31074a59866a6 100644 --- a/x-pack/test/functional/apps/ml/embeddables/index.ts +++ b/x-pack/test/functional/apps/ml/embeddables/index.ts @@ -11,5 +11,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('embeddables', function () { this.tags(['skipFirefox']); loadTestFile(require.resolve('./anomaly_charts_dashboard_embeddables')); + loadTestFile(require.resolve('./anomaly_embeddables_migration')); }); } diff --git a/x-pack/test/functional/services/ml/dashboard_embeddables.ts b/x-pack/test/functional/services/ml/dashboard_embeddables.ts index 0dc5cc8fae2d5..5c55a16698cb6 100644 --- a/x-pack/test/functional/services/ml/dashboard_embeddables.ts +++ b/x-pack/test/functional/services/ml/dashboard_embeddables.ts @@ -93,13 +93,21 @@ export function MachineLearningDashboardEmbeddablesProvider( }); }, - async openJobSelectionFlyout() { + async assertAnomalySwimlaneExists() { + await retry.tryForTime(60 * 1000, async () => { + await testSubjects.existOrFail(`mlAnomalySwimlaneEmbeddableWrapper`); + }); + }, + + async openAnomalyJobSelectionFlyout( + mlEmbeddableType: 'ml_anomaly_swimlane' | 'ml_anomaly_charts' + ) { await retry.tryForTime(60 * 1000, async () => { await dashboardAddPanel.clickEditorMenuButton(); await testSubjects.existOrFail('dashboardEditorContextMenu', { timeout: 2000 }); await dashboardAddPanel.clickEmbeddableFactoryGroupButton('ml'); - await dashboardAddPanel.clickAddNewEmbeddableLink('ml_anomaly_charts'); + await dashboardAddPanel.clickAddNewEmbeddableLink(mlEmbeddableType); await mlDashboardJobSelectionTable.assertJobSelectionTableExists(); }); diff --git a/x-pack/test/functional/services/ml/test_resources.ts b/x-pack/test/functional/services/ml/test_resources.ts index 129ef223b6a1f..01aa60c0ed9e0 100644 --- a/x-pack/test/functional/services/ml/test_resources.ts +++ b/x-pack/test/functional/services/ml/test_resources.ts @@ -128,11 +128,15 @@ export function MachineLearningTestResourcesProvider({ getService }: FtrProvider return createResponse.id; }, - async createDashboardSavedObject(title: string, body: object): Promise { + async createDashboardSavedObject( + title: string, + body: object, + override = false + ): Promise { log.debug(`Creating dashboard with title '${title}'`); const createResponse = await supertest - .post(`/api/saved_objects/${SavedObjectType.DASHBOARD}`) + .post(`/api/saved_objects/${SavedObjectType.DASHBOARD}?overwrite=${override}`) .set(COMMON_REQUEST_HEADERS) .send(body) .then((res: any) => res.body); From c32274cf330d2c8a20db4ba10a9b0d7004a66fa1 Mon Sep 17 00:00:00 2001 From: Quynh Nguyen Date: Mon, 1 Nov 2021 17:03:35 -0500 Subject: [PATCH 3/5] [ML] Fix function rename --- x-pack/test/accessibility/apps/ml_embeddables_in_dashboard.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/accessibility/apps/ml_embeddables_in_dashboard.ts b/x-pack/test/accessibility/apps/ml_embeddables_in_dashboard.ts index 48224ebcf7353..c9088c650c033 100644 --- a/x-pack/test/accessibility/apps/ml_embeddables_in_dashboard.ts +++ b/x-pack/test/accessibility/apps/ml_embeddables_in_dashboard.ts @@ -95,7 +95,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('can open job selection flyout', async () => { await PageObjects.dashboard.clickCreateDashboardPrompt(); await ml.dashboardEmbeddables.assertDashboardIsEmpty(); - await ml.dashboardEmbeddables.openJobSelectionFlyout(); + await ml.dashboardEmbeddables.openAnomalyJobSelectionFlyout('ml_anomaly_charts'); await a11y.testAppSnapshot(); }); From 7e51b015e16dd3ddfbae904fbb5778f529fa4f37 Mon Sep 17 00:00:00 2001 From: Quynh Nguyen Date: Tue, 2 Nov 2021 10:49:50 -0500 Subject: [PATCH 4/5] [ML] Update tests to use bulk api --- .../anomaly_embeddables_migration.ts | 19 ++++++++----------- .../functional/services/ml/test_resources.ts | 19 ++++++++----------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/x-pack/test/functional/apps/ml/embeddables/anomaly_embeddables_migration.ts b/x-pack/test/functional/apps/ml/embeddables/anomaly_embeddables_migration.ts index e3321ddc93f3a..a7fcfa1b83475 100644 --- a/x-pack/test/functional/apps/ml/embeddables/anomaly_embeddables_migration.ts +++ b/x-pack/test/functional/apps/ml/embeddables/anomaly_embeddables_migration.ts @@ -13,6 +13,7 @@ const testDataList = [ type: ML_EMBEDDABLE_TYPES.ANOMALY_SWIMLANE, panelTitle: 'ML anomaly swim lane', dashboardSavedObject: { + type: 'dashboard', attributes: { title: `7.15.2 ML anomaly swimlane dashboard ${Date.now()}`, description: '', @@ -36,6 +37,7 @@ const testDataList = [ type: ML_EMBEDDABLE_TYPES.ANOMALY_CHARTS, panelTitle: 'ML anomaly charts', dashboardSavedObject: { + type: 'dashboard', attributes: { title: `7.15.2 ML anomaly charts dashboard ${Date.now()}`, description: '', @@ -73,6 +75,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await ml.securityUI.loginAsMlPowerUser(); await ml.api.createAndRunAnomalyDetectionLookbackJob(JOB_CONFIG, DATAFEED_CONFIG); + // Using bulk API because create API might return 400 for conflict errors + await ml.testResources.createBulkSavedObjects( + testDataList.map((d) => d.dashboardSavedObject) + ); + await PageObjects.common.navigateToApp('dashboard'); }); @@ -82,13 +89,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { for (const testData of testDataList) { const { dashboardSavedObject, panelTitle, type } = testData; - describe(`loads saved dashboard from version ${dashboardSavedObject.coreMigrationVersion}`, function () { + describe(`for ${panelTitle}`, function () { before(async () => { - await ml.testResources.createDashboardSavedObject( - dashboardSavedObject.attributes.title, - dashboardSavedObject, - true - ); await PageObjects.common.navigateToApp('dashboard'); }); @@ -100,11 +102,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.loadSavedDashboard(dashboardSavedObject.attributes.title); await ml.dashboardEmbeddables.assertDashboardPanelExists(panelTitle); - await PageObjects.timePicker.setAbsoluteRange( - 'Feb 7, 2015 @ 00:00:00.000', - 'Feb 11, 2016 @ 00:00:00.000' - ); - await PageObjects.timePicker.pauseAutoRefresh(); if (type === ML_EMBEDDABLE_TYPES.ANOMALY_CHARTS) { await ml.dashboardEmbeddables.assertAnomalyChartsSeverityThresholdControlExists(); diff --git a/x-pack/test/functional/services/ml/test_resources.ts b/x-pack/test/functional/services/ml/test_resources.ts index 01aa60c0ed9e0..53223a68c9329 100644 --- a/x-pack/test/functional/services/ml/test_resources.ts +++ b/x-pack/test/functional/services/ml/test_resources.ts @@ -128,21 +128,18 @@ export function MachineLearningTestResourcesProvider({ getService }: FtrProvider return createResponse.id; }, - async createDashboardSavedObject( - title: string, - body: object, - override = false - ): Promise { - log.debug(`Creating dashboard with title '${title}'`); + async createBulkSavedObjects(body: object[]): Promise { + log.debug(`Creating bulk saved objects'`); const createResponse = await supertest - .post(`/api/saved_objects/${SavedObjectType.DASHBOARD}?overwrite=${override}`) + .post(`/api/saved_objects/_bulk_create`) .set(COMMON_REQUEST_HEADERS) .send(body) + .expect(200) .then((res: any) => res.body); - log.debug(` > Created with id '${createResponse.id}'`); - return createResponse.id; + log.debug(` > Created bulk saved objects'`); + return createResponse; }, async createIndexPatternIfNeeded(title: string, timeFieldName?: string): Promise { @@ -175,11 +172,11 @@ export function MachineLearningTestResourcesProvider({ getService }: FtrProvider return createResponse.id; }, - async createDashboard(title: string, body: object): Promise { + async createDashboard(title: string, body: object, override = false): Promise { log.debug(`Creating dashboard with title '${title}'`); const createResponse = await supertest - .post(`/api/saved_objects/${SavedObjectType.DASHBOARD}`) + .post(`/api/saved_objects/${SavedObjectType.DASHBOARD}?override=${override}`) .set(COMMON_REQUEST_HEADERS) .send(body) .expect(200) From 7449472d925a13a1668dc33398f8feda04368996 Mon Sep 17 00:00:00 2001 From: Quynh Nguyen Date: Tue, 2 Nov 2021 14:43:48 -0500 Subject: [PATCH 5/5] [ML] Remove override --- x-pack/test/functional/services/ml/test_resources.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test/functional/services/ml/test_resources.ts b/x-pack/test/functional/services/ml/test_resources.ts index 53223a68c9329..071db63125a55 100644 --- a/x-pack/test/functional/services/ml/test_resources.ts +++ b/x-pack/test/functional/services/ml/test_resources.ts @@ -172,11 +172,11 @@ export function MachineLearningTestResourcesProvider({ getService }: FtrProvider return createResponse.id; }, - async createDashboard(title: string, body: object, override = false): Promise { + async createDashboard(title: string, body: object): Promise { log.debug(`Creating dashboard with title '${title}'`); const createResponse = await supertest - .post(`/api/saved_objects/${SavedObjectType.DASHBOARD}?override=${override}`) + .post(`/api/saved_objects/${SavedObjectType.DASHBOARD}`) .set(COMMON_REQUEST_HEADERS) .send(body) .expect(200)