mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
# Backport This will backport the following commits from `main` to `8.5`: - [[ML] Adds anomaly alerts screenshot test suite (#146552)](https://github.com/elastic/kibana/pull/146552) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"István Zoltán Szabó","email":"szabosteve@gmail.com"},"sourceCommit":{"committedDate":"2022-12-02T10:01:51Z","message":"[ML] Adds anomaly alerts screenshot test suite (#146552)\n\n## Summary\r\n\r\nThis PR adds a new test suite to the screenshot creation script that\r\ncovers the screenshots on [Generating alerts for anomaly detection\r\njobs](https://www.elastic.co/guide/en/machine-learning/master/ml-configuring-alerts.html).","sha":"475e47ed993fba0ecd69caa211150f298e1eefe4","branchLabelMapping":{"^v8.7.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":[":ml","release_note:skip","v8.6.0","v8.7.0","v8.5.3"],"number":146552,"url":"https://github.com/elastic/kibana/pull/146552","mergeCommit":{"message":"[ML] Adds anomaly alerts screenshot test suite (#146552)\n\n## Summary\r\n\r\nThis PR adds a new test suite to the screenshot creation script that\r\ncovers the screenshots on [Generating alerts for anomaly detection\r\njobs](https://www.elastic.co/guide/en/machine-learning/master/ml-configuring-alerts.html).","sha":"475e47ed993fba0ecd69caa211150f298e1eefe4"}},"sourceBranch":"main","suggestedTargetBranches":["8.6","8.5"],"targetPullRequestStates":[{"branch":"8.6","label":"v8.6.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.7.0","labelRegex":"^v8.7.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/146552","number":146552,"mergeCommit":{"message":"[ML] Adds anomaly alerts screenshot test suite (#146552)\n\n## Summary\r\n\r\nThis PR adds a new test suite to the screenshot creation script that\r\ncovers the screenshots on [Generating alerts for anomaly detection\r\njobs](https://www.elastic.co/guide/en/machine-learning/master/ml-configuring-alerts.html).","sha":"475e47ed993fba0ecd69caa211150f298e1eefe4"}},{"branch":"8.5","label":"v8.5.3","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: István Zoltán Szabó <szabosteve@gmail.com>
This commit is contained in:
parent
644c49d944
commit
36b9290cb1
6 changed files with 238 additions and 5 deletions
|
@ -171,6 +171,9 @@ export default async function ({ readConfigFile }) {
|
|||
connectors: {
|
||||
pathname: '/app/management/insightsAndAlerting/triggersActions/connectors',
|
||||
},
|
||||
triggersActions: {
|
||||
pathname: '/app/management/insightsAndAlerting/triggersActions',
|
||||
},
|
||||
},
|
||||
|
||||
// choose where screenshots should be saved
|
||||
|
|
|
@ -9,6 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context';
|
|||
|
||||
export function ActionsAPIServiceProvider({ getService }: FtrProviderContext) {
|
||||
const kbnSupertest = getService('supertest');
|
||||
const log = getService('log');
|
||||
|
||||
return {
|
||||
async createConnector({
|
||||
|
@ -37,10 +38,24 @@ export function ActionsAPIServiceProvider({ getService }: FtrProviderContext) {
|
|||
},
|
||||
|
||||
async deleteConnector(id: string) {
|
||||
return kbnSupertest
|
||||
log.debug(`Deleting connector with id '${id}'...`);
|
||||
const rsp = kbnSupertest
|
||||
.delete(`/api/actions/connector/${id}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.expect(204, '');
|
||||
log.debug('> Connector deleted.');
|
||||
return rsp;
|
||||
},
|
||||
|
||||
async deleteAllConnectors() {
|
||||
const { body } = await kbnSupertest
|
||||
.get(`/api/actions/connectors`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.expect(200);
|
||||
|
||||
for (const connector of body) {
|
||||
await this.deleteConnector(connector.id);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -26,9 +26,9 @@ export function MachineLearningAlertingProvider(
|
|||
|
||||
return {
|
||||
async selectAnomalyDetectionAlertType() {
|
||||
await testSubjects.click('xpack.ml.anomaly_detection_alert-SelectOption');
|
||||
await retry.tryForTime(5000, async () => {
|
||||
await testSubjects.existOrFail(`mlAnomalyAlertForm`);
|
||||
await testSubjects.click('xpack.ml.anomaly_detection_alert-SelectOption');
|
||||
await testSubjects.existOrFail(`mlAnomalyAlertForm`, { timeout: 1000 });
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -50,8 +50,14 @@ export function MachineLearningAlertingProvider(
|
|||
},
|
||||
|
||||
async selectResultType(resultType: string) {
|
||||
await testSubjects.click(`mlAnomalyAlertResult_${resultType}`);
|
||||
await this.assertResultTypeSelection(resultType);
|
||||
if (
|
||||
(await testSubjects.exists(`mlAnomalyAlertResult_${resultType}_selected`, {
|
||||
timeout: 1000,
|
||||
})) === false
|
||||
) {
|
||||
await testSubjects.click(`mlAnomalyAlertResult_${resultType}`);
|
||||
await this.assertResultTypeSelection(resultType);
|
||||
}
|
||||
},
|
||||
|
||||
async assertResultTypeSelection(resultType: string) {
|
||||
|
@ -168,5 +174,56 @@ export function MachineLearningAlertingProvider(
|
|||
mlApi.assertResponseStatusCode(204, status, body);
|
||||
}
|
||||
},
|
||||
|
||||
async openNotifySelection() {
|
||||
await retry.tryForTime(5000, async () => {
|
||||
await testSubjects.click('notifyWhenSelect');
|
||||
await testSubjects.existOrFail('onActionGroupChange', { timeout: 1000 });
|
||||
});
|
||||
},
|
||||
|
||||
async setRuleName(rulename: string) {
|
||||
await testSubjects.setValue('ruleNameInput', rulename);
|
||||
},
|
||||
|
||||
async scrollRuleNameIntoView() {
|
||||
await testSubjects.scrollIntoView('ruleNameInput');
|
||||
},
|
||||
|
||||
async selectSlackConnectorType() {
|
||||
await retry.tryForTime(5000, async () => {
|
||||
await testSubjects.click('.slack-alerting-ActionTypeSelectOption');
|
||||
await testSubjects.existOrFail('createActionConnectorButton-0', { timeout: 1000 });
|
||||
});
|
||||
},
|
||||
|
||||
async clickCreateConnectorButton() {
|
||||
await retry.tryForTime(5000, async () => {
|
||||
await testSubjects.click('createActionConnectorButton-0');
|
||||
await testSubjects.existOrFail('connectorAddModal', { timeout: 1000 });
|
||||
});
|
||||
},
|
||||
|
||||
async setConnectorName(connectorname: string) {
|
||||
await testSubjects.setValue('nameInput', connectorname);
|
||||
},
|
||||
|
||||
async setWebhookUrl(webhookurl: string) {
|
||||
await testSubjects.setValue('slackWebhookUrlInput', webhookurl);
|
||||
},
|
||||
|
||||
async clickSaveActionButton() {
|
||||
await retry.tryForTime(5000, async () => {
|
||||
await testSubjects.click('saveActionButtonModal');
|
||||
await testSubjects.existOrFail('addNewActionConnectorActionGroup-0', { timeout: 1000 });
|
||||
});
|
||||
},
|
||||
|
||||
async openAddRuleVariable() {
|
||||
await retry.tryForTime(5000, async () => {
|
||||
await testSubjects.click('messageAddVariableButton');
|
||||
await testSubjects.existOrFail('variableMenuButton-alert.actionGroup', { timeout: 1000 });
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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 type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { DATAFEED_STATE } from '@kbn/ml-plugin/common/constants/states';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
import { ECOMMERCE_INDEX_PATTERN } from '..';
|
||||
|
||||
function createTestJobAndDatafeed() {
|
||||
const timestamp = Date.now();
|
||||
const jobId = `high_sum_total_sales_${timestamp}`;
|
||||
|
||||
return {
|
||||
job: {
|
||||
job_id: jobId,
|
||||
description: 'test_job',
|
||||
groups: ['ecommerce'],
|
||||
analysis_config: {
|
||||
bucket_span: '1h',
|
||||
detectors: [
|
||||
{
|
||||
detector_description: 'High total sales',
|
||||
function: 'high_sum',
|
||||
field_name: 'taxful_total_price',
|
||||
over_field_name: 'customer_full_name.keyword',
|
||||
detector_index: 0,
|
||||
},
|
||||
],
|
||||
influencers: ['customer_full_name.keyword', 'category.keyword'],
|
||||
},
|
||||
data_description: {
|
||||
time_field: 'order_date',
|
||||
time_format: 'epoch_ms',
|
||||
},
|
||||
analysis_limits: {
|
||||
model_memory_limit: '13mb',
|
||||
categorization_examples_limit: 4,
|
||||
},
|
||||
},
|
||||
datafeed: {
|
||||
datafeed_id: `datafeed-${jobId}`,
|
||||
job_id: jobId,
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
match_all: {},
|
||||
},
|
||||
],
|
||||
filter: [],
|
||||
must_not: [],
|
||||
},
|
||||
},
|
||||
query_delay: '120s',
|
||||
indices: [ECOMMERCE_INDEX_PATTERN],
|
||||
} as unknown as estypes.MlDatafeed,
|
||||
};
|
||||
}
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const ml = getService('ml');
|
||||
const pageObjects = getPageObjects(['triggersActionsUI']);
|
||||
const commonScreenshots = getService('commonScreenshots');
|
||||
const browser = getService('browser');
|
||||
const actions = getService('actions');
|
||||
|
||||
const screenshotDirectories = ['ml_docs', 'anomaly_detection'];
|
||||
|
||||
let testJobId = '';
|
||||
|
||||
describe('anomaly detection alert', function () {
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce');
|
||||
await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date');
|
||||
|
||||
const { job, datafeed } = createTestJobAndDatafeed();
|
||||
|
||||
testJobId = job.job_id;
|
||||
|
||||
// Set up jobs
|
||||
// @ts-expect-error not full interface
|
||||
await ml.api.createAnomalyDetectionJob(job);
|
||||
await ml.api.openAnomalyDetectionJob(job.job_id);
|
||||
await ml.api.createDatafeed(datafeed);
|
||||
await ml.api.startDatafeed(datafeed.datafeed_id);
|
||||
await ml.api.waitForDatafeedState(datafeed.datafeed_id, DATAFEED_STATE.STARTED);
|
||||
await ml.api.assertJobResultsExist(job.job_id);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await ml.api.deleteAnomalyDetectionJobES(testJobId);
|
||||
await ml.api.cleanMlIndices();
|
||||
await ml.alerting.cleanAnomalyDetectionRules();
|
||||
await actions.api.deleteAllConnectors();
|
||||
});
|
||||
|
||||
describe('overview page alert flyout controls', () => {
|
||||
it('alert flyout screenshot', async () => {
|
||||
await ml.navigation.navigateToAlertsAndAction();
|
||||
await pageObjects.triggersActionsUI.clickCreateAlertButton();
|
||||
await ml.alerting.setRuleName('test-ecommerce');
|
||||
|
||||
await ml.alerting.openNotifySelection();
|
||||
await commonScreenshots.takeScreenshot('ml-rule', screenshotDirectories, 1920, 1400);
|
||||
|
||||
// close popover
|
||||
await browser.pressKeys(browser.keys.ESCAPE);
|
||||
|
||||
await ml.alerting.selectAnomalyDetectionAlertType();
|
||||
await ml.testExecution.logTestStep('should have correct default values');
|
||||
await ml.alerting.assertSeverity(75);
|
||||
await ml.alerting.assertPreviewButtonState(false);
|
||||
await ml.testExecution.logTestStep('should complete the alert params');
|
||||
await ml.alerting.selectJobs([testJobId]);
|
||||
await ml.alerting.selectResultType('bucket');
|
||||
await ml.alerting.setSeverity(75);
|
||||
await ml.testExecution.logTestStep('should populate advanced settings with default values');
|
||||
await ml.alerting.assertTopNBuckets(1);
|
||||
await ml.alerting.assertLookbackInterval('123m');
|
||||
await ml.testExecution.logTestStep('should preview the alert condition');
|
||||
await ml.alerting.assertPreviewButtonState(false);
|
||||
await ml.alerting.setTestInterval('1y');
|
||||
await ml.alerting.assertPreviewButtonState(true);
|
||||
await ml.alerting.scrollRuleNameIntoView();
|
||||
await ml.testExecution.logTestStep('take screenshot');
|
||||
await commonScreenshots.takeScreenshot(
|
||||
'ml-anomaly-alert-severity',
|
||||
screenshotDirectories,
|
||||
1920,
|
||||
1400
|
||||
);
|
||||
await ml.alerting.selectSlackConnectorType();
|
||||
await ml.testExecution.logTestStep('should open connectors');
|
||||
await ml.alerting.clickCreateConnectorButton();
|
||||
await ml.alerting.setConnectorName('test-connector');
|
||||
await ml.alerting.setWebhookUrl('https://www.elastic.co');
|
||||
await ml.alerting.clickSaveActionButton();
|
||||
await ml.alerting.openAddRuleVariable();
|
||||
await ml.testExecution.logTestStep('take screenshot');
|
||||
await commonScreenshots.takeScreenshot(
|
||||
'ml-anomaly-alert-messages',
|
||||
screenshotDirectories,
|
||||
1920,
|
||||
1400
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -10,6 +10,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context';
|
|||
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||
describe('anomaly detection', function () {
|
||||
loadTestFile(require.resolve('./geographic_data'));
|
||||
loadTestFile(require.resolve('./generate_anomaly_alerts'));
|
||||
loadTestFile(require.resolve('./population_analysis'));
|
||||
loadTestFile(require.resolve('./custom_urls'));
|
||||
loadTestFile(require.resolve('./mapping_anomalies'));
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import Fs from 'fs';
|
||||
import { CA_CERT_PATH } from '@kbn/dev-utils';
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
import { pageObjects } from './page_objects';
|
||||
import { services } from './services';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
|
@ -28,6 +29,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
// default to the xpack functional config
|
||||
...xpackFunctionalConfig.getAll(),
|
||||
servers,
|
||||
pageObjects,
|
||||
services,
|
||||
testFiles: [require.resolve('./apps')],
|
||||
junit: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue