mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[ML] Initial serverless functional tests for ML (#167493)
Add serverless functional tests for each project. **Search** Opens the trained models page and checks that there are 4 models listed. **Observability** Creates a AD job and then navigates to the AD jobs list and checks that the job is listed. **Security** Creates a AD job and then navigates to the AD jobs list and checks that the job is listed. Creates a DFA job and then navigates to the DFA jobs list and checks that the job is listed. Navigates to the trained models page and checks that there are no trained models listed. Also adds tests for each project to ensure that kibana search bar only lists the pages which are enabled. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
1814580e1b
commit
fe7d2eb441
23 changed files with 636 additions and 4 deletions
|
@ -263,7 +263,7 @@ function createDeepLinks(
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
getDataComparisonDeepLink: (): AppDeepLink<LinkId> => {
|
getDataDriftDeepLink: (): AppDeepLink<LinkId> => {
|
||||||
return {
|
return {
|
||||||
id: 'dataDrift',
|
id: 'dataDrift',
|
||||||
title: i18n.translate('xpack.ml.deepLink.dataDrift', {
|
title: i18n.translate('xpack.ml.deepLink.dataDrift', {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
|
|
||||||
const COMMON_REQUEST_HEADERS = {
|
const COMMON_REQUEST_HEADERS = {
|
||||||
'kbn-xsrf': 'some-xsrf-token',
|
'kbn-xsrf': 'some-xsrf-token',
|
||||||
|
'x-elastic-internal-origin': 'Kibana',
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MlCommonAPI = ProvidedType<typeof MachineLearningCommonAPIProvider>;
|
export type MlCommonAPI = ProvidedType<typeof MachineLearningCommonAPIProvider>;
|
||||||
|
|
|
@ -60,9 +60,9 @@ export function MachineLearningTestResourcesProvider(
|
||||||
objectType: SavedObjectType,
|
objectType: SavedObjectType,
|
||||||
space?: string
|
space?: string
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const response = await supertest.get(
|
const response = await supertest
|
||||||
`${space ? `/s/${space}` : ''}/api/saved_objects/${objectType}/${id}`
|
.get(`${space ? `/s/${space}` : ''}/api/saved_objects/${objectType}/${id}`)
|
||||||
);
|
.set(getCommonRequestHeader('1'));
|
||||||
return response.status === 200;
|
return response.status === 200;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,21 @@ export function TrainedModelsTableProvider(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async assertTableIsPopulated() {
|
||||||
|
await this.waitForModelsToLoad();
|
||||||
|
const rows = await this.parseModelsTable();
|
||||||
|
expect(rows.length).to.not.eql(0, `Expected trained model row count to be '>0' (got '0')`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertTableIsNotPopulated() {
|
||||||
|
await this.waitForModelsToLoad();
|
||||||
|
const rows = await this.parseModelsTable();
|
||||||
|
expect(rows.length).to.eql(
|
||||||
|
0,
|
||||||
|
`Expected trained model row count to be '0' (got '${rows.length}')`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public async assertModelCollapsedActionsButtonExists(modelId: string, expectedValue: boolean) {
|
public async assertModelCollapsedActionsButtonExists(modelId: string, expectedValue: boolean) {
|
||||||
const actionsExists = await this.doesModelCollapsedActionsButtonExist(modelId);
|
const actionsExists = await this.doesModelCollapsedActionsButtonExist(modelId);
|
||||||
expect(actionsExists).to.eql(
|
expect(actionsExists).to.eql(
|
||||||
|
|
|
@ -47,6 +47,7 @@ const deploymentAgnosticFunctionalServices = _.pick(functionalServices, [
|
||||||
'listingTable',
|
'listingTable',
|
||||||
'managementMenu',
|
'managementMenu',
|
||||||
'menuToggle',
|
'menuToggle',
|
||||||
|
'ml',
|
||||||
'monacoEditor',
|
'monacoEditor',
|
||||||
'pieChart',
|
'pieChart',
|
||||||
'pipelineEditor',
|
'pipelineEditor',
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { SvlObltNavigationServiceProvider } from './svl_oblt_navigation';
|
||||||
import { SvlSearchNavigationServiceProvider } from './svl_search_navigation';
|
import { SvlSearchNavigationServiceProvider } from './svl_search_navigation';
|
||||||
import { SvlSecNavigationServiceProvider } from './svl_sec_navigation';
|
import { SvlSecNavigationServiceProvider } from './svl_sec_navigation';
|
||||||
import { SvlCommonScreenshotsProvider } from './svl_common_screenshots';
|
import { SvlCommonScreenshotsProvider } from './svl_common_screenshots';
|
||||||
|
import { MachineLearningProvider } from './ml';
|
||||||
|
|
||||||
export const services = {
|
export const services = {
|
||||||
// deployment agnostic FTR services
|
// deployment agnostic FTR services
|
||||||
|
@ -25,4 +26,5 @@ export const services = {
|
||||||
svlSearchNavigation: SvlSearchNavigationServiceProvider,
|
svlSearchNavigation: SvlSearchNavigationServiceProvider,
|
||||||
svlSecNavigation: SvlSecNavigationServiceProvider,
|
svlSecNavigation: SvlSecNavigationServiceProvider,
|
||||||
svlCommonScreenshots: SvlCommonScreenshotsProvider,
|
svlCommonScreenshots: SvlCommonScreenshotsProvider,
|
||||||
|
svlMl: MachineLearningProvider,
|
||||||
};
|
};
|
||||||
|
|
23
x-pack/test_serverless/functional/services/ml/index.ts
Normal file
23
x-pack/test_serverless/functional/services/ml/index.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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 { MachineLearningNavigationProviderObservability } from './observability_navigation';
|
||||||
|
import { MachineLearningNavigationProviderSecurity } from './security_navigation';
|
||||||
|
|
||||||
|
export function MachineLearningProvider(context: FtrProviderContext) {
|
||||||
|
const observabilityNavigation = MachineLearningNavigationProviderObservability(context);
|
||||||
|
const securityNavigation = MachineLearningNavigationProviderSecurity(context);
|
||||||
|
|
||||||
|
return {
|
||||||
|
navigation: {
|
||||||
|
observability: observabilityNavigation,
|
||||||
|
security: securityNavigation,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export function MachineLearningNavigationProviderObservability({ getService }: FtrProviderContext) {
|
||||||
|
const testSubjects = getService('testSubjects');
|
||||||
|
|
||||||
|
async function navigateToArea(id: string) {
|
||||||
|
await testSubjects.click('~nav-item-id-aiops');
|
||||||
|
await testSubjects.existOrFail(`~nav-item-id-ml:${id}`, { timeout: 60 * 1000 });
|
||||||
|
await testSubjects.click(`~nav-item-id-ml:${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
async navigateToAnomalyDetection() {
|
||||||
|
await navigateToArea('anomalyDetection');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export function MachineLearningNavigationProviderSecurity({ getService }: FtrProviderContext) {
|
||||||
|
const testSubjects = getService('testSubjects');
|
||||||
|
|
||||||
|
async function navigateToArea(id: string) {
|
||||||
|
await testSubjects.click('~solutionSideNavItemButton-machine_learning-landing');
|
||||||
|
await testSubjects.existOrFail(`~solutionSideNavPanelLink-ml:${id}`, {
|
||||||
|
timeout: 60 * 1000,
|
||||||
|
});
|
||||||
|
await testSubjects.click(`~solutionSideNavPanelLink-ml:${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
async navigateToAnomalyDetection() {
|
||||||
|
await navigateToArea('anomalyDetection');
|
||||||
|
},
|
||||||
|
async navigateToDataFrameAnalytics() {
|
||||||
|
await navigateToArea('dataFrameAnalytics');
|
||||||
|
},
|
||||||
|
async navigateToTrainedModels() {
|
||||||
|
await navigateToArea('nodesOverview');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -18,5 +18,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
||||||
loadTestFile(require.resolve('./cases/create_case_form'));
|
loadTestFile(require.resolve('./cases/create_case_form'));
|
||||||
loadTestFile(require.resolve('./cases/list_view'));
|
loadTestFile(require.resolve('./cases/list_view'));
|
||||||
loadTestFile(require.resolve('./advanced_settings'));
|
loadTestFile(require.resolve('./advanced_settings'));
|
||||||
|
loadTestFile(require.resolve('./ml'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||||
|
const ml = getService('ml');
|
||||||
|
const svlMl = getService('svlMl');
|
||||||
|
const PageObjects = getPageObjects(['svlCommonPage']);
|
||||||
|
const adJobId = 'fq_single_permission';
|
||||||
|
|
||||||
|
describe('Anomaly detection jobs list', () => {
|
||||||
|
before(async () => {
|
||||||
|
await PageObjects.svlCommonPage.login();
|
||||||
|
|
||||||
|
await ml.api.createAnomalyDetectionJob(ml.commonConfig.getADFqMultiMetricJobConfig(adJobId));
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await PageObjects.svlCommonPage.forceLogout();
|
||||||
|
await ml.api.cleanMlIndices();
|
||||||
|
await ml.testResources.cleanMLSavedObjects();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('page navigation', () => {
|
||||||
|
it('renders job list and finds created job', async () => {
|
||||||
|
await ml.navigation.navigateToMl();
|
||||||
|
await ml.testExecution.logTestStep('loads the anomaly detection area');
|
||||||
|
await svlMl.navigation.observability.navigateToAnomalyDetection();
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('should display the stats bar and the AD job table');
|
||||||
|
await ml.jobManagement.assertJobStatsBarExists();
|
||||||
|
await ml.jobManagement.assertJobTableExists();
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('should display an enabled "Create job" button');
|
||||||
|
await ml.jobManagement.assertCreateNewJobButtonExists();
|
||||||
|
await ml.jobManagement.assertCreateNewJobButtonEnabled(true);
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('should display the AD job in the list');
|
||||||
|
await ml.jobTable.filterWithSearchString(adJobId, 1);
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('should display enabled AD job result links');
|
||||||
|
await ml.jobTable.assertJobActionSingleMetricViewerButtonEnabled(adJobId, true);
|
||||||
|
await ml.jobTable.assertJobActionAnomalyExplorerButtonEnabled(adJobId, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||||
|
describe('Observability ML', function () {
|
||||||
|
loadTestFile(require.resolve('./anomaly_detection_jobs_list'));
|
||||||
|
loadTestFile(require.resolve('./search_bar_features'));
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* 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 default function ({ getPageObjects }: FtrProviderContext) {
|
||||||
|
const PageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation']);
|
||||||
|
|
||||||
|
const allLabels = [
|
||||||
|
{ label: 'Machine Learning', expected: true },
|
||||||
|
{ label: 'Machine Learning / Overview', expected: true },
|
||||||
|
{ label: 'Machine Learning / Anomaly Detection', expected: true },
|
||||||
|
{ label: 'Machine Learning / Anomaly Detection / Anomaly explorer', expected: true },
|
||||||
|
{ label: 'Machine Learning / Anomaly Detection / Single metric viewer', expected: true },
|
||||||
|
{ label: 'Machine Learning / Data Frame Analytics', expected: false },
|
||||||
|
{ label: 'Machine Learning / Data Frame Analytics / Results explorer', expected: false },
|
||||||
|
{ label: 'Machine Learning / Data Frame Analytics / Analytics map', expected: false },
|
||||||
|
{ label: 'Machine Learning / Model Management', expected: false },
|
||||||
|
{ label: 'Machine Learning / Model Management / Trained Models', expected: false },
|
||||||
|
{ label: 'Machine Learning / Model Management / Nodes', expected: false },
|
||||||
|
{ label: 'Machine Learning / Memory Usage', expected: true },
|
||||||
|
{ label: 'Machine Learning / Settings', expected: true },
|
||||||
|
{ label: 'Machine Learning / Settings / Calendars', expected: true },
|
||||||
|
{ label: 'Machine Learning / Settings / Filter Lists', expected: true },
|
||||||
|
{ label: 'Machine Learning / AIOps', expected: true },
|
||||||
|
{ label: 'Machine Learning / AIOps / Log Rate Analysis', expected: true },
|
||||||
|
{ label: 'Machine Learning / AIOps / Log Pattern Analysis', expected: true },
|
||||||
|
{ label: 'Machine Learning / AIOps / Change Point Detection', expected: true },
|
||||||
|
{ label: 'Machine Learning / Notifications', expected: true },
|
||||||
|
{ label: 'Machine Learning / Data Visualizer', expected: true },
|
||||||
|
{ label: 'Machine Learning / File Upload', expected: true },
|
||||||
|
{ label: 'Machine Learning / Index Data Visualizer', expected: true },
|
||||||
|
{ label: 'Machine Learning / Data Drift', expected: true },
|
||||||
|
{ label: 'Alerts and Insights / Machine Learning', expected: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('Search bar features', () => {
|
||||||
|
before(async () => {
|
||||||
|
await PageObjects.svlCommonPage.login();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await PageObjects.svlCommonPage.forceLogout();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('list features', () => {
|
||||||
|
it('has the correct features enabled', async () => {
|
||||||
|
await PageObjects.svlCommonNavigation.search.showSearch();
|
||||||
|
|
||||||
|
const expectedLabels = allLabels.filter((l) => l.expected).map((l) => l.label);
|
||||||
|
|
||||||
|
for (const expectedLabel of expectedLabels) {
|
||||||
|
await PageObjects.svlCommonNavigation.search.searchFor(expectedLabel);
|
||||||
|
const [result] = await PageObjects.svlCommonNavigation.search.getDisplayedResults();
|
||||||
|
const label = result?.label;
|
||||||
|
expect(label).to.eql(
|
||||||
|
expectedLabel,
|
||||||
|
`First result should be ${expectedLabel} (got matching items '${label}')`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await PageObjects.svlCommonNavigation.search.hideSearch();
|
||||||
|
});
|
||||||
|
it('has the correct features disabled', async () => {
|
||||||
|
await PageObjects.svlCommonNavigation.search.showSearch();
|
||||||
|
|
||||||
|
const notExpectedLabels = allLabels.filter((l) => !l.expected).map((l) => l.label);
|
||||||
|
|
||||||
|
for (const notExpectedLabel of notExpectedLabels) {
|
||||||
|
await PageObjects.svlCommonNavigation.search.searchFor(notExpectedLabel);
|
||||||
|
const [result] = await PageObjects.svlCommonNavigation.search.getDisplayedResults();
|
||||||
|
const label = result?.label;
|
||||||
|
expect(label).to.not.eql(
|
||||||
|
notExpectedLabel,
|
||||||
|
`First result should not be ${notExpectedLabel} (got matching items '${label}')`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await PageObjects.svlCommonNavigation.search.hideSearch();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -17,5 +17,7 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
||||||
loadTestFile(require.resolve('./dashboards/build_dashboard'));
|
loadTestFile(require.resolve('./dashboards/build_dashboard'));
|
||||||
loadTestFile(require.resolve('./dashboards/import_dashboard'));
|
loadTestFile(require.resolve('./dashboards/import_dashboard'));
|
||||||
loadTestFile(require.resolve('./advanced_settings'));
|
loadTestFile(require.resolve('./advanced_settings'));
|
||||||
|
|
||||||
|
loadTestFile(require.resolve('./ml'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||||
|
describe('Search ML', function () {
|
||||||
|
loadTestFile(require.resolve('./trained_models_list'));
|
||||||
|
loadTestFile(require.resolve('./search_bar_features'));
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* 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 default function ({ getPageObjects }: FtrProviderContext) {
|
||||||
|
const PageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation']);
|
||||||
|
|
||||||
|
const allLabels = [
|
||||||
|
{ label: 'Machine Learning', expected: true },
|
||||||
|
{ label: 'Machine Learning / Overview', expected: false },
|
||||||
|
{ label: 'Machine Learning / Anomaly Detection', expected: false },
|
||||||
|
{ label: 'Machine Learning / Anomaly Detection / Anomaly explorer', expected: false },
|
||||||
|
{ label: 'Machine Learning / Anomaly Detection / Single metric viewer', expected: false },
|
||||||
|
{ label: 'Machine Learning / Data Frame Analytics', expected: false },
|
||||||
|
{ label: 'Machine Learning / Data Frame Analytics / Results explorer', expected: false },
|
||||||
|
{ label: 'Machine Learning / Data Frame Analytics / Analytics map', expected: false },
|
||||||
|
{ label: 'Machine Learning / Model Management', expected: true },
|
||||||
|
{ label: 'Machine Learning / Model Management / Trained Models', expected: true },
|
||||||
|
{ label: 'Machine Learning / Model Management / Nodes', expected: false },
|
||||||
|
{ label: 'Machine Learning / Memory Usage', expected: true },
|
||||||
|
{ label: 'Machine Learning / Settings', expected: false },
|
||||||
|
{ label: 'Machine Learning / Settings / Calendars', expected: false },
|
||||||
|
{ label: 'Machine Learning / Settings / Filter Lists', expected: false },
|
||||||
|
{ label: 'Machine Learning / AIOps', expected: true },
|
||||||
|
{ label: 'Machine Learning / AIOps / Log Rate Analysis', expected: true },
|
||||||
|
{ label: 'Machine Learning / AIOps / Log Pattern Analysis', expected: true },
|
||||||
|
{ label: 'Machine Learning / AIOps / Change Point Detection', expected: true },
|
||||||
|
{ label: 'Machine Learning / Notifications', expected: true },
|
||||||
|
{ label: 'Machine Learning / Data Visualizer', expected: true },
|
||||||
|
{ label: 'Machine Learning / File Upload', expected: true },
|
||||||
|
{ label: 'Machine Learning / Index Data Visualizer', expected: true },
|
||||||
|
{ label: 'Machine Learning / Data Drift', expected: true },
|
||||||
|
{ label: 'Alerts and Insights / Machine Learning', expected: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('Search bar features', () => {
|
||||||
|
before(async () => {
|
||||||
|
await PageObjects.svlCommonPage.login();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await PageObjects.svlCommonPage.forceLogout();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('list features', () => {
|
||||||
|
it('has the correct features enabled', async () => {
|
||||||
|
await PageObjects.svlCommonNavigation.search.showSearch();
|
||||||
|
|
||||||
|
const expectedLabels = allLabels.filter((l) => l.expected).map((l) => l.label);
|
||||||
|
|
||||||
|
for (const expectedLabel of expectedLabels) {
|
||||||
|
await PageObjects.svlCommonNavigation.search.searchFor(expectedLabel);
|
||||||
|
const [result] = await PageObjects.svlCommonNavigation.search.getDisplayedResults();
|
||||||
|
const label = result?.label;
|
||||||
|
expect(label).to.eql(
|
||||||
|
expectedLabel,
|
||||||
|
`First result should be ${expectedLabel} (got matching items '${label}')`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await PageObjects.svlCommonNavigation.search.hideSearch();
|
||||||
|
});
|
||||||
|
it('has the correct features disabled', async () => {
|
||||||
|
await PageObjects.svlCommonNavigation.search.showSearch();
|
||||||
|
|
||||||
|
const notExpectedLabels = allLabels.filter((l) => !l.expected).map((l) => l.label);
|
||||||
|
|
||||||
|
for (const notExpectedLabel of notExpectedLabels) {
|
||||||
|
await PageObjects.svlCommonNavigation.search.searchFor(notExpectedLabel);
|
||||||
|
const [result] = await PageObjects.svlCommonNavigation.search.getDisplayedResults();
|
||||||
|
const label = result?.label;
|
||||||
|
expect(label).to.not.eql(
|
||||||
|
notExpectedLabel,
|
||||||
|
`First result should not be ${notExpectedLabel} (got matching items '${label}')`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await PageObjects.svlCommonNavigation.search.hideSearch();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||||
|
const ml = getService('ml');
|
||||||
|
const PageObjects = getPageObjects(['svlCommonPage']);
|
||||||
|
|
||||||
|
describe('Trained models list', () => {
|
||||||
|
before(async () => {
|
||||||
|
await PageObjects.svlCommonPage.login();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await PageObjects.svlCommonPage.forceLogout();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('page navigation', () => {
|
||||||
|
it('renders trained models list', async () => {
|
||||||
|
await ml.navigation.navigateToMl();
|
||||||
|
await ml.testExecution.logTestStep('should load the trained models page');
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep(
|
||||||
|
'should display the stats bar and the analytics table with 1 installed trained model and built in elser models in the table'
|
||||||
|
);
|
||||||
|
await ml.trainedModels.assertStats(1);
|
||||||
|
await ml.trainedModelsTable.assertTableIsPopulated();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -18,5 +18,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
||||||
loadTestFile(require.resolve('./ftr/cases/configure'));
|
loadTestFile(require.resolve('./ftr/cases/configure'));
|
||||||
loadTestFile(require.resolve('./ftr/cases/list_view'));
|
loadTestFile(require.resolve('./ftr/cases/list_view'));
|
||||||
loadTestFile(require.resolve('./advanced_settings'));
|
loadTestFile(require.resolve('./advanced_settings'));
|
||||||
|
loadTestFile(require.resolve('./ml'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||||
|
const ml = getService('ml');
|
||||||
|
const svlMl = getService('svlMl');
|
||||||
|
const PageObjects = getPageObjects(['svlCommonPage']);
|
||||||
|
const adJobId = 'fq_single_permission';
|
||||||
|
|
||||||
|
describe('Anomaly detection jobs list', () => {
|
||||||
|
before(async () => {
|
||||||
|
await PageObjects.svlCommonPage.login();
|
||||||
|
|
||||||
|
await ml.api.createAnomalyDetectionJob(ml.commonConfig.getADFqMultiMetricJobConfig(adJobId));
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await PageObjects.svlCommonPage.forceLogout();
|
||||||
|
await ml.api.cleanMlIndices();
|
||||||
|
await ml.testResources.cleanMLSavedObjects();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('page navigation', () => {
|
||||||
|
it('renders job list and finds created job', async () => {
|
||||||
|
await ml.navigation.navigateToMl();
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('loads the anomaly detection area');
|
||||||
|
await svlMl.navigation.security.navigateToAnomalyDetection();
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('should display the stats bar and the AD job table');
|
||||||
|
await ml.jobManagement.assertJobStatsBarExists();
|
||||||
|
await ml.jobManagement.assertJobTableExists();
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('should display an enabled "Create job" button');
|
||||||
|
await ml.jobManagement.assertCreateNewJobButtonExists();
|
||||||
|
await ml.jobManagement.assertCreateNewJobButtonEnabled(true);
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('should display the AD job in the list');
|
||||||
|
await ml.jobTable.filterWithSearchString(adJobId, 1);
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('should display enabled AD job result links');
|
||||||
|
await ml.jobTable.assertJobActionSingleMetricViewerButtonEnabled(adJobId, true);
|
||||||
|
await ml.jobTable.assertJobActionAnomalyExplorerButtonEnabled(adJobId, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||||
|
const esArchiver = getService('esArchiver');
|
||||||
|
const ml = getService('ml');
|
||||||
|
const svlMl = getService('svlMl');
|
||||||
|
const PageObjects = getPageObjects(['svlCommonPage']);
|
||||||
|
const dfaJobId = 'iph_outlier_permission';
|
||||||
|
|
||||||
|
describe('Data frame analytics jobs list', () => {
|
||||||
|
before(async () => {
|
||||||
|
await PageObjects.svlCommonPage.login();
|
||||||
|
|
||||||
|
await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ihp_outlier');
|
||||||
|
await ml.testResources.createIndexPatternIfNeeded('ft_ihp_outlier', '@timestamp');
|
||||||
|
|
||||||
|
await ml.api.createDataFrameAnalyticsJob(
|
||||||
|
ml.commonConfig.getDFAIhpOutlierDetectionJobConfig(dfaJobId)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await PageObjects.svlCommonPage.forceLogout();
|
||||||
|
await ml.api.cleanMlIndices();
|
||||||
|
await ml.testResources.cleanMLSavedObjects();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('page navigation', () => {
|
||||||
|
it('renders job list and finds created job', async () => {
|
||||||
|
await ml.testExecution.logTestStep('should load the DFA job management page');
|
||||||
|
await svlMl.navigation.security.navigateToDataFrameAnalytics();
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('should display the stats bar and the analytics table');
|
||||||
|
await ml.dataFrameAnalytics.assertAnalyticsStatsBarExists();
|
||||||
|
await ml.dataFrameAnalytics.assertAnalyticsTableExists();
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('should display an enabled "Create job" button');
|
||||||
|
await ml.dataFrameAnalytics.assertCreateNewAnalyticsButtonExists();
|
||||||
|
await ml.dataFrameAnalytics.assertCreateNewAnalyticsButtonEnabled(true);
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep('should display the DFA job in the list');
|
||||||
|
await ml.dataFrameAnalyticsTable.filterWithSearchString(dfaJobId, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||||
|
describe('Security ML', function () {
|
||||||
|
loadTestFile(require.resolve('./anomaly_detection_jobs_list'));
|
||||||
|
loadTestFile(require.resolve('./data_frame_analytics_jobs_list'));
|
||||||
|
loadTestFile(require.resolve('./trained_models_list'));
|
||||||
|
loadTestFile(require.resolve('./search_bar_features'));
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* 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 default function ({ getPageObjects }: FtrProviderContext) {
|
||||||
|
const PageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation']);
|
||||||
|
|
||||||
|
const allLabels = [
|
||||||
|
{ label: 'Machine Learning', expected: true },
|
||||||
|
{ label: 'Machine Learning / Overview', expected: true },
|
||||||
|
{ label: 'Machine Learning / Anomaly Detection', expected: true },
|
||||||
|
{ label: 'Machine Learning / Anomaly Detection / Anomaly explorer', expected: true },
|
||||||
|
{ label: 'Machine Learning / Anomaly Detection / Single metric viewer', expected: true },
|
||||||
|
{ label: 'Machine Learning / Data Frame Analytics', expected: true },
|
||||||
|
{ label: 'Machine Learning / Data Frame Analytics / Results explorer', expected: true },
|
||||||
|
{ label: 'Machine Learning / Data Frame Analytics / Analytics map', expected: true },
|
||||||
|
{ label: 'Machine Learning / Model Management', expected: true },
|
||||||
|
{ label: 'Machine Learning / Model Management / Trained Models', expected: true },
|
||||||
|
{ label: 'Machine Learning / Model Management / Nodes', expected: false },
|
||||||
|
{ label: 'Machine Learning / Memory Usage', expected: true },
|
||||||
|
{ label: 'Machine Learning / Settings', expected: true },
|
||||||
|
{ label: 'Machine Learning / Settings / Calendars', expected: true },
|
||||||
|
{ label: 'Machine Learning / Settings / Filter Lists', expected: true },
|
||||||
|
{ label: 'Machine Learning / AIOps', expected: true },
|
||||||
|
{ label: 'Machine Learning / AIOps / Log Rate Analysis', expected: true },
|
||||||
|
{ label: 'Machine Learning / AIOps / Log Pattern Analysis', expected: true },
|
||||||
|
{ label: 'Machine Learning / AIOps / Change Point Detection', expected: true },
|
||||||
|
{ label: 'Machine Learning / Notifications', expected: true },
|
||||||
|
{ label: 'Machine Learning / Data Visualizer', expected: true },
|
||||||
|
{ label: 'Machine Learning / File Upload', expected: true },
|
||||||
|
{ label: 'Machine Learning / Index Data Visualizer', expected: true },
|
||||||
|
{ label: 'Machine Learning / Data Drift', expected: true },
|
||||||
|
{ label: 'Alerts and Insights / Machine Learning', expected: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('Search bar features', () => {
|
||||||
|
before(async () => {
|
||||||
|
await PageObjects.svlCommonPage.login();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await PageObjects.svlCommonPage.forceLogout();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('list features', () => {
|
||||||
|
it('has the correct features enabled', async () => {
|
||||||
|
await PageObjects.svlCommonNavigation.search.showSearch();
|
||||||
|
|
||||||
|
const expectedLabels = allLabels.filter((l) => l.expected).map((l) => l.label);
|
||||||
|
|
||||||
|
for (const expectedLabel of expectedLabels) {
|
||||||
|
await PageObjects.svlCommonNavigation.search.searchFor(expectedLabel);
|
||||||
|
const [result] = await PageObjects.svlCommonNavigation.search.getDisplayedResults();
|
||||||
|
const label = result?.label;
|
||||||
|
expect(label).to.eql(
|
||||||
|
expectedLabel,
|
||||||
|
`First result should be ${expectedLabel} (got matching items '${label}')`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await PageObjects.svlCommonNavigation.search.hideSearch();
|
||||||
|
});
|
||||||
|
it('has the correct features disabled', async () => {
|
||||||
|
await PageObjects.svlCommonNavigation.search.showSearch();
|
||||||
|
|
||||||
|
const notExpectedLabels = allLabels.filter((l) => !l.expected).map((l) => l.label);
|
||||||
|
|
||||||
|
for (const notExpectedLabel of notExpectedLabels) {
|
||||||
|
await PageObjects.svlCommonNavigation.search.searchFor(notExpectedLabel);
|
||||||
|
const [result] = await PageObjects.svlCommonNavigation.search.getDisplayedResults();
|
||||||
|
const label = result?.label;
|
||||||
|
expect(label).to.not.eql(
|
||||||
|
notExpectedLabel,
|
||||||
|
`First result should not be ${notExpectedLabel} (got matching items '${label}')`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await PageObjects.svlCommonNavigation.search.hideSearch();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||||
|
const ml = getService('ml');
|
||||||
|
const svlMl = getService('svlMl');
|
||||||
|
const PageObjects = getPageObjects(['svlCommonPage']);
|
||||||
|
|
||||||
|
describe('Trained models list', () => {
|
||||||
|
before(async () => {
|
||||||
|
await PageObjects.svlCommonPage.login();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await PageObjects.svlCommonPage.forceLogout();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('page navigation', () => {
|
||||||
|
it('renders trained models list', async () => {
|
||||||
|
await ml.navigation.navigateToMl();
|
||||||
|
await ml.testExecution.logTestStep('should load the trained models page');
|
||||||
|
await svlMl.navigation.security.navigateToTrainedModels();
|
||||||
|
|
||||||
|
await ml.testExecution.logTestStep(
|
||||||
|
'should display the stats bar and the analytics table with no trained models'
|
||||||
|
);
|
||||||
|
await ml.trainedModels.assertStats(0);
|
||||||
|
await ml.trainedModelsTable.assertTableIsNotPopulated();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue