Skip to content

Commit

Permalink
[Observability] add custom threshold functional test (elastic#184602)
Browse files Browse the repository at this point in the history
Closes elastic#175301

## Summary

Resolves
https://github.com/orgs/elastic/projects/1375/views/1?pane=issue&itemId=50879015

To run
```
cd x-pack && node ../scripts/functional_tests_server --config=test/observability_functional/with_rac_write.config.ts

or

node scripts/functional_tests_server.js --config x-pack/test/observability_functional/with_rac_write.config.ts
```
In a different terminal
```
node ../scripts/functional_test_runner --config=test/observability_functional/with_rac_write.config.ts --grep "Custom threshold rule"

or

node scripts/functional_test_runner --config=x-pack/test/observability_functional/with_rac_write.config.ts  --grep "Custom threshold rule"
```

---------

Co-authored-by: Maryam Saeidi <[email protected]>
(cherry picked from commit 0241cf6)
  • Loading branch information
dominiqueclarke committed Sep 18, 2024
1 parent 137ed13 commit 22aa311
Show file tree
Hide file tree
Showing 12 changed files with 368 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -228,6 +228,7 @@ export function MetricRowWithAgg({
options={fieldOptions}
selectedOptions={field ? [{ label: field }] : []}
onChange={handleFieldChange}
data-test-subj="aggregationField"
/>
</EuiFormRow>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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', () => {
Expand All @@ -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]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,10 @@ export const ThresholdExpression = ({
repositionOnScroll
>
<div>
<ClosablePopoverTitle onClose={() => setAlertThresholdPopoverOpen(false)}>
<ClosablePopoverTitle
onClose={() => setAlertThresholdPopoverOpen(false)}
dataTestSubj="thresholdPopoverTitle"
>
<>{comparators[comparator].text}</>
</ClosablePopoverTitle>
<EuiFlexGroup>
Expand Down Expand Up @@ -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])}
Expand Down
67 changes: 67 additions & 0 deletions x-pack/test/functional/services/observability/alerts/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -357,5 +422,7 @@ export function ObservabilityAlertsCommonProvider({
navigateToRulesLogsPage,
navigateToRuleDetailsByRuleId,
navigateToAlertDetails,
createDataView,
deleteDataView,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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');
Expand All @@ -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();
Expand All @@ -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,
Expand All @@ -52,5 +67,7 @@ export function ObservabilityAlertsRulesProvider({ getService }: FtrProviderCont
clickOnRuleInEventLogs,
clickOnInfrastructureCategory,
clickOnMetricThresholdRule,
clickOnObservabilityCategory,
clickOnCustomThresholdRule,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
Expand Down
Loading

0 comments on commit 22aa311

Please sign in to comment.