mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[Observability] add custom threshold functional test (#184602)](https://github.com/elastic/kibana/pull/184602) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Dominique Clarke","email":"dominique.clarke@elastic.co"},"sourceCommit":{"committedDate":"2024-09-18T07:56:58Z","message":"[Observability] add custom threshold functional test (#184602)\n\nCloses #175301\r\n\r\n## Summary\r\n\r\nResolves\r\nhttps://github.com/orgs/elastic/projects/1375/views/1?pane=issue&itemId=50879015\r\n\r\nTo run\r\n```\r\ncd x-pack && node ../scripts/functional_tests_server --config=test/observability_functional/with_rac_write.config.ts\r\n\r\nor\r\n\r\nnode scripts/functional_tests_server.js --config x-pack/test/observability_functional/with_rac_write.config.ts\r\n```\r\nIn a different terminal\r\n```\r\nnode ../scripts/functional_test_runner --config=test/observability_functional/with_rac_write.config.ts --grep \"Custom threshold rule\"\r\n\r\nor\r\n\r\nnode scripts/functional_test_runner --config=x-pack/test/observability_functional/with_rac_write.config.ts --grep \"Custom threshold rule\"\r\n```\r\n\r\n---------\r\n\r\nCo-authored-by: Maryam Saeidi <maryam.saeidi@elastic.co>","sha":"0241cf690c631d4865b9c412240ab49357646a26","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["chore","release_note:skip","v9.0.0","ci:project-deploy-observability","Team:obs-ux-management","v8.16.0"],"title":"[Observability] add custom threshold functional test","number":184602,"url":"https://github.com/elastic/kibana/pull/184602","mergeCommit":{"message":"[Observability] add custom threshold functional test (#184602)\n\nCloses #175301\r\n\r\n## Summary\r\n\r\nResolves\r\nhttps://github.com/orgs/elastic/projects/1375/views/1?pane=issue&itemId=50879015\r\n\r\nTo run\r\n```\r\ncd x-pack && node ../scripts/functional_tests_server --config=test/observability_functional/with_rac_write.config.ts\r\n\r\nor\r\n\r\nnode scripts/functional_tests_server.js --config x-pack/test/observability_functional/with_rac_write.config.ts\r\n```\r\nIn a different terminal\r\n```\r\nnode ../scripts/functional_test_runner --config=test/observability_functional/with_rac_write.config.ts --grep \"Custom threshold rule\"\r\n\r\nor\r\n\r\nnode scripts/functional_test_runner --config=x-pack/test/observability_functional/with_rac_write.config.ts --grep \"Custom threshold rule\"\r\n```\r\n\r\n---------\r\n\r\nCo-authored-by: Maryam Saeidi <maryam.saeidi@elastic.co>","sha":"0241cf690c631d4865b9c412240ab49357646a26"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/184602","number":184602,"mergeCommit":{"message":"[Observability] add custom threshold functional test (#184602)\n\nCloses #175301\r\n\r\n## Summary\r\n\r\nResolves\r\nhttps://github.com/orgs/elastic/projects/1375/views/1?pane=issue&itemId=50879015\r\n\r\nTo run\r\n```\r\ncd x-pack && node ../scripts/functional_tests_server --config=test/observability_functional/with_rac_write.config.ts\r\n\r\nor\r\n\r\nnode scripts/functional_tests_server.js --config x-pack/test/observability_functional/with_rac_write.config.ts\r\n```\r\nIn a different terminal\r\n```\r\nnode ../scripts/functional_test_runner --config=test/observability_functional/with_rac_write.config.ts --grep \"Custom threshold rule\"\r\n\r\nor\r\n\r\nnode scripts/functional_test_runner --config=x-pack/test/observability_functional/with_rac_write.config.ts --grep \"Custom threshold rule\"\r\n```\r\n\r\n---------\r\n\r\nCo-authored-by: Maryam Saeidi <maryam.saeidi@elastic.co>","sha":"0241cf690c631d4865b9c412240ab49357646a26"}},{"branch":"8.x","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Dominique Clarke <dominique.clarke@elastic.co>
This commit is contained in:
parent
4b862c0794
commit
a197fb196b
12 changed files with 368 additions and 19 deletions
|
@ -142,7 +142,7 @@ export function MetricRowWithAgg({
|
|||
}
|
||||
>
|
||||
<EuiExpression
|
||||
data-test-subj="aggregationName"
|
||||
data-test-subj={`aggregationName${name}`}
|
||||
description={aggregationTypes[aggType].text}
|
||||
value={aggType === Aggregators.COUNT ? filter || DEFAULT_COUNT_FILTER_TITLE : field}
|
||||
isActive={aggTypePopoverOpen}
|
||||
|
@ -228,6 +228,7 @@ export function MetricRowWithAgg({
|
|||
options={fieldOptions}
|
||||
selectedOptions={field ? [{ label: field }] : []}
|
||||
onChange={handleFieldChange}
|
||||
data-test-subj="aggregationField"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
)}
|
||||
|
|
|
@ -166,7 +166,7 @@ export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
|
|||
<EuiFlexItem>
|
||||
<EuiFormRow label={LABEL_LABEL} fullWidth helpText={LABEL_HELP_MESSAGE}>
|
||||
<EuiFieldText
|
||||
data-test-subj="thresholdRuleCustomEquationEditorFieldText"
|
||||
data-test-subj="thresholdRuleCustomEquationEditorFieldTextLabel"
|
||||
compressed
|
||||
fullWidth
|
||||
value={label}
|
||||
|
|
|
@ -12,13 +12,18 @@ import { EuiPopoverTitle, EuiFlexGroup, EuiFlexItem, EuiButtonIcon } from '@elas
|
|||
interface ClosablePopoverTitleProps {
|
||||
children: JSX.Element;
|
||||
onClose: () => void;
|
||||
dataTestSubj?: string;
|
||||
}
|
||||
|
||||
export const ClosablePopoverTitle = ({ children, onClose }: ClosablePopoverTitleProps) => {
|
||||
export const ClosablePopoverTitle = ({
|
||||
children,
|
||||
onClose,
|
||||
dataTestSubj,
|
||||
}: ClosablePopoverTitleProps) => {
|
||||
return (
|
||||
<EuiPopoverTitle>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="s">
|
||||
<EuiFlexItem>{children}</EuiFlexItem>
|
||||
<EuiFlexItem data-test-subj={dataTestSubj}>{children}</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
iconType="cross"
|
||||
|
|
|
@ -89,10 +89,10 @@ describe('threshold expression', () => {
|
|||
|
||||
wrapper.find('[data-test-subj="thresholdPopover"]').last().simulate('click');
|
||||
expect(wrapper.find('[data-test-subj="comparatorOptionsComboBox"]').exists()).toBeTruthy();
|
||||
expect(wrapper.find('[data-test-subj="alertThresholdInput"]').exists()).toBeTruthy();
|
||||
expect(wrapper.find('[data-test-subj="alertThresholdInput0"]').exists()).toBeTruthy();
|
||||
|
||||
wrapper
|
||||
.find('[data-test-subj="alertThresholdInput"]')
|
||||
.find('[data-test-subj="alertThresholdInput0"]')
|
||||
.last()
|
||||
.simulate('change', { target: { value: 1000 } });
|
||||
expect(onChangeSelectedThreshold).toHaveBeenCalled();
|
||||
|
@ -145,21 +145,22 @@ describe('threshold expression', () => {
|
|||
|
||||
wrapper.find('[data-test-subj="thresholdPopover"]').last().simulate('click');
|
||||
expect(wrapper.find('[data-test-subj="comparatorOptionsComboBox"]').exists()).toBeTruthy();
|
||||
expect(wrapper.find('input[data-test-subj="alertThresholdInput"]').length).toEqual(1);
|
||||
expect(wrapper.find('input[data-test-subj="alertThresholdInput0"]').length).toEqual(1);
|
||||
|
||||
wrapper
|
||||
.find('[data-test-subj="comparatorOptionsComboBox"]')
|
||||
.last()
|
||||
.simulate('change', { target: { value: 'between' } });
|
||||
wrapper.update();
|
||||
expect(wrapper.find('input[data-test-subj="alertThresholdInput"]').length).toEqual(2);
|
||||
expect(wrapper.find('input[data-test-subj="alertThresholdInput0"]').length).toEqual(1);
|
||||
expect(wrapper.find('input[data-test-subj="alertThresholdInput1"]').length).toEqual(1);
|
||||
|
||||
wrapper
|
||||
.find('[data-test-subj="comparatorOptionsComboBox"]')
|
||||
.last()
|
||||
.simulate('change', { target: { value: '<' } });
|
||||
wrapper.update();
|
||||
expect(wrapper.find('input[data-test-subj="alertThresholdInput"]').length).toEqual(1);
|
||||
expect(wrapper.find('input[data-test-subj="alertThresholdInput0"]').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('is valid when the threshold value is 0', () => {
|
||||
|
@ -174,9 +175,9 @@ describe('threshold expression', () => {
|
|||
onChangeSelectedThresholdComparator={onChangeSelectedThresholdComparator}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="alertThresholdInput"]')).toMatchInlineSnapshot(`
|
||||
expect(wrapper.find('[data-test-subj="alertThresholdInput0"]')).toMatchInlineSnapshot(`
|
||||
<EuiFieldNumber
|
||||
data-test-subj="alertThresholdInput"
|
||||
data-test-subj="alertThresholdInput0"
|
||||
isInvalid={false}
|
||||
min={0}
|
||||
onChange={[Function]}
|
||||
|
|
|
@ -120,7 +120,10 @@ export const ThresholdExpression = ({
|
|||
repositionOnScroll
|
||||
>
|
||||
<div>
|
||||
<ClosablePopoverTitle onClose={() => setAlertThresholdPopoverOpen(false)}>
|
||||
<ClosablePopoverTitle
|
||||
onClose={() => setAlertThresholdPopoverOpen(false)}
|
||||
dataTestSubj="thresholdPopoverTitle"
|
||||
>
|
||||
<>{comparators[comparator].text}</>
|
||||
</ClosablePopoverTitle>
|
||||
<EuiFlexGroup>
|
||||
|
@ -154,7 +157,7 @@ export const ThresholdExpression = ({
|
|||
error={errors[`threshold${i}`] as string[]}
|
||||
>
|
||||
<EuiFieldNumber
|
||||
data-test-subj="alertThresholdInput"
|
||||
data-test-subj={`alertThresholdInput${i}`}
|
||||
min={0}
|
||||
value={!threshold || threshold[i] === undefined ? '' : threshold[i]}
|
||||
isInvalid={Number(errors[`threshold${i}`]?.length) > 0 || isNil(threshold[i])}
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { ToolingLog } from '@kbn/tooling-log';
|
||||
import { chunk } from 'lodash';
|
||||
import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED, AlertStatus } from '@kbn/rule-data-utils';
|
||||
import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services';
|
||||
import { Agent as SuperTestAgent } from 'supertest';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
// Based on the x-pack/test/functional/es_archives/observability/alerts archive.
|
||||
|
@ -314,6 +316,69 @@ export function ObservabilityAlertsCommonProvider({
|
|||
return value;
|
||||
});
|
||||
|
||||
// Data view
|
||||
const createDataView = async ({
|
||||
supertest,
|
||||
id,
|
||||
name,
|
||||
title,
|
||||
logger,
|
||||
}: {
|
||||
supertest: SuperTestAgent;
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
logger: ToolingLog;
|
||||
}) => {
|
||||
const { body } = await supertest
|
||||
.post(`/api/content_management/rpc/create`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send({
|
||||
contentTypeId: 'index-pattern',
|
||||
data: {
|
||||
fieldAttrs: '{}',
|
||||
title,
|
||||
timeFieldName: '@timestamp',
|
||||
sourceFilters: '[]',
|
||||
fields: '[]',
|
||||
fieldFormatMap: '{}',
|
||||
typeMeta: '{}',
|
||||
runtimeFieldMap: '{}',
|
||||
name,
|
||||
},
|
||||
options: { id },
|
||||
version: 1,
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
logger.debug(`Created data view: ${JSON.stringify(body)}`);
|
||||
return body;
|
||||
};
|
||||
|
||||
const deleteDataView = async ({
|
||||
supertest,
|
||||
id,
|
||||
logger,
|
||||
}: {
|
||||
supertest: SuperTestAgent;
|
||||
id: string;
|
||||
logger: ToolingLog;
|
||||
}) => {
|
||||
const { body } = await supertest
|
||||
.post(`/api/content_management/rpc/delete`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send({
|
||||
contentTypeId: 'index-pattern',
|
||||
id,
|
||||
options: { force: true },
|
||||
version: 1,
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
logger.debug(`Deleted data view id: ${id}`);
|
||||
return body;
|
||||
};
|
||||
|
||||
return {
|
||||
getQueryBar,
|
||||
clearQueryBar,
|
||||
|
@ -357,5 +422,7 @@ export function ObservabilityAlertsCommonProvider({
|
|||
navigateToRulesLogsPage,
|
||||
navigateToRuleDetailsByRuleId,
|
||||
navigateToAlertDetails,
|
||||
createDataView,
|
||||
deleteDataView,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
const METRIC_THRESHOLD_RULE_TYPE_SELECTOR = 'metrics.alert.threshold-SelectOption';
|
||||
const CUSTOM_THRESHOLD_RULE_TYPE_SELECTOR = 'observability.rules.custom_threshold-SelectOption';
|
||||
|
||||
export function ObservabilityAlertsRulesProvider({ getService }: FtrProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
|
@ -18,8 +19,9 @@ export function ObservabilityAlertsRulesProvider({ getService }: FtrProviderCont
|
|||
};
|
||||
|
||||
const clickCreateRuleButton = async () => {
|
||||
await testSubjects.existOrFail('createRuleButton');
|
||||
const createRuleButton = await testSubjects.find('createRuleButton');
|
||||
return createRuleButton.click();
|
||||
return await createRuleButton.click();
|
||||
};
|
||||
|
||||
const clickRuleStatusDropDownMenu = async () => testSubjects.click('statusDropdown');
|
||||
|
@ -33,6 +35,7 @@ export function ObservabilityAlertsRulesProvider({ getService }: FtrProviderCont
|
|||
};
|
||||
|
||||
const clickOnInfrastructureCategory = async () => {
|
||||
await testSubjects.existOrFail('ruleTypeModal');
|
||||
const categories = await testSubjects.find('ruleTypeModal');
|
||||
const category = await categories.findByCssSelector(`.euiFacetButton[title="Infrastructure"]`);
|
||||
await category.click();
|
||||
|
@ -43,6 +46,18 @@ export function ObservabilityAlertsRulesProvider({ getService }: FtrProviderCont
|
|||
await testSubjects.click(METRIC_THRESHOLD_RULE_TYPE_SELECTOR);
|
||||
};
|
||||
|
||||
const clickOnObservabilityCategory = async () => {
|
||||
await testSubjects.existOrFail('ruleTypeModal');
|
||||
const categories = await testSubjects.find('ruleTypeModal');
|
||||
const category = await categories.findByCssSelector(`.euiFacetButton[title="Observability"]`);
|
||||
await category.click();
|
||||
};
|
||||
|
||||
const clickOnCustomThresholdRule = async () => {
|
||||
await testSubjects.existOrFail(CUSTOM_THRESHOLD_RULE_TYPE_SELECTOR);
|
||||
await testSubjects.click(CUSTOM_THRESHOLD_RULE_TYPE_SELECTOR);
|
||||
};
|
||||
|
||||
return {
|
||||
getManageRulesPageHref,
|
||||
clickCreateRuleButton,
|
||||
|
@ -52,5 +67,7 @@ export function ObservabilityAlertsRulesProvider({ getService }: FtrProviderCont
|
|||
clickOnRuleInEventLogs,
|
||||
clickOnInfrastructureCategory,
|
||||
clickOnMetricThresholdRule,
|
||||
clickOnObservabilityCategory,
|
||||
clickOnCustomThresholdRule,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
return ruleName === alertName;
|
||||
});
|
||||
await testSubjects.click('thresholdPopover');
|
||||
await testSubjects.setValue('alertThresholdInput', '1');
|
||||
await testSubjects.setValue('alertThresholdInput0', '1');
|
||||
|
||||
await testSubjects.click('forLastExpression');
|
||||
await testSubjects.setValue('timeWindowSizeNumber', '30');
|
||||
|
@ -469,7 +469,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await filterBar.addFilter({ field: 'message.keyword', operation: 'is', value: 'msg-1' });
|
||||
|
||||
await testSubjects.click('thresholdPopover');
|
||||
await testSubjects.setValue('alertThresholdInput', '1');
|
||||
await testSubjects.setValue('alertThresholdInput0', '1');
|
||||
await testSubjects.click('saveEditedRuleButton');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
|||
loadTestFile(require.resolve('./pages/alerts/rule_stats'));
|
||||
loadTestFile(require.resolve('./pages/alerts/state_synchronization'));
|
||||
loadTestFile(require.resolve('./pages/alerts/table_storage'));
|
||||
loadTestFile(require.resolve('./pages/alerts/custom_threshold'));
|
||||
loadTestFile(require.resolve('./pages/cases/case_details'));
|
||||
loadTestFile(require.resolve('./pages/overview/alert_table'));
|
||||
loadTestFile(require.resolve('./exploratory_view'));
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* 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 { Key } from 'selenium-webdriver';
|
||||
import expect from 'expect';
|
||||
import { FtrProviderContext } from '../../../../ftr_provider_context';
|
||||
|
||||
export default ({ getService }: FtrProviderContext) => {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const supertest = getService('supertest');
|
||||
const find = getService('find');
|
||||
const logger = getService('log');
|
||||
const retry = getService('retry');
|
||||
|
||||
describe('Custom threshold rule', function () {
|
||||
this.tags('includeFirefox');
|
||||
|
||||
const observability = getService('observability');
|
||||
const DATA_VIEW_1 = 'filebeat-*';
|
||||
const DATA_VIEW_1_ID = 'data-view-id_1';
|
||||
const DATA_VIEW_1_NAME = 'test-data-view-name_1';
|
||||
const DATA_VIEW_2 = 'metricbeat-*';
|
||||
const DATA_VIEW_2_ID = 'data-view-id_2';
|
||||
const DATA_VIEW_2_NAME = 'test-data-view-name_2';
|
||||
|
||||
before(async () => {
|
||||
await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs');
|
||||
// create two data views
|
||||
await observability.alerts.common.createDataView({
|
||||
supertest,
|
||||
name: DATA_VIEW_1_NAME,
|
||||
id: DATA_VIEW_1_ID,
|
||||
title: DATA_VIEW_1,
|
||||
logger,
|
||||
});
|
||||
await observability.alerts.common.createDataView({
|
||||
supertest,
|
||||
name: DATA_VIEW_2_NAME,
|
||||
id: DATA_VIEW_2_ID,
|
||||
title: DATA_VIEW_2,
|
||||
logger,
|
||||
});
|
||||
await observability.alerts.common.navigateToRulesPage();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs');
|
||||
// This also deletes the created data views
|
||||
await kibanaServer.savedObjects.cleanStandardList();
|
||||
});
|
||||
|
||||
it('shows the custom threshold rule in the observability section', async () => {
|
||||
await observability.alerts.rulesPage.clickCreateRuleButton();
|
||||
await observability.alerts.rulesPage.clickOnObservabilityCategory();
|
||||
await observability.alerts.rulesPage.clickOnCustomThresholdRule();
|
||||
});
|
||||
|
||||
it('can add name and tags', async () => {
|
||||
await testSubjects.setValue('ruleNameInput', 'test custom threshold rule');
|
||||
await testSubjects.setValue('comboBoxSearchInput', 'tag1');
|
||||
});
|
||||
|
||||
it('can add data view', async () => {
|
||||
// select data view
|
||||
await testSubjects.click('selectDataViewExpression');
|
||||
await testSubjects.setValue('indexPattern-switcher--input', 'test-data-view-name_2');
|
||||
const dataViewExpression = await find.byCssSelector(
|
||||
'[data-test-subj="indexPattern-switcher--input"]'
|
||||
);
|
||||
await dataViewExpression.pressKeys(Key.ENTER);
|
||||
await retry.waitFor('data view selection to happen', async () => {
|
||||
const dataViewSelector = await testSubjects.find('selectDataViewExpression');
|
||||
return (await dataViewSelector.getVisibleText()) === 'DATA VIEW\ntest-data-view-name_2';
|
||||
});
|
||||
});
|
||||
|
||||
it('can select aggregation', async () => {
|
||||
// select aggregation
|
||||
await testSubjects.click('aggregationNameA');
|
||||
await testSubjects.click('aggregationTypeSelect');
|
||||
// assert all options are available
|
||||
await find.byCssSelector('option[value="avg"]');
|
||||
await find.byCssSelector('option[value="min"]');
|
||||
await find.byCssSelector('option[value="max"]');
|
||||
await find.byCssSelector('option[value="sum"]');
|
||||
await find.byCssSelector('option[value="count"]');
|
||||
await find.byCssSelector('option[value="cardinality"]');
|
||||
await find.byCssSelector('option[value="p99"]');
|
||||
await find.byCssSelector('option[value="p95"]');
|
||||
await find.byCssSelector('option[value="rate"]');
|
||||
|
||||
// set first aggregation
|
||||
await find.clickByCssSelector(`option[value="avg"]`);
|
||||
const input1 = await find.byCssSelector('[data-test-subj="aggregationField"] input');
|
||||
await input1.type('metricset.rtt');
|
||||
await testSubjects.click('o11yClosablePopoverTitleButton');
|
||||
await retry.waitFor('first aggregation to happen', async () => {
|
||||
const aggregationNameA = await testSubjects.find('aggregationNameA');
|
||||
return (await aggregationNameA.getVisibleText()) === 'AVERAGE\nmetricset.rtt';
|
||||
});
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
|
||||
// set second aggregation
|
||||
await testSubjects.click('thresholdRuleCustomEquationEditorAddAggregationFieldButton');
|
||||
await testSubjects.click('aggregationNameB');
|
||||
await testSubjects.setValue('o11ySearchField', 'service.name : "opbeans-node"');
|
||||
await testSubjects.click('o11yClosablePopoverTitleButton');
|
||||
await retry.waitFor('first aggregation to happen', async () => {
|
||||
const aggregationNameB = await testSubjects.find('aggregationNameB');
|
||||
return (await aggregationNameB.getVisibleText()) === 'COUNT\nservice.name : "opbeans-node"';
|
||||
});
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
});
|
||||
|
||||
it('can set custom equation', async () => {
|
||||
// set custom equation
|
||||
await testSubjects.click('customEquation');
|
||||
const customEquationField = await find.byCssSelector(
|
||||
'[data-test-subj="thresholdRuleCustomEquationEditorFieldText"]'
|
||||
);
|
||||
await customEquationField.click();
|
||||
await customEquationField.type('A - B');
|
||||
await testSubjects.click('o11yClosablePopoverTitleButton');
|
||||
await retry.waitFor('custom equation update to happen', async () => {
|
||||
const customEquation = await testSubjects.find('customEquation');
|
||||
return (await customEquation.getVisibleText()) === 'EQUATION\nA - B';
|
||||
});
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
});
|
||||
|
||||
it('can set threshold', async () => {
|
||||
// set threshold
|
||||
await testSubjects.click('thresholdPopover');
|
||||
await testSubjects.click('comparatorOptionsComboBox');
|
||||
// assert all options are available
|
||||
await find.byCssSelector('option[value=">="]');
|
||||
await find.byCssSelector('option[value="<="]');
|
||||
await find.byCssSelector('option[value=">"]');
|
||||
await find.byCssSelector('option[value="<"]');
|
||||
await find.byCssSelector('option[value="between"]');
|
||||
await find.byCssSelector('option[value="notBetween"]');
|
||||
// select an option
|
||||
await find.clickByCssSelector(`option[value="notBetween"]`);
|
||||
const thresholdField1 = await find.byCssSelector('[data-test-subj="alertThresholdInput0"]');
|
||||
await thresholdField1.click();
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
await thresholdField1.pressKeys(Key.BACK_SPACE);
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
await thresholdField1.pressKeys(Key.BACK_SPACE);
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
await thresholdField1.pressKeys(Key.BACK_SPACE);
|
||||
await thresholdField1.type('200');
|
||||
const thresholdField2 = await find.byCssSelector('[data-test-subj="alertThresholdInput1"]');
|
||||
await thresholdField2.type('250');
|
||||
await find.clickByCssSelector('[aria-label="Close"]');
|
||||
await retry.waitFor('comparator selection to happen', async () => {
|
||||
const customEquation = await testSubjects.find('thresholdPopover');
|
||||
return (await customEquation.getVisibleText()) === 'IS NOT BETWEEN\n200 AND 250';
|
||||
});
|
||||
});
|
||||
|
||||
it('can set equation label', async () => {
|
||||
// set equation label
|
||||
await testSubjects.setValue(
|
||||
'thresholdRuleCustomEquationEditorFieldTextLabel',
|
||||
'test equation'
|
||||
);
|
||||
});
|
||||
|
||||
it('can set time range', async () => {
|
||||
// set time range
|
||||
await testSubjects.click('forLastExpression');
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
const timeRangeField = await find.byCssSelector('[data-test-subj="timeWindowSizeNumber"]');
|
||||
await timeRangeField.click();
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
await timeRangeField.pressKeys(Key.BACK_SPACE);
|
||||
await timeRangeField.type('2');
|
||||
// assert all options are available
|
||||
await testSubjects.click('timeWindowUnitSelect');
|
||||
await find.byCssSelector('option[value="s"]');
|
||||
await find.byCssSelector('option[value="m"]');
|
||||
await find.byCssSelector('option[value="h"]');
|
||||
await find.byCssSelector('option[value="d"]');
|
||||
// select an option
|
||||
await new Promise((r) => setTimeout(r, 3000));
|
||||
await find.clickByCssSelector('[data-test-subj="timeWindowUnitSelect"] option[value="d"]');
|
||||
await find.clickByCssSelector('[aria-label="Close"]');
|
||||
});
|
||||
|
||||
it('can set groupby', async () => {
|
||||
// set group by
|
||||
const groupByField = await find.byCssSelector(
|
||||
'[data-test-subj="thresholdRuleMetricsExplorer-groupBy"] [data-test-subj="comboBoxSearchInput"]'
|
||||
);
|
||||
await groupByField.type('docker.container.name');
|
||||
});
|
||||
|
||||
it('can save the rule', async () => {
|
||||
await testSubjects.click('saveRuleButton');
|
||||
await testSubjects.click('confirmModalConfirmButton');
|
||||
await find.byCssSelector('button[title="test custom threshold rule"]');
|
||||
});
|
||||
|
||||
it('saved the rule correctly', async () => {
|
||||
const { body: rules } = await supertest.get('/internal/alerting/rules/_find');
|
||||
|
||||
expect(rules.data.length).toEqual(1);
|
||||
expect(rules.data[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
name: 'test custom threshold rule',
|
||||
tags: ['tag1'],
|
||||
params: expect.objectContaining({
|
||||
alertOnGroupDisappear: false,
|
||||
alertOnNoData: false,
|
||||
criteria: [
|
||||
{
|
||||
comparator: 'notBetween',
|
||||
label: 'test equation',
|
||||
equation: 'A - B',
|
||||
metrics: [
|
||||
{
|
||||
aggType: 'avg',
|
||||
field: 'metricset.rtt',
|
||||
name: 'A',
|
||||
},
|
||||
{
|
||||
aggType: 'count',
|
||||
filter: 'service.name : "opbeans-node"',
|
||||
name: 'B',
|
||||
},
|
||||
],
|
||||
threshold: [200, 250],
|
||||
timeSize: 2,
|
||||
timeUnit: 'd',
|
||||
},
|
||||
],
|
||||
groupBy: ['docker.container.name'],
|
||||
searchConfiguration: {
|
||||
index: 'data-view-id_2',
|
||||
query: { query: '', language: 'kuery' },
|
||||
},
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
|
@ -81,7 +81,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await nameInput1.click();
|
||||
|
||||
await testSubjects.click('thresholdPopover');
|
||||
await testSubjects.setValue('alertThresholdInput', '420000');
|
||||
await testSubjects.setValue('alertThresholdInput0', '420000');
|
||||
await testSubjects.click('forLastExpression');
|
||||
await testSubjects.setValue('timeWindowSizeNumber', '24');
|
||||
await testSubjects.setValue('timeWindowUnitSelect', 'hours');
|
||||
|
|
|
@ -195,7 +195,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
return ruleName === alertName;
|
||||
});
|
||||
await testSubjects.click('thresholdPopover');
|
||||
await testSubjects.setValue('alertThresholdInput', '1');
|
||||
await testSubjects.setValue('alertThresholdInput0', '1');
|
||||
|
||||
await testSubjects.click('forLastExpression');
|
||||
await testSubjects.setValue('timeWindowSizeNumber', '30');
|
||||
|
@ -499,7 +499,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await filterBar.addFilter({ field: 'message.keyword', operation: 'is', value: 'msg-1' });
|
||||
|
||||
await testSubjects.click('thresholdPopover');
|
||||
await testSubjects.setValue('alertThresholdInput', '1');
|
||||
await testSubjects.setValue('alertThresholdInput0', '1');
|
||||
await testSubjects.click('saveEditedRuleButton');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue