diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation_saved_search.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation_saved_search.ts new file mode 100644 index 0000000000000..67550ae17a4b0 --- /dev/null +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation_saved_search.ts @@ -0,0 +1,363 @@ +/* + * 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 { AnalyticsTableRowDetails } from '../../../services/ml/data_frame_analytics_table'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const ml = getService('ml'); + const editedDescription = 'Edited description'; + + describe('classification saved search creation', function () { + before(async () => { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote_small'); + await ml.testResources.createIndexPatternIfNeeded('ft_farequote_small', '@timestamp'); + await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded('ft_farequote_small'); + await ml.testResources.createSavedSearchFarequoteKueryIfNeeded('ft_farequote_small'); + await ml.testResources.setKibanaTimeZoneToUTC(); + + await ml.securityUI.loginAsMlPowerUser(); + }); + + after(async () => { + await ml.api.cleanMlIndices(); + await ml.testResources.deleteSavedSearches(); + await ml.testResources.deleteIndexPatternByTitle('ft_farequote_small'); + }); + + const dateNow = Date.now(); + const testDataList = [ + { + suiteTitle: 'with lucene query', + jobType: 'classification', + jobId: `fq_saved_search_2_${dateNow}`, + jobDescription: 'Classification job based on a saved search with lucene query', + source: 'ft_farequote_lucene', + get destinationIndex(): string { + return `user-${this.jobId}`; + }, + runtimeFields: { + uppercase_airline: { + type: 'keyword', + script: 'emit(params._source.airline.toUpperCase())', + }, + }, + dependentVariable: 'airline', + trainingPercent: 20, + modelMemory: '20mb', + createIndexPattern: true, + expected: { + source: 'ft_farequote_small', + rocCurveColorState: [ + // tick/grid/axis + { color: '#DDDDDD', percentage: 38 }, + // line + { color: '#98A2B3', percentage: 7 }, + ], + runtimeFieldsEditorContent: ['{', ' "uppercase_airline": {', ' "type": "keyword",'], + row: { + memoryStatus: 'ok', + type: 'classification', + status: 'stopped', + progress: '100', + }, + rowDetails: { + jobDetails: [ + { + section: 'state', + expectedEntries: { + id: `fq_saved_search_2_${dateNow}`, + state: 'stopped', + data_counts: + '{"training_docs_count":320,"test_docs_count":1284,"skipped_docs_count":0}', + description: 'Classification job based on a saved search with lucene query', + }, + }, + { section: 'progress', expectedEntries: { Phase: '8/8' } }, + ], + } as AnalyticsTableRowDetails, + }, + }, + { + suiteTitle: 'with kuery query', + jobType: 'classification', + jobId: `fq_saved_search_3_${dateNow}`, + jobDescription: 'Classification job based on a saved search with kuery query', + source: 'ft_farequote_kuery', + get destinationIndex(): string { + return `user-${this.jobId}`; + }, + runtimeFields: { + uppercase_airline: { + type: 'keyword', + script: 'emit(params._source.airline.toUpperCase())', + }, + }, + dependentVariable: 'airline', + trainingPercent: 20, + modelMemory: '20mb', + createIndexPattern: true, + expected: { + source: 'ft_farequote_small', + rocCurveColorState: [ + // tick/grid/axis + { color: '#DDDDDD', percentage: 38 }, + // line + { color: '#98A2B3', percentage: 7 }, + ], + runtimeFieldsEditorContent: ['{', ' "uppercase_airline": {', ' "type": "keyword",'], + row: { + memoryStatus: 'ok', + type: 'classification', + status: 'stopped', + progress: '100', + }, + rowDetails: { + jobDetails: [ + { + section: 'state', + expectedEntries: { + id: `fq_saved_search_3_${dateNow}`, + state: 'stopped', + data_counts: + '{"training_docs_count":320,"test_docs_count":1283,"skipped_docs_count":0}', + description: 'Classification job based on a saved search with kuery query', + }, + }, + { section: 'progress', expectedEntries: { Phase: '8/8' } }, + ], + } as AnalyticsTableRowDetails, + }, + }, + ]; + + for (const testData of testDataList) { + describe(`${testData.suiteTitle}`, function () { + after(async () => { + await ml.api.deleteIndices(testData.destinationIndex); + await ml.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + }); + + it('loads the data frame analytics wizard', async () => { + await ml.testExecution.logTestStep('loads the data frame analytics page'); + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToDataFrameAnalytics(); + + await ml.testExecution.logTestStep('loads the source selection modal'); + + // Disable anti-aliasing to stabilize canvas image rendering assertions + await ml.commonUI.disableAntiAliasing(); + + await ml.dataFrameAnalytics.startAnalyticsCreation(); + + await ml.testExecution.logTestStep( + 'selects the source data and loads the job wizard page' + ); + await ml.jobSourceSelection.selectSourceForAnalyticsJob(testData.source); + await ml.dataFrameAnalyticsCreation.assertConfigurationStepActive(); + }); + + it('navigates through the wizard and sets all needed fields', async () => { + await ml.testExecution.logTestStep('selects the job type'); + await ml.dataFrameAnalyticsCreation.assertJobTypeSelectExists(); + await ml.dataFrameAnalyticsCreation.selectJobType(testData.jobType); + + await ml.testExecution.logTestStep('displays the runtime mappings editor switch'); + await ml.dataFrameAnalyticsCreation.assertRuntimeMappingSwitchExists(); + + await ml.testExecution.logTestStep('enables the runtime mappings editor'); + await ml.dataFrameAnalyticsCreation.toggleRuntimeMappingsEditorSwitch(true); + await ml.dataFrameAnalyticsCreation.assertRuntimeMappingsEditorContent(['']); + + await ml.testExecution.logTestStep('sets runtime mappings'); + await ml.dataFrameAnalyticsCreation.setRuntimeMappingsEditorContent( + JSON.stringify(testData.runtimeFields) + ); + await ml.dataFrameAnalyticsCreation.applyRuntimeMappings(); + await ml.dataFrameAnalyticsCreation.assertRuntimeMappingsEditorContent( + testData.expected.runtimeFieldsEditorContent + ); + + await ml.testExecution.logTestStep('inputs the dependent variable'); + await ml.dataFrameAnalyticsCreation.assertDependentVariableInputExists(); + await ml.dataFrameAnalyticsCreation.selectDependentVariable(testData.dependentVariable); + + await ml.testExecution.logTestStep('inputs the training percent'); + await ml.dataFrameAnalyticsCreation.assertTrainingPercentInputExists(); + await ml.dataFrameAnalyticsCreation.setTrainingPercent(testData.trainingPercent); + + await ml.testExecution.logTestStep('displays the source data preview'); + await ml.dataFrameAnalyticsCreation.assertSourceDataPreviewExists(); + + await ml.testExecution.logTestStep('displays the include fields selection'); + await ml.dataFrameAnalyticsCreation.assertIncludeFieldsSelectionExists(); + + await ml.testExecution.logTestStep('continues to the additional options step'); + await ml.dataFrameAnalyticsCreation.continueToAdditionalOptionsStep(); + + await ml.testExecution.logTestStep('accepts the suggested model memory limit'); + await ml.dataFrameAnalyticsCreation.assertModelMemoryInputExists(); + await ml.dataFrameAnalyticsCreation.assertModelMemoryInputPopulated(); + + await ml.testExecution.logTestStep('continues to the details step'); + await ml.dataFrameAnalyticsCreation.continueToDetailsStep(); + + await ml.testExecution.logTestStep('inputs the job id'); + await ml.dataFrameAnalyticsCreation.assertJobIdInputExists(); + await ml.dataFrameAnalyticsCreation.setJobId(testData.jobId); + + await ml.testExecution.logTestStep('inputs the job description'); + await ml.dataFrameAnalyticsCreation.assertJobDescriptionInputExists(); + await ml.dataFrameAnalyticsCreation.setJobDescription(testData.jobDescription); + + await ml.testExecution.logTestStep( + 'should default the set destination index to job id switch to true' + ); + await ml.dataFrameAnalyticsCreation.assertDestIndexSameAsIdSwitchExists(); + await ml.dataFrameAnalyticsCreation.assertDestIndexSameAsIdCheckState(true); + + await ml.testExecution.logTestStep('should input the destination index'); + await ml.dataFrameAnalyticsCreation.setDestIndexSameAsIdCheckState(false); + await ml.dataFrameAnalyticsCreation.assertDestIndexInputExists(); + await ml.dataFrameAnalyticsCreation.setDestIndex(testData.destinationIndex); + + await ml.testExecution.logTestStep('continues to the validation step'); + await ml.dataFrameAnalyticsCreation.continueToValidationStep(); + + await ml.testExecution.logTestStep('checks validation callouts exist'); + await ml.dataFrameAnalyticsCreation.assertValidationCalloutsExists(); + // Expect the follow callouts: + // - ✓ Dependent variable + // - ✓ Training percent + // - ✓ Top classes + // - ⚠ Analysis fields + await ml.dataFrameAnalyticsCreation.assertAllValidationCalloutsPresent(4); + + await ml.testExecution.logTestStep('continues to the create step'); + await ml.dataFrameAnalyticsCreation.continueToCreateStep(); + + await ml.testExecution.logTestStep('sets the create data view switch'); + await ml.dataFrameAnalyticsCreation.assertCreateIndexPatternSwitchExists(); + await ml.dataFrameAnalyticsCreation.setCreateIndexPatternSwitchState( + testData.createIndexPattern + ); + }); + + it('runs the analytics job and displays it correctly in the job list', async () => { + await ml.testExecution.logTestStep('creates and starts the analytics job'); + await ml.dataFrameAnalyticsCreation.assertCreateButtonExists(); + await ml.dataFrameAnalyticsCreation.assertStartJobCheckboxCheckState(true); + await ml.dataFrameAnalyticsCreation.createAnalyticsJob(testData.jobId); + + await ml.testExecution.logTestStep('finishes analytics processing'); + await ml.dataFrameAnalytics.waitForAnalyticsCompletion(testData.jobId); + + await ml.testExecution.logTestStep('displays the analytics table'); + await ml.dataFrameAnalyticsCreation.navigateToJobManagementPage(); + await ml.dataFrameAnalytics.assertAnalyticsTableExists(); + + await ml.testExecution.logTestStep('displays the stats bar'); + await ml.dataFrameAnalytics.assertAnalyticsStatsBarExists(); + + await ml.testExecution.logTestStep('displays the created job in the analytics table'); + await ml.dataFrameAnalyticsTable.refreshAnalyticsTable(); + await ml.dataFrameAnalyticsTable.filterWithSearchString(testData.jobId, 1); + + await ml.testExecution.logTestStep( + 'displays details for the created job in the analytics table' + ); + await ml.dataFrameAnalyticsTable.assertAnalyticsRowFields(testData.jobId, { + id: testData.jobId, + description: testData.jobDescription, + memoryStatus: testData.expected.row.memoryStatus, + sourceIndex: testData.expected.source, + destinationIndex: testData.destinationIndex, + type: testData.expected.row.type, + status: testData.expected.row.status, + progress: testData.expected.row.progress, + }); + + await ml.dataFrameAnalyticsTable.assertAnalyticsRowDetails( + testData.jobId, + testData.expected.rowDetails + ); + }); + + it('edits the analytics job and displays it correctly in the job list', async () => { + await ml.testExecution.logTestStep( + 'should open the edit form for the created job in the analytics table' + ); + await ml.dataFrameAnalyticsTable.openEditFlyout(testData.jobId); + + await ml.testExecution.logTestStep('should input the description in the edit form'); + await ml.dataFrameAnalyticsEdit.assertJobDescriptionEditInputExists(); + await ml.dataFrameAnalyticsEdit.setJobDescriptionEdit(editedDescription); + + await ml.testExecution.logTestStep( + 'should input the model memory limit in the edit form' + ); + await ml.dataFrameAnalyticsEdit.assertJobMmlEditInputExists(); + await ml.dataFrameAnalyticsEdit.setJobMmlEdit('21mb'); + + await ml.testExecution.logTestStep('should submit the edit job form'); + await ml.dataFrameAnalyticsEdit.updateAnalyticsJob(); + + await ml.testExecution.logTestStep( + 'displays details for the edited job in the analytics table' + ); + await ml.dataFrameAnalyticsTable.assertAnalyticsRowFields(testData.jobId, { + id: testData.jobId, + description: editedDescription, + memoryStatus: testData.expected.row.memoryStatus, + sourceIndex: testData.expected.source, + destinationIndex: testData.destinationIndex, + type: testData.expected.row.type, + status: testData.expected.row.status, + progress: testData.expected.row.progress, + }); + + await ml.testExecution.logTestStep( + 'creates the destination index and writes results to it' + ); + await ml.api.assertIndicesExist(testData.destinationIndex); + await ml.api.assertIndicesNotEmpty(testData.destinationIndex); + + await ml.testExecution.logTestStep('displays the results view for created job'); + await ml.dataFrameAnalyticsTable.openResultsView(testData.jobId); + await ml.dataFrameAnalyticsResults.assertClassificationEvaluatePanelElementsExists(); + await ml.dataFrameAnalyticsResults.assertClassificationTablePanelExists(); + await ml.dataFrameAnalyticsResults.assertResultsTableExists(); + await ml.dataFrameAnalyticsResults.assertResultsTableTrainingFiltersExist(); + await ml.dataFrameAnalyticsResults.assertResultsTableNotEmpty(); + + await ml.testExecution.logTestStep('displays the ROC curve chart'); + await ml.commonUI.assertColorsInCanvasElement( + 'mlDFAnalyticsClassificationExplorationRocCurveChart', + testData.expected.rocCurveColorState, + ['#000000'], + undefined, + undefined, + // increased tolerance for ROC curve chart up from 10 to 20 + // since the returned colors vary quite a bit on each run. + 20 + ); + + await ml.commonUI.resetAntiAliasing(); + }); + + it('displays the analytics job in the map view', async () => { + await ml.testExecution.logTestStep('should open the map view for created job'); + await ml.navigation.navigateToDataFrameAnalytics(); + await ml.dataFrameAnalyticsTable.openMapView(testData.jobId); + await ml.dataFrameAnalyticsMap.assertMapElementsExists(); + await ml.dataFrameAnalyticsMap.assertJobMapTitle(testData.jobId); + }); + }); + } + }); +} diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/index.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/index.ts index e7b5df70c99a0..908e45daf7105 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/index.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/index.ts @@ -16,5 +16,8 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./classification_creation')); loadTestFile(require.resolve('./cloning')); loadTestFile(require.resolve('./feature_importance')); + loadTestFile(require.resolve('./regression_creation_saved_search')); + loadTestFile(require.resolve('./classification_creation_saved_search')); + loadTestFile(require.resolve('./outlier_detection_creation_saved_search')); }); } diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation_saved_search.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation_saved_search.ts new file mode 100644 index 0000000000000..861be18591a11 --- /dev/null +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation_saved_search.ts @@ -0,0 +1,377 @@ +/* + * 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 { AnalyticsTableRowDetails } from '../../../services/ml/data_frame_analytics_table'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const ml = getService('ml'); + const editedDescription = 'Edited description'; + + describe('outlier detection saved search creation', function () { + before(async () => { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote_small'); + await ml.testResources.createIndexPatternIfNeeded('ft_farequote_small', '@timestamp'); + await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded('ft_farequote_small'); + await ml.testResources.createSavedSearchFarequoteKueryIfNeeded('ft_farequote_small'); + await ml.testResources.setKibanaTimeZoneToUTC(); + + await ml.securityUI.loginAsMlPowerUser(); + }); + + after(async () => { + await ml.api.cleanMlIndices(); + await ml.testResources.deleteSavedSearches(); + await ml.testResources.deleteIndexPatternByTitle('ft_farequote_small'); + }); + + const dateNow = Date.now(); + const testDataList = [ + { + suiteTitle: 'with lucene query', + jobType: 'outlier_detection', + jobId: `fq_saved_search_2_${dateNow}`, + jobDescription: 'Outlier detection job based on a saved search with lucene query', + source: 'ft_farequote_lucene', + get destinationIndex(): string { + return `user-${this.jobId}`; + }, + runtimeFields: { + uppercase_airline: { + type: 'keyword', + script: 'emit(params._source.airline.toUpperCase())', + }, + }, + modelMemory: '65mb', + createIndexPattern: true, + expected: { + source: 'ft_farequote_small', + histogramCharts: [ + { chartAvailable: true, id: 'uppercase_airline', legend: '5 categories' }, + { chartAvailable: true, id: 'responsetime', legend: '4.91 - 171.08' }, + { chartAvailable: true, id: 'airline', legend: '5 categories' }, + ], + scatterplotMatrixColorsWizard: [ + // markers + { color: '#52B398', percentage: 15 }, + // grey boilerplate + { color: '#6A717D', percentage: 13 }, + ], + scatterplotMatrixColorStatsResults: [ + // red markers + { color: '#D98071', percentage: 1 }, + // tick/grid/axis, grey markers + { color: '#6A717D', percentage: 12 }, + { color: '#D3DAE6', percentage: 8 }, + { color: '#98A1B3', percentage: 12 }, + // anti-aliasing + { color: '#F5F7FA', percentage: 30 }, + ], + runtimeFieldsEditorContent: ['{', ' "uppercase_airline": {', ' "type": "keyword",'], + row: { + memoryStatus: 'ok', + type: 'outlier_detection', + status: 'stopped', + progress: '100', + }, + rowDetails: { + jobDetails: [ + { + section: 'state', + expectedEntries: { + id: `fq_saved_search_2_${dateNow}`, + state: 'stopped', + data_counts: + '{"training_docs_count":1604,"test_docs_count":0,"skipped_docs_count":0}', + description: 'Outlier detection job based on a saved search with lucene query', + }, + }, + { section: 'progress', expectedEntries: { Phase: '4/4' } }, + ], + } as AnalyticsTableRowDetails, + }, + }, + { + suiteTitle: 'with kuery query', + jobType: 'outlier_detection', + jobId: `fq_saved_search_3_${dateNow}`, + jobDescription: 'Outlier detection job based on a saved search with kuery query', + source: 'ft_farequote_kuery', + get destinationIndex(): string { + return `user-${this.jobId}`; + }, + runtimeFields: { + uppercase_airline: { + type: 'keyword', + script: 'emit(params._source.airline.toUpperCase())', + }, + }, + modelMemory: '65mb', + createIndexPattern: true, + expected: { + source: 'ft_farequote_small', + histogramCharts: [ + { chartAvailable: true, id: 'uppercase_airline', legend: '5 categories' }, + { chartAvailable: true, id: 'responsetime', legend: '9.91 - 171.08' }, + { chartAvailable: true, id: 'airline', legend: '5 categories' }, + ], + scatterplotMatrixColorsWizard: [ + // markers + { color: '#52B398', percentage: 15 }, + // grey boilerplate + { color: '#6A717D', percentage: 13 }, + ], + scatterplotMatrixColorStatsResults: [ + // red markers + { color: '#D98071', percentage: 1 }, + // tick/grid/axis, grey markers + { color: '#6A717D', percentage: 12 }, + { color: '#D3DAE6', percentage: 8 }, + { color: '#98A1B3', percentage: 12 }, + // anti-aliasing + { color: '#F5F7FA', percentage: 30 }, + ], + runtimeFieldsEditorContent: ['{', ' "uppercase_airline": {', ' "type": "keyword",'], + row: { + memoryStatus: 'ok', + type: 'outlier_detection', + status: 'stopped', + progress: '100', + }, + rowDetails: { + jobDetails: [ + { + section: 'state', + expectedEntries: { + id: `fq_saved_search_3_${dateNow}`, + state: 'stopped', + data_counts: + '{"training_docs_count":1603,"test_docs_count":0,"skipped_docs_count":0}', + description: 'Outlier detection job based on a saved search with kuery query', + }, + }, + { section: 'progress', expectedEntries: { Phase: '4/4' } }, + ], + } as AnalyticsTableRowDetails, + }, + }, + ]; + + for (const testData of testDataList) { + describe(`${testData.suiteTitle}`, function () { + after(async () => { + await ml.api.deleteIndices(testData.destinationIndex); + await ml.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + }); + + it('loads the data frame analytics wizard', async () => { + await ml.testExecution.logTestStep('loads the data frame analytics page'); + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToDataFrameAnalytics(); + + await ml.testExecution.logTestStep('loads the source selection modal'); + + // Disable anti-aliasing to stabilize canvas image rendering assertions + await ml.commonUI.disableAntiAliasing(); + + await ml.dataFrameAnalytics.startAnalyticsCreation(); + + await ml.testExecution.logTestStep( + 'selects the source data and loads the job wizard page' + ); + await ml.jobSourceSelection.selectSourceForAnalyticsJob(testData.source); + await ml.dataFrameAnalyticsCreation.assertConfigurationStepActive(); + }); + + it('navigates through the wizard and sets all needed fields', async () => { + await ml.testExecution.logTestStep('selects the job type'); + await ml.dataFrameAnalyticsCreation.assertJobTypeSelectExists(); + await ml.dataFrameAnalyticsCreation.selectJobType(testData.jobType); + + await ml.testExecution.logTestStep('displays the runtime mappings editor switch'); + await ml.dataFrameAnalyticsCreation.assertRuntimeMappingSwitchExists(); + + await ml.testExecution.logTestStep('enables the runtime mappings editor'); + await ml.dataFrameAnalyticsCreation.toggleRuntimeMappingsEditorSwitch(true); + await ml.dataFrameAnalyticsCreation.assertRuntimeMappingsEditorContent(['']); + + await ml.testExecution.logTestStep('sets runtime mappings'); + await ml.dataFrameAnalyticsCreation.setRuntimeMappingsEditorContent( + JSON.stringify(testData.runtimeFields) + ); + await ml.dataFrameAnalyticsCreation.applyRuntimeMappings(); + await ml.dataFrameAnalyticsCreation.assertRuntimeMappingsEditorContent( + testData.expected.runtimeFieldsEditorContent + ); + + await ml.testExecution.logTestStep('does not display the dependent variable input'); + await ml.dataFrameAnalyticsCreation.assertDependentVariableInputMissing(); + + await ml.testExecution.logTestStep('does not display the training percent input'); + await ml.dataFrameAnalyticsCreation.assertTrainingPercentInputMissing(); + + await ml.testExecution.logTestStep('displays the source data preview'); + await ml.dataFrameAnalyticsCreation.assertSourceDataPreviewExists(); + + await ml.testExecution.logTestStep('enables the source data preview histogram charts'); + await ml.dataFrameAnalyticsCreation.enableSourceDataPreviewHistogramCharts(true); + + await ml.testExecution.logTestStep('displays the source data preview histogram charts'); + await ml.dataFrameAnalyticsCreation.assertSourceDataPreviewHistogramCharts( + testData.expected.histogramCharts + ); + + await ml.testExecution.logTestStep('displays the include fields selection'); + await ml.dataFrameAnalyticsCreation.assertIncludeFieldsSelectionExists(); + + await ml.testExecution.logTestStep('continues to the additional options step'); + await ml.dataFrameAnalyticsCreation.continueToAdditionalOptionsStep(); + + await ml.testExecution.logTestStep('accepts the suggested model memory limit'); + await ml.dataFrameAnalyticsCreation.assertModelMemoryInputExists(); + await ml.dataFrameAnalyticsCreation.assertModelMemoryInputPopulated(); + + await ml.testExecution.logTestStep('continues to the details step'); + await ml.dataFrameAnalyticsCreation.continueToDetailsStep(); + + await ml.testExecution.logTestStep('inputs the job id'); + await ml.dataFrameAnalyticsCreation.assertJobIdInputExists(); + await ml.dataFrameAnalyticsCreation.setJobId(testData.jobId); + + await ml.testExecution.logTestStep('inputs the job description'); + await ml.dataFrameAnalyticsCreation.assertJobDescriptionInputExists(); + await ml.dataFrameAnalyticsCreation.setJobDescription(testData.jobDescription); + + await ml.testExecution.logTestStep( + 'should default the set destination index to job id switch to true' + ); + await ml.dataFrameAnalyticsCreation.assertDestIndexSameAsIdSwitchExists(); + await ml.dataFrameAnalyticsCreation.assertDestIndexSameAsIdCheckState(true); + + await ml.testExecution.logTestStep('should input the destination index'); + await ml.dataFrameAnalyticsCreation.setDestIndexSameAsIdCheckState(false); + await ml.dataFrameAnalyticsCreation.assertDestIndexInputExists(); + await ml.dataFrameAnalyticsCreation.setDestIndex(testData.destinationIndex); + + await ml.testExecution.logTestStep('continues to the validation step'); + await ml.dataFrameAnalyticsCreation.continueToValidationStep(); + + await ml.testExecution.logTestStep('checks validation callouts exist'); + await ml.dataFrameAnalyticsCreation.assertValidationCalloutsExists(); + await ml.dataFrameAnalyticsCreation.assertAllValidationCalloutsPresent(1); + + await ml.testExecution.logTestStep('continues to the create step'); + await ml.dataFrameAnalyticsCreation.continueToCreateStep(); + + await ml.testExecution.logTestStep('sets the create data view switch'); + await ml.dataFrameAnalyticsCreation.assertCreateIndexPatternSwitchExists(); + await ml.dataFrameAnalyticsCreation.setCreateIndexPatternSwitchState( + testData.createIndexPattern + ); + }); + + it('runs the analytics job and displays it correctly in the job list', async () => { + await ml.testExecution.logTestStep('creates and starts the analytics job'); + await ml.dataFrameAnalyticsCreation.assertCreateButtonExists(); + await ml.dataFrameAnalyticsCreation.assertStartJobCheckboxCheckState(true); + await ml.dataFrameAnalyticsCreation.createAnalyticsJob(testData.jobId); + + await ml.testExecution.logTestStep('finishes analytics processing'); + await ml.dataFrameAnalytics.waitForAnalyticsCompletion(testData.jobId); + + await ml.testExecution.logTestStep('displays the analytics table'); + await ml.dataFrameAnalyticsCreation.navigateToJobManagementPage(); + await ml.dataFrameAnalytics.assertAnalyticsTableExists(); + + await ml.testExecution.logTestStep('displays the stats bar'); + await ml.dataFrameAnalytics.assertAnalyticsStatsBarExists(); + + await ml.testExecution.logTestStep('displays the created job in the analytics table'); + await ml.dataFrameAnalyticsTable.refreshAnalyticsTable(); + await ml.dataFrameAnalyticsTable.filterWithSearchString(testData.jobId, 1); + + await ml.testExecution.logTestStep( + 'displays details for the created job in the analytics table' + ); + await ml.dataFrameAnalyticsTable.assertAnalyticsRowFields(testData.jobId, { + id: testData.jobId, + description: testData.jobDescription, + memoryStatus: testData.expected.row.memoryStatus, + sourceIndex: testData.expected.source, + destinationIndex: testData.destinationIndex, + type: testData.expected.row.type, + status: testData.expected.row.status, + progress: testData.expected.row.progress, + }); + + await ml.dataFrameAnalyticsTable.assertAnalyticsRowDetails( + testData.jobId, + testData.expected.rowDetails + ); + }); + + it('edits the analytics job and displays it correctly in the job list', async () => { + await ml.testExecution.logTestStep( + 'should open the edit form for the created job in the analytics table' + ); + await ml.dataFrameAnalyticsTable.openEditFlyout(testData.jobId); + + await ml.testExecution.logTestStep('should input the description in the edit form'); + await ml.dataFrameAnalyticsEdit.assertJobDescriptionEditInputExists(); + await ml.dataFrameAnalyticsEdit.setJobDescriptionEdit(editedDescription); + + await ml.testExecution.logTestStep( + 'should input the model memory limit in the edit form' + ); + await ml.dataFrameAnalyticsEdit.assertJobMmlEditInputExists(); + await ml.dataFrameAnalyticsEdit.setJobMmlEdit('21mb'); + + await ml.testExecution.logTestStep('should submit the edit job form'); + await ml.dataFrameAnalyticsEdit.updateAnalyticsJob(); + + await ml.testExecution.logTestStep( + 'displays details for the edited job in the analytics table' + ); + await ml.dataFrameAnalyticsTable.assertAnalyticsRowFields(testData.jobId, { + id: testData.jobId, + description: editedDescription, + memoryStatus: testData.expected.row.memoryStatus, + sourceIndex: testData.expected.source, + destinationIndex: testData.destinationIndex, + type: testData.expected.row.type, + status: testData.expected.row.status, + progress: testData.expected.row.progress, + }); + + await ml.testExecution.logTestStep( + 'creates the destination index and writes results to it' + ); + await ml.api.assertIndicesExist(testData.destinationIndex); + await ml.api.assertIndicesNotEmpty(testData.destinationIndex); + + await ml.testExecution.logTestStep('displays the results view for created job'); + await ml.dataFrameAnalyticsTable.openResultsView(testData.jobId); + await ml.dataFrameAnalyticsResults.assertOutlierTablePanelExists(); + await ml.dataFrameAnalyticsResults.assertResultsTableExists(); + await ml.dataFrameAnalyticsResults.assertResultsTableNotEmpty(); + await ml.dataFrameAnalyticsResults.assertFeatureInfluenceCellNotEmpty(); + + await ml.commonUI.resetAntiAliasing(); + }); + + it('displays the analytics job in the map view', async () => { + await ml.testExecution.logTestStep('should open the map view for created job'); + await ml.navigation.navigateToDataFrameAnalytics(); + await ml.dataFrameAnalyticsTable.openMapView(testData.jobId); + await ml.dataFrameAnalyticsMap.assertMapElementsExists(); + await ml.dataFrameAnalyticsMap.assertJobMapTitle(testData.jobId); + }); + }); + } + }); +} diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation_saved_search.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation_saved_search.ts new file mode 100644 index 0000000000000..e22c4908486d1 --- /dev/null +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation_saved_search.ts @@ -0,0 +1,333 @@ +/* + * 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 { AnalyticsTableRowDetails } from '../../../services/ml/data_frame_analytics_table'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const ml = getService('ml'); + const editedDescription = 'Edited description'; + + describe('regression saved search creation', function () { + before(async () => { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote_small'); + await ml.testResources.createIndexPatternIfNeeded('ft_farequote_small', '@timestamp'); + await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded('ft_farequote_small'); + await ml.testResources.createSavedSearchFarequoteKueryIfNeeded('ft_farequote_small'); + await ml.testResources.setKibanaTimeZoneToUTC(); + + await ml.securityUI.loginAsMlPowerUser(); + }); + + after(async () => { + await ml.api.cleanMlIndices(); + await ml.testResources.deleteSavedSearches(); + await ml.testResources.deleteIndexPatternByTitle('ft_farequote_small'); + }); + + const dateNow = Date.now(); + const testDataList = [ + { + suiteTitle: 'with lucene query', + jobType: 'regression', + jobId: `fq_saved_search_2_${dateNow}`, + jobDescription: 'Regression job based on a saved search with lucene query', + source: 'ft_farequote_lucene', + get destinationIndex(): string { + return `user-${this.jobId}`; + }, + runtimeFields: { + uppercase_airline: { + type: 'keyword', + script: 'emit(params._source.airline.toUpperCase())', + }, + }, + dependentVariable: 'responsetime', + trainingPercent: 20, + modelMemory: '20mb', + createIndexPattern: true, + expected: { + source: 'ft_farequote_small', + runtimeFieldsEditorContent: ['{', ' "uppercase_airline": {', ' "type": "keyword",'], + row: { + memoryStatus: 'ok', + type: 'regression', + status: 'stopped', + progress: '100', + }, + rowDetails: { + jobDetails: [ + { + section: 'state', + expectedEntries: { + id: `fq_saved_search_2_${dateNow}`, + state: 'stopped', + data_counts: + '{"training_docs_count":320,"test_docs_count":1284,"skipped_docs_count":0}', + description: 'Regression job based on a saved search with lucene query', + }, + }, + { section: 'progress', expectedEntries: { Phase: '8/8' } }, + ], + } as AnalyticsTableRowDetails, + }, + }, + { + suiteTitle: 'with kuery query', + jobType: 'regression', + jobId: `fq_saved_search_3_${dateNow}`, + jobDescription: 'Regression job based on a saved search with kuery query', + source: 'ft_farequote_kuery', + get destinationIndex(): string { + return `user-${this.jobId}`; + }, + runtimeFields: { + uppercase_airline: { + type: 'keyword', + script: 'emit(params._source.airline.toUpperCase())', + }, + }, + dependentVariable: 'responsetime', + trainingPercent: 20, + modelMemory: '20mb', + createIndexPattern: true, + expected: { + source: 'ft_farequote_small', + runtimeFieldsEditorContent: ['{', ' "uppercase_airline": {', ' "type": "keyword",'], + row: { + memoryStatus: 'ok', + type: 'regression', + status: 'stopped', + progress: '100', + }, + rowDetails: { + jobDetails: [ + { + section: 'state', + expectedEntries: { + id: `fq_saved_search_3_${dateNow}`, + state: 'stopped', + data_counts: + '{"training_docs_count":320,"test_docs_count":1283,"skipped_docs_count":0}', + description: 'Regression job based on a saved search with kuery query', + }, + }, + { section: 'progress', expectedEntries: { Phase: '8/8' } }, + ], + } as AnalyticsTableRowDetails, + }, + }, + ]; + + for (const testData of testDataList) { + describe(`${testData.suiteTitle}`, function () { + after(async () => { + await ml.api.deleteIndices(testData.destinationIndex); + await ml.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + }); + + it('loads the data frame analytics wizard', async () => { + await ml.testExecution.logTestStep('loads the data frame analytics page'); + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToDataFrameAnalytics(); + + await ml.testExecution.logTestStep('loads the source selection modal'); + + // Disable anti-aliasing to stabilize canvas image rendering assertions + await ml.commonUI.disableAntiAliasing(); + + await ml.dataFrameAnalytics.startAnalyticsCreation(); + + await ml.testExecution.logTestStep( + 'selects the source data and loads the job wizard page' + ); + await ml.jobSourceSelection.selectSourceForAnalyticsJob(testData.source); + await ml.dataFrameAnalyticsCreation.assertConfigurationStepActive(); + }); + + it('navigates through the wizard and sets all needed fields', async () => { + await ml.testExecution.logTestStep('selects the job type'); + await ml.dataFrameAnalyticsCreation.assertJobTypeSelectExists(); + await ml.dataFrameAnalyticsCreation.selectJobType(testData.jobType); + + await ml.testExecution.logTestStep('displays the runtime mappings editor switch'); + await ml.dataFrameAnalyticsCreation.assertRuntimeMappingSwitchExists(); + + await ml.testExecution.logTestStep('enables the runtime mappings editor'); + await ml.dataFrameAnalyticsCreation.toggleRuntimeMappingsEditorSwitch(true); + await ml.dataFrameAnalyticsCreation.assertRuntimeMappingsEditorContent(['']); + + await ml.testExecution.logTestStep('sets runtime mappings'); + await ml.dataFrameAnalyticsCreation.setRuntimeMappingsEditorContent( + JSON.stringify(testData.runtimeFields) + ); + await ml.dataFrameAnalyticsCreation.applyRuntimeMappings(); + await ml.dataFrameAnalyticsCreation.assertRuntimeMappingsEditorContent( + testData.expected.runtimeFieldsEditorContent + ); + + await ml.testExecution.logTestStep('inputs the dependent variable'); + await ml.dataFrameAnalyticsCreation.assertDependentVariableInputExists(); + await ml.dataFrameAnalyticsCreation.selectDependentVariable(testData.dependentVariable); + + await ml.testExecution.logTestStep('inputs the training percent'); + await ml.dataFrameAnalyticsCreation.assertTrainingPercentInputExists(); + await ml.dataFrameAnalyticsCreation.setTrainingPercent(testData.trainingPercent); + + await ml.testExecution.logTestStep('displays the source data preview'); + await ml.dataFrameAnalyticsCreation.assertSourceDataPreviewExists(); + + await ml.testExecution.logTestStep('displays the include fields selection'); + await ml.dataFrameAnalyticsCreation.assertIncludeFieldsSelectionExists(); + + await ml.testExecution.logTestStep('continues to the additional options step'); + await ml.dataFrameAnalyticsCreation.continueToAdditionalOptionsStep(); + + await ml.testExecution.logTestStep('accepts the suggested model memory limit'); + await ml.dataFrameAnalyticsCreation.assertModelMemoryInputExists(); + await ml.dataFrameAnalyticsCreation.assertModelMemoryInputPopulated(); + + await ml.testExecution.logTestStep('continues to the details step'); + await ml.dataFrameAnalyticsCreation.continueToDetailsStep(); + + await ml.testExecution.logTestStep('inputs the job id'); + await ml.dataFrameAnalyticsCreation.assertJobIdInputExists(); + await ml.dataFrameAnalyticsCreation.setJobId(testData.jobId); + + await ml.testExecution.logTestStep('inputs the job description'); + await ml.dataFrameAnalyticsCreation.assertJobDescriptionInputExists(); + await ml.dataFrameAnalyticsCreation.setJobDescription(testData.jobDescription); + + await ml.testExecution.logTestStep( + 'should default the set destination index to job id switch to true' + ); + await ml.dataFrameAnalyticsCreation.assertDestIndexSameAsIdSwitchExists(); + await ml.dataFrameAnalyticsCreation.assertDestIndexSameAsIdCheckState(true); + + await ml.testExecution.logTestStep('should input the destination index'); + await ml.dataFrameAnalyticsCreation.setDestIndexSameAsIdCheckState(false); + await ml.dataFrameAnalyticsCreation.assertDestIndexInputExists(); + await ml.dataFrameAnalyticsCreation.setDestIndex(testData.destinationIndex); + + await ml.testExecution.logTestStep('continues to the validation step'); + await ml.dataFrameAnalyticsCreation.continueToValidationStep(); + + await ml.testExecution.logTestStep('checks validation callouts exist'); + await ml.dataFrameAnalyticsCreation.assertValidationCalloutsExists(); + await ml.dataFrameAnalyticsCreation.assertAllValidationCalloutsPresent(3); + + await ml.testExecution.logTestStep('continues to the create step'); + await ml.dataFrameAnalyticsCreation.continueToCreateStep(); + + await ml.testExecution.logTestStep('sets the create data view switch'); + await ml.dataFrameAnalyticsCreation.assertCreateIndexPatternSwitchExists(); + await ml.dataFrameAnalyticsCreation.setCreateIndexPatternSwitchState( + testData.createIndexPattern + ); + }); + + it('runs the analytics job and displays it correctly in the job list', async () => { + await ml.testExecution.logTestStep('creates and starts the analytics job'); + await ml.dataFrameAnalyticsCreation.assertCreateButtonExists(); + await ml.dataFrameAnalyticsCreation.assertStartJobCheckboxCheckState(true); + await ml.dataFrameAnalyticsCreation.createAnalyticsJob(testData.jobId); + + await ml.testExecution.logTestStep('finishes analytics processing'); + await ml.dataFrameAnalytics.waitForAnalyticsCompletion(testData.jobId); + + await ml.testExecution.logTestStep('displays the analytics table'); + await ml.dataFrameAnalyticsCreation.navigateToJobManagementPage(); + await ml.dataFrameAnalytics.assertAnalyticsTableExists(); + + await ml.testExecution.logTestStep('displays the stats bar'); + await ml.dataFrameAnalytics.assertAnalyticsStatsBarExists(); + + await ml.testExecution.logTestStep('displays the created job in the analytics table'); + await ml.dataFrameAnalyticsTable.refreshAnalyticsTable(); + await ml.dataFrameAnalyticsTable.filterWithSearchString(testData.jobId, 1); + + await ml.testExecution.logTestStep( + 'displays details for the created job in the analytics table' + ); + await ml.dataFrameAnalyticsTable.assertAnalyticsRowFields(testData.jobId, { + id: testData.jobId, + description: testData.jobDescription, + memoryStatus: testData.expected.row.memoryStatus, + sourceIndex: testData.expected.source, + destinationIndex: testData.destinationIndex, + type: testData.expected.row.type, + status: testData.expected.row.status, + progress: testData.expected.row.progress, + }); + await ml.dataFrameAnalyticsTable.assertAnalyticsRowDetails( + testData.jobId, + testData.expected.rowDetails + ); + }); + + it('edits the analytics job and displays it correctly in the job list', async () => { + await ml.testExecution.logTestStep( + 'should open the edit form for the created job in the analytics table' + ); + await ml.dataFrameAnalyticsTable.openEditFlyout(testData.jobId); + + await ml.testExecution.logTestStep('should input the description in the edit form'); + await ml.dataFrameAnalyticsEdit.assertJobDescriptionEditInputExists(); + await ml.dataFrameAnalyticsEdit.setJobDescriptionEdit(editedDescription); + + await ml.testExecution.logTestStep( + 'should input the model memory limit in the edit form' + ); + await ml.dataFrameAnalyticsEdit.assertJobMmlEditInputExists(); + await ml.dataFrameAnalyticsEdit.setJobMmlEdit('21mb'); + + await ml.testExecution.logTestStep('should submit the edit job form'); + await ml.dataFrameAnalyticsEdit.updateAnalyticsJob(); + + await ml.testExecution.logTestStep( + 'displays details for the edited job in the analytics table' + ); + await ml.dataFrameAnalyticsTable.assertAnalyticsRowFields(testData.jobId, { + id: testData.jobId, + description: editedDescription, + memoryStatus: testData.expected.row.memoryStatus, + sourceIndex: testData.expected.source, + destinationIndex: testData.destinationIndex, + type: testData.expected.row.type, + status: testData.expected.row.status, + progress: testData.expected.row.progress, + }); + + await ml.testExecution.logTestStep( + 'creates the destination index and writes results to it' + ); + await ml.api.assertIndicesExist(testData.destinationIndex); + await ml.api.assertIndicesNotEmpty(testData.destinationIndex); + + await ml.testExecution.logTestStep('displays the results view for created job'); + await ml.dataFrameAnalyticsTable.openResultsView(testData.jobId); + await ml.dataFrameAnalyticsResults.assertRegressionEvaluatePanelElementsExists(); + await ml.dataFrameAnalyticsResults.assertRegressionTablePanelExists(); + await ml.dataFrameAnalyticsResults.assertResultsTableExists(); + await ml.dataFrameAnalyticsResults.assertResultsTableTrainingFiltersExist(); + await ml.dataFrameAnalyticsResults.assertResultsTableNotEmpty(); + + await ml.commonUI.resetAntiAliasing(); + }); + + it('displays the analytics job in the map view', async () => { + await ml.testExecution.logTestStep('should open the map view for created job'); + await ml.navigation.navigateToDataFrameAnalytics(); + await ml.dataFrameAnalyticsTable.openMapView(testData.jobId); + await ml.dataFrameAnalyticsMap.assertMapElementsExists(); + await ml.dataFrameAnalyticsMap.assertJobMapTitle(testData.jobId); + }); + }); + } + }); +} diff --git a/x-pack/test/functional/apps/ml/index.ts b/x-pack/test/functional/apps/ml/index.ts index eeae200f35ba7..c58b20e1c374b 100644 --- a/x-pack/test/functional/apps/ml/index.ts +++ b/x-pack/test/functional/apps/ml/index.ts @@ -25,6 +25,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await ml.securityCommon.cleanMlRoles(); await esArchiver.unload('x-pack/test/functional/es_archives/ml/farequote'); + await esArchiver.unload('x-pack/test/functional/es_archives/ml/farequote_small'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/ecommerce'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/categorization_small'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/event_rate_nanos'); diff --git a/x-pack/test/functional/es_archives/ml/farequote_small/data.json.gz b/x-pack/test/functional/es_archives/ml/farequote_small/data.json.gz new file mode 100644 index 0000000000000..7c82fda817373 Binary files /dev/null and b/x-pack/test/functional/es_archives/ml/farequote_small/data.json.gz differ diff --git a/x-pack/test/functional/es_archives/ml/farequote_small/mappings.json b/x-pack/test/functional/es_archives/ml/farequote_small/mappings.json new file mode 100644 index 0000000000000..d1f03b687b013 --- /dev/null +++ b/x-pack/test/functional/es_archives/ml/farequote_small/mappings.json @@ -0,0 +1,48 @@ +{ + "type": "index", + "value": { + "aliases": { + }, + "index": "ft_farequote_small", + "mappings": { + "properties": { + "@timestamp": { + "type": "date" + }, + "@version": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "airline": { + "type": "keyword" + }, + "responsetime": { + "type": "float" + }, + "sourcetype": { + "type": "keyword" + }, + "type": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "settings": { + "index": { + "number_of_replicas": "1", + "number_of_shards": "1" + } + } + } +} diff --git a/x-pack/test/functional/services/ml/test_resources.ts b/x-pack/test/functional/services/ml/test_resources.ts index afb808b0f0bb1..d52ee857c1d9c 100644 --- a/x-pack/test/functional/services/ml/test_resources.ts +++ b/x-pack/test/functional/services/ml/test_resources.ts @@ -186,7 +186,7 @@ export function MachineLearningTestResourcesProvider({ getService }: FtrProvider return createResponse.id; }, - async createSavedSearchIfNeeded(savedSearch: any): Promise { + async createSavedSearchIfNeeded(savedSearch: any, indexPatternTitle: string): Promise { const title = savedSearch.requestBody.attributes.title; const savedSearchId = await this.getSavedSearchId(title); if (savedSearchId !== undefined) { @@ -195,7 +195,7 @@ export function MachineLearningTestResourcesProvider({ getService }: FtrProvider } else { const body = await this.updateSavedSearchRequestBody( savedSearch.requestBody, - savedSearch.indexPatternTitle + indexPatternTitle ); return await this.createSavedSearch(title, body); } @@ -226,8 +226,8 @@ export function MachineLearningTestResourcesProvider({ getService }: FtrProvider return updatedBody; }, - async createSavedSearchFarequoteFilterIfNeeded() { - await this.createSavedSearchIfNeeded(savedSearches.farequoteFilter); + async createSavedSearchFarequoteFilterIfNeeded(indexPatternTitle: string = 'ft_farequote') { + await this.createSavedSearchIfNeeded(savedSearches.farequoteFilter, indexPatternTitle); }, async createMLTestDashboardIfNeeded() { @@ -249,20 +249,30 @@ export function MachineLearningTestResourcesProvider({ getService }: FtrProvider } }, - async createSavedSearchFarequoteLuceneIfNeeded() { - await this.createSavedSearchIfNeeded(savedSearches.farequoteLucene); + async createSavedSearchFarequoteLuceneIfNeeded(indexPatternTitle: string = 'ft_farequote') { + await this.createSavedSearchIfNeeded(savedSearches.farequoteLucene, indexPatternTitle); }, - async createSavedSearchFarequoteKueryIfNeeded() { - await this.createSavedSearchIfNeeded(savedSearches.farequoteKuery); + async createSavedSearchFarequoteKueryIfNeeded(indexPatternTitle: string = 'ft_farequote') { + await this.createSavedSearchIfNeeded(savedSearches.farequoteKuery, indexPatternTitle); }, - async createSavedSearchFarequoteFilterAndLuceneIfNeeded() { - await this.createSavedSearchIfNeeded(savedSearches.farequoteFilterAndLucene); + async createSavedSearchFarequoteFilterAndLuceneIfNeeded( + indexPatternTitle: string = 'ft_farequote' + ) { + await this.createSavedSearchIfNeeded( + savedSearches.farequoteFilterAndLucene, + indexPatternTitle + ); }, - async createSavedSearchFarequoteFilterAndKueryIfNeeded() { - await this.createSavedSearchIfNeeded(savedSearches.farequoteFilterAndKuery); + async createSavedSearchFarequoteFilterAndKueryIfNeeded( + indexPatternTitle: string = 'ft_farequote' + ) { + await this.createSavedSearchIfNeeded( + savedSearches.farequoteFilterAndKuery, + indexPatternTitle + ); }, async deleteSavedObjectById(id: string, objectType: SavedObjectType, force: boolean = false) { diff --git a/x-pack/test/functional/services/ml/test_resources_data.ts b/x-pack/test/functional/services/ml/test_resources_data.ts index 7502968bd2bb4..aeacc51cecbc9 100644 --- a/x-pack/test/functional/services/ml/test_resources_data.ts +++ b/x-pack/test/functional/services/ml/test_resources_data.ts @@ -7,7 +7,6 @@ export const savedSearches = { farequoteFilter: { - indexPatternTitle: 'ft_farequote', requestBody: { attributes: { title: 'ft_farequote_filter', @@ -66,7 +65,6 @@ export const savedSearches = { }, }, farequoteLucene: { - indexPatternTitle: 'ft_farequote', requestBody: { attributes: { title: 'ft_farequote_lucene', @@ -98,7 +96,6 @@ export const savedSearches = { }, }, farequoteKuery: { - indexPatternTitle: 'ft_farequote', requestBody: { attributes: { title: 'ft_farequote_kuery', @@ -130,7 +127,6 @@ export const savedSearches = { }, }, farequoteFilterAndLucene: { - indexPatternTitle: 'ft_farequote', requestBody: { attributes: { title: 'ft_farequote_filter_and_lucene', @@ -189,7 +185,6 @@ export const savedSearches = { }, }, farequoteFilterAndKuery: { - indexPatternTitle: 'ft_farequote', requestBody: { attributes: { title: 'ft_farequote_filter_and_kuery',