mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[RAM] Create serverless functional tests for rule details (#168101)
Serverless functional tests for rule details on Search. I did not copy all rule details tests to serverless. Some of them will be copied after soon rules changes: https://github.com/elastic/kibana/issues/168965 --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
1659434b94
commit
c2e4d40a23
4 changed files with 795 additions and 1 deletions
|
@ -17,6 +17,7 @@ import { SvlObltOverviewPageProvider } from './svl_oblt_overview_page';
|
|||
import { SvlSearchLandingPageProvider } from './svl_search_landing_page';
|
||||
import { SvlSecLandingPageProvider } from './svl_sec_landing_page';
|
||||
import { SvlTriggersActionsPageProvider } from './svl_triggers_actions_ui_page';
|
||||
import { SvlRuleDetailsPageProvider } from './svl_rule_details_ui_page';
|
||||
|
||||
export const pageObjects = {
|
||||
...xpackFunctionalPageObjects,
|
||||
|
@ -30,4 +31,5 @@ export const pageObjects = {
|
|||
svlSearchLandingPage: SvlSearchLandingPageProvider,
|
||||
svlSecLandingPage: SvlSecLandingPageProvider,
|
||||
svlTriggersActionsUI: SvlTriggersActionsPageProvider,
|
||||
svlRuleDetailsUI: SvlRuleDetailsPageProvider,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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 function SvlRuleDetailsPageProvider({ getService }: FtrProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const find = getService('find');
|
||||
const log = getService('log');
|
||||
const retry = getService('retry');
|
||||
|
||||
return {
|
||||
async getHeadingText() {
|
||||
return await testSubjects.getVisibleText('ruleDetailsTitle');
|
||||
},
|
||||
async getRuleType() {
|
||||
return await testSubjects.getVisibleText('ruleTypeLabel');
|
||||
},
|
||||
async getAPIKeyOwner() {
|
||||
return await testSubjects.getVisibleText('apiKeyOwnerLabel');
|
||||
},
|
||||
async getAlertsList() {
|
||||
const table = await find.byCssSelector(
|
||||
'.euiBasicTable[data-test-subj="alertsList"]:not(.euiBasicTable-loading)'
|
||||
);
|
||||
const $ = await table.parseDomContent();
|
||||
return $.findTestSubjects('alert-row')
|
||||
.toArray()
|
||||
.map((row) => {
|
||||
return {
|
||||
alert: $(row)
|
||||
.findTestSubject('alertsTableCell-alert')
|
||||
.find('.euiTableCellContent')
|
||||
.text(),
|
||||
status: $(row)
|
||||
.findTestSubject('alertsTableCell-status')
|
||||
.find('.euiTableCellContent')
|
||||
.text(),
|
||||
start: $(row)
|
||||
.findTestSubject('alertsTableCell-start')
|
||||
.find('.euiTableCellContent')
|
||||
.text(),
|
||||
duration: $(row)
|
||||
.findTestSubject('alertsTableCell-duration')
|
||||
.find('.euiTableCellContent')
|
||||
.text(),
|
||||
};
|
||||
});
|
||||
},
|
||||
async getAlertDurationEpoch(): Promise<number> {
|
||||
const alertDurationEpoch = await find.byCssSelector(
|
||||
'input[data-test-subj="alertsDurationEpoch"]'
|
||||
);
|
||||
return parseInt(await alertDurationEpoch.getAttribute('value'), 10);
|
||||
},
|
||||
async clickAlertMuteButton(alert: string) {
|
||||
const muteAlertButton = await testSubjects.find(`muteAlertButton_${alert}`);
|
||||
await muteAlertButton.click();
|
||||
},
|
||||
async ensureAlertMuteState(alert: string, isMuted: boolean) {
|
||||
await retry.try(async () => {
|
||||
const muteAlertButton = await testSubjects.find(`muteAlertButton_${alert}`);
|
||||
log.debug(`checked:${await muteAlertButton.getAttribute('aria-checked')}`);
|
||||
expect(await muteAlertButton.getAttribute('aria-checked')).to.eql(
|
||||
isMuted ? 'true' : 'false'
|
||||
);
|
||||
});
|
||||
},
|
||||
async ensureAlertExistence(alert: string, shouldExist: boolean) {
|
||||
await retry.try(async () => {
|
||||
const table = await find.byCssSelector(
|
||||
'.euiBasicTable[data-test-subj="alertsList"]:not(.euiBasicTable-loading)'
|
||||
);
|
||||
const $ = await table.parseDomContent();
|
||||
expect(
|
||||
$.findTestSubjects('alert-row')
|
||||
.toArray()
|
||||
.filter(
|
||||
(row) =>
|
||||
$(row)
|
||||
.findTestSubject('alertsTableCell-alert')
|
||||
.find('.euiTableCellContent')
|
||||
.text() === alert
|
||||
)
|
||||
).to.eql(shouldExist ? 1 : 0);
|
||||
});
|
||||
},
|
||||
async clickPaginationNextPage() {
|
||||
const nextButton = await testSubjects.find(`pagination-button-next`);
|
||||
nextButton.click();
|
||||
},
|
||||
async isViewInAppDisabled() {
|
||||
await retry.try(async () => {
|
||||
const viewInAppButton = await testSubjects.find(`ruleDetails-viewInApp`);
|
||||
expect(await viewInAppButton.getAttribute('disabled')).to.eql('true');
|
||||
});
|
||||
return true;
|
||||
},
|
||||
async isViewInAppEnabled() {
|
||||
await retry.try(async () => {
|
||||
const viewInAppButton = await testSubjects.find(`ruleDetails-viewInApp`);
|
||||
await new Promise((resolve) => {});
|
||||
expect(await viewInAppButton.getAttribute('disabled')).to.not.eql('true');
|
||||
});
|
||||
return true;
|
||||
},
|
||||
async clickViewInApp() {
|
||||
return await testSubjects.click('ruleDetails-viewInApp');
|
||||
},
|
||||
async getNoOpAppTitle() {
|
||||
await retry.try(async () => {
|
||||
const title = await testSubjects.find('noop-title');
|
||||
expect(title.isDisplayed()).to.eql(true);
|
||||
});
|
||||
return await testSubjects.getVisibleText('noop-title');
|
||||
},
|
||||
};
|
||||
}
|
|
@ -13,10 +13,10 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
|||
loadTestFile(require.resolve('./empty_page'));
|
||||
loadTestFile(require.resolve('./navigation'));
|
||||
loadTestFile(require.resolve('./cases/attachment_framework'));
|
||||
|
||||
loadTestFile(require.resolve('./dashboards/build_dashboard'));
|
||||
loadTestFile(require.resolve('./dashboards/import_dashboard'));
|
||||
loadTestFile(require.resolve('./advanced_settings'));
|
||||
loadTestFile(require.resolve('./rules/rule_details'));
|
||||
|
||||
loadTestFile(require.resolve('./ml'));
|
||||
});
|
||||
|
|
|
@ -0,0 +1,669 @@
|
|||
/*
|
||||
* 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 'expect';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import {
|
||||
createEsQueryRule as createRule,
|
||||
createSlackConnector,
|
||||
createIndexConnector,
|
||||
} from '../../../../api_integration/test_suites/common/alerting/helpers/alerting_api_helper';
|
||||
|
||||
export enum RuleNotifyWhen {
|
||||
CHANGE = 'onActionGroupChange',
|
||||
ACTIVE = 'onActiveAlert',
|
||||
THROTTLE = 'onThrottleInterval',
|
||||
}
|
||||
|
||||
export default ({ getPageObject, getService }: FtrProviderContext) => {
|
||||
const svlCommonPage = getPageObject('svlCommonPage');
|
||||
const svlCommonNavigation = getPageObject('svlCommonNavigation');
|
||||
const svlTriggersActionsUI = getPageObject('svlTriggersActionsUI');
|
||||
const svlRuleDetailsUI = getPageObject('svlRuleDetailsUI');
|
||||
const svlSearchNavigation = getService('svlSearchNavigation');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const supertest = getService('supertest');
|
||||
const find = getService('find');
|
||||
const retry = getService('retry');
|
||||
const toasts = getService('toasts');
|
||||
const comboBox = getService('comboBox');
|
||||
|
||||
const openFirstRule = async (ruleName: string) => {
|
||||
await svlTriggersActionsUI.searchRules(ruleName);
|
||||
await find.clickDisplayedByCssSelector(`[data-test-subj="rulesList"] [title="${ruleName}"]`);
|
||||
};
|
||||
|
||||
const openRulesSection = async () => {
|
||||
await svlSearchNavigation.navigateToLandingPage();
|
||||
await svlCommonNavigation.sidenav.clickLink({ text: 'Alerts' });
|
||||
};
|
||||
|
||||
const navigateToConnectors = async () => {
|
||||
await svlSearchNavigation.navigateToLandingPage();
|
||||
await svlCommonNavigation.sidenav.openSection('project_settings_project_nav');
|
||||
await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management' });
|
||||
await testSubjects.click('app-card-triggersActionsConnectors');
|
||||
};
|
||||
|
||||
const deleteConnector = async (connectorName: string) => {
|
||||
await svlTriggersActionsUI.searchConnectors(connectorName);
|
||||
await testSubjects.click('deleteConnector');
|
||||
await testSubjects.existOrFail('deleteIdsConfirmation');
|
||||
await testSubjects.click('deleteIdsConfirmation > confirmModalConfirmButton');
|
||||
await testSubjects.missingOrFail('deleteIdsConfirmation');
|
||||
};
|
||||
|
||||
describe('Rule details', () => {
|
||||
let ruleIdList: string[];
|
||||
let connectorIdList: string[];
|
||||
|
||||
before(async () => {
|
||||
await svlCommonPage.login();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await svlCommonPage.forceLogout();
|
||||
});
|
||||
|
||||
describe('Header', () => {
|
||||
const testRunUuid = uuidv4();
|
||||
const ruleName = `test-rule-${testRunUuid}`;
|
||||
const RULE_TYPE_ID = '.es-query';
|
||||
|
||||
before(async () => {
|
||||
const rule = await createRule({
|
||||
supertest,
|
||||
consumer: 'alerts',
|
||||
name: ruleName,
|
||||
ruleTypeId: RULE_TYPE_ID,
|
||||
params: {
|
||||
size: 100,
|
||||
thresholdComparator: '>',
|
||||
threshold: [-1],
|
||||
index: ['alert-test-data'],
|
||||
timeField: 'date',
|
||||
esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`,
|
||||
timeWindowSize: 20,
|
||||
timeWindowUnit: 's',
|
||||
},
|
||||
actions: [],
|
||||
});
|
||||
|
||||
ruleIdList = [rule.id];
|
||||
|
||||
await openRulesSection();
|
||||
await testSubjects.existOrFail('rulesList');
|
||||
await openFirstRule(rule.name);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await Promise.all(
|
||||
ruleIdList.map(async (ruleId) => {
|
||||
await supertest
|
||||
.delete(`/api/alerting/rule/${ruleId}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.set('x-elastic-internal-origin', 'foo');
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('renders the rule details', async () => {
|
||||
const headingText = await testSubjects.getVisibleText('ruleDetailsTitle');
|
||||
expect(headingText.includes(`test-rule-${testRunUuid}`)).toBe(true);
|
||||
const ruleType = await testSubjects.getVisibleText('ruleTypeLabel');
|
||||
expect(ruleType).toEqual('Elasticsearch query');
|
||||
const owner = await testSubjects.getVisibleText('apiKeyOwnerLabel');
|
||||
expect(owner).toEqual('elastic_serverless');
|
||||
});
|
||||
|
||||
it('should disable the rule', async () => {
|
||||
const actionsDropdown = await testSubjects.find('statusDropdown');
|
||||
|
||||
expect(await actionsDropdown.getVisibleText()).toEqual('Enabled');
|
||||
|
||||
await actionsDropdown.click();
|
||||
const actionsMenuElem = await testSubjects.find('ruleStatusMenu');
|
||||
const actionsMenuItemElem = await actionsMenuElem.findAllByClassName('euiContextMenuItem');
|
||||
|
||||
await actionsMenuItemElem.at(1)?.click();
|
||||
|
||||
await retry.try(async () => {
|
||||
expect(await actionsDropdown.getVisibleText()).toEqual('Disabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow you to snooze a disabled rule', async () => {
|
||||
const actionsDropdown = await testSubjects.find('statusDropdown');
|
||||
|
||||
expect(await actionsDropdown.getVisibleText()).toEqual('Disabled');
|
||||
|
||||
let snoozeBadge = await testSubjects.find('rulesListNotifyBadge-unsnoozed');
|
||||
await snoozeBadge.click();
|
||||
|
||||
const snoozeIndefinite = await testSubjects.find('ruleSnoozeIndefiniteApply');
|
||||
await snoozeIndefinite.click();
|
||||
|
||||
await retry.try(async () => {
|
||||
await testSubjects.existOrFail('rulesListNotifyBadge-snoozedIndefinitely');
|
||||
});
|
||||
|
||||
// Unsnooze the rule for the next test
|
||||
snoozeBadge = await testSubjects.find('rulesListNotifyBadge-snoozedIndefinitely');
|
||||
await snoozeBadge.click();
|
||||
|
||||
const snoozeCancel = await testSubjects.find('ruleSnoozeCancel');
|
||||
await snoozeCancel.click();
|
||||
});
|
||||
|
||||
it('should reenable a disabled the rule', async () => {
|
||||
const actionsDropdown = await testSubjects.find('statusDropdown');
|
||||
|
||||
expect(await actionsDropdown.getVisibleText()).toEqual('Disabled');
|
||||
|
||||
await actionsDropdown.click();
|
||||
const actionsMenuElem = await testSubjects.find('ruleStatusMenu');
|
||||
const actionsMenuItemElem = await actionsMenuElem.findAllByClassName('euiContextMenuItem');
|
||||
|
||||
await actionsMenuItemElem.at(0)?.click();
|
||||
|
||||
await retry.try(async () => {
|
||||
expect(await actionsDropdown.getVisibleText()).toEqual('Enabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('should snooze the rule', async () => {
|
||||
let snoozeBadge = await testSubjects.find('rulesListNotifyBadge-unsnoozed');
|
||||
await snoozeBadge.click();
|
||||
|
||||
const snoozeIndefinite = await testSubjects.find('ruleSnoozeIndefiniteApply');
|
||||
await snoozeIndefinite.click();
|
||||
|
||||
await retry.try(async () => {
|
||||
await testSubjects.existOrFail('rulesListNotifyBadge-snoozedIndefinitely');
|
||||
});
|
||||
|
||||
// Unsnooze the rule for the next test
|
||||
snoozeBadge = await testSubjects.find('rulesListNotifyBadge-snoozedIndefinitely');
|
||||
await snoozeBadge.click();
|
||||
|
||||
const snoozeCancel = await testSubjects.find('ruleSnoozeCancel');
|
||||
await snoozeCancel.click();
|
||||
});
|
||||
|
||||
it('should snooze the rule for a set duration', async () => {
|
||||
let snoozeBadge = await testSubjects.find('rulesListNotifyBadge-unsnoozed');
|
||||
await snoozeBadge.click();
|
||||
|
||||
const snooze8h = await testSubjects.find('linkSnooze8h');
|
||||
await snooze8h.click();
|
||||
|
||||
await retry.try(async () => {
|
||||
await testSubjects.existOrFail('rulesListNotifyBadge-snoozed');
|
||||
});
|
||||
|
||||
// Unsnooze the rule for the next test
|
||||
snoozeBadge = await testSubjects.find('rulesListNotifyBadge-snoozed');
|
||||
await snoozeBadge.click();
|
||||
|
||||
const snoozeCancel = await testSubjects.find('ruleSnoozeCancel');
|
||||
await snoozeCancel.click();
|
||||
});
|
||||
|
||||
it('should add snooze schedule', async () => {
|
||||
let snoozeBadge = await testSubjects.find('rulesListNotifyBadge-unsnoozed');
|
||||
await snoozeBadge.click();
|
||||
|
||||
const addScheduleButton = await testSubjects.find('ruleAddSchedule');
|
||||
await addScheduleButton.click();
|
||||
|
||||
const saveScheduleButton = await testSubjects.find('scheduler-saveSchedule');
|
||||
await saveScheduleButton.click();
|
||||
|
||||
await retry.try(async () => {
|
||||
await testSubjects.existOrFail('rulesListNotifyBadge-scheduled');
|
||||
});
|
||||
|
||||
// Unsnooze the rule for the next test
|
||||
snoozeBadge = await testSubjects.find('rulesListNotifyBadge-scheduled');
|
||||
await snoozeBadge.click();
|
||||
|
||||
const snoozeCancel = await testSubjects.find('ruleRemoveAllSchedules');
|
||||
await snoozeCancel.click();
|
||||
|
||||
const confirmButton = await testSubjects.find('confirmModalConfirmButton');
|
||||
await confirmButton.click();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edit rule button', () => {
|
||||
const testRunUuid = uuidv4();
|
||||
const ruleName = `${testRunUuid}`;
|
||||
const updatedRuleName = `Changed Rule Name ${ruleName}`;
|
||||
const RULE_TYPE_ID = '.es-query';
|
||||
|
||||
before(async () => {
|
||||
const rule = await createRule({
|
||||
supertest,
|
||||
consumer: 'alerts',
|
||||
name: ruleName,
|
||||
ruleTypeId: RULE_TYPE_ID,
|
||||
params: {
|
||||
size: 100,
|
||||
thresholdComparator: '>',
|
||||
threshold: [-1],
|
||||
index: ['alert-test-data'],
|
||||
timeField: 'date',
|
||||
esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`,
|
||||
timeWindowSize: 20,
|
||||
timeWindowUnit: 's',
|
||||
},
|
||||
actions: [],
|
||||
});
|
||||
|
||||
ruleIdList = [rule.id];
|
||||
|
||||
await openRulesSection();
|
||||
await testSubjects.existOrFail('rulesList');
|
||||
await openFirstRule(rule.name);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await Promise.all(
|
||||
ruleIdList.map(async (ruleId) => {
|
||||
await supertest
|
||||
.delete(`/api/alerting/rule/${ruleId}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.set('x-elastic-internal-origin', 'foo');
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should open edit rule flyout', async () => {
|
||||
const editButton = await testSubjects.find('openEditRuleFlyoutButton');
|
||||
await editButton.click();
|
||||
expect(await testSubjects.exists('hasActionsDisabled')).toBe(false);
|
||||
|
||||
await testSubjects.setValue('ruleNameInput', updatedRuleName, {
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
|
||||
await find.clickByCssSelector('[data-test-subj="saveEditedRuleButton"]:not(disabled)');
|
||||
|
||||
await retry.try(async () => {
|
||||
const resultToast = await toasts.getToastElement(1);
|
||||
const toastText = await resultToast.getVisibleText();
|
||||
expect(toastText).toEqual(`Updated '${updatedRuleName}'`);
|
||||
});
|
||||
|
||||
await retry.tryForTime(30 * 1000, async () => {
|
||||
const headingText = await testSubjects.getVisibleText('ruleDetailsTitle');
|
||||
expect(headingText.includes(updatedRuleName)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should reset rule when canceling an edit', async () => {
|
||||
const editButton = await testSubjects.find('openEditRuleFlyoutButton');
|
||||
await editButton.click();
|
||||
|
||||
await testSubjects.setValue('ruleNameInput', uuidv4(), {
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
|
||||
await testSubjects.click('cancelSaveEditedRuleButton');
|
||||
await testSubjects.existOrFail('confirmRuleCloseModal');
|
||||
await testSubjects.click('confirmRuleCloseModal > confirmModalConfirmButton');
|
||||
await find.waitForDeletedByCssSelector('[data-test-subj="cancelSaveEditedRuleButton"]');
|
||||
|
||||
await editButton.click();
|
||||
|
||||
const nameInputAfterCancel = await testSubjects.find('ruleNameInput');
|
||||
const textAfterCancel = await nameInputAfterCancel.getAttribute('value');
|
||||
expect(textAfterCancel).toEqual(updatedRuleName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edit rule with deleted connector', () => {
|
||||
const ALERT_ACTION_INDEX = 'alert-action-es-query';
|
||||
const RULE_TYPE_ID = '.es-query';
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
ruleIdList.map(async (ruleId) => {
|
||||
await supertest
|
||||
.delete(`/api/alerting/rule/${ruleId}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.set('x-elastic-internal-origin', 'foo');
|
||||
})
|
||||
);
|
||||
await Promise.all(
|
||||
connectorIdList.map(async (connectorId) => {
|
||||
await supertest
|
||||
.delete(`/api/actions/connector/${connectorId}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.set('x-elastic-internal-origin', 'foo');
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should show and update deleted connectors when there are existing connectors of the same type', async () => {
|
||||
const testRunUuid = uuidv4();
|
||||
|
||||
const connector1 = await createSlackConnector({
|
||||
supertest,
|
||||
name: `slack-${testRunUuid}-${0}`,
|
||||
});
|
||||
|
||||
const connector2 = await createSlackConnector({
|
||||
supertest,
|
||||
name: `slack-${testRunUuid}-${1}`,
|
||||
});
|
||||
|
||||
connectorIdList = [connector2.id];
|
||||
|
||||
const rule = await createRule({
|
||||
supertest,
|
||||
consumer: 'alerts',
|
||||
name: testRunUuid,
|
||||
ruleTypeId: RULE_TYPE_ID,
|
||||
schedule: { interval: '1m' },
|
||||
params: {
|
||||
size: 100,
|
||||
thresholdComparator: '>',
|
||||
threshold: [-1],
|
||||
index: ['alert-test-data'],
|
||||
timeField: 'date',
|
||||
esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`,
|
||||
timeWindowSize: 20,
|
||||
timeWindowUnit: 's',
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
group: 'query matched',
|
||||
id: connector1.id,
|
||||
params: { level: 'info', message: ' {{context.message}}' },
|
||||
frequency: {
|
||||
summary: false,
|
||||
notify_when: RuleNotifyWhen.THROTTLE,
|
||||
throttle: '1m',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
ruleIdList = [rule.id];
|
||||
|
||||
await openRulesSection();
|
||||
await testSubjects.existOrFail('rulesList');
|
||||
await navigateToConnectors();
|
||||
|
||||
await deleteConnector(connector1.name);
|
||||
|
||||
await retry.try(async () => {
|
||||
const resultToast = await toasts.getToastElement(1);
|
||||
const toastText = await resultToast.getVisibleText();
|
||||
expect(toastText).toEqual('Deleted 1 connector');
|
||||
});
|
||||
|
||||
await openRulesSection();
|
||||
await openFirstRule(rule.name);
|
||||
|
||||
const editButton = await testSubjects.find('openEditRuleFlyoutButton');
|
||||
await editButton.click();
|
||||
expect(await testSubjects.exists('hasActionsDisabled')).toEqual(false);
|
||||
|
||||
expect(await testSubjects.exists('addNewActionConnectorActionGroup-0')).toEqual(false);
|
||||
expect(await testSubjects.exists('alertActionAccordion-0')).toEqual(true);
|
||||
|
||||
expect(await testSubjects.exists('selectActionConnector-.slack-0')).toEqual(true);
|
||||
// click the super selector the reveal the options
|
||||
await testSubjects.click('selectActionConnector-.slack-0');
|
||||
await testSubjects.click(`dropdown-connector-${connector2.id}`);
|
||||
expect(await testSubjects.exists('addNewActionConnectorActionGroup-0')).toEqual(true);
|
||||
});
|
||||
|
||||
it('should show and update deleted connectors when there are no existing connectors of the same type', async () => {
|
||||
const testRunUuid = uuidv4();
|
||||
const connector = await createIndexConnector({
|
||||
supertest,
|
||||
name: `index-${testRunUuid}-${2}`,
|
||||
indexName: ALERT_ACTION_INDEX,
|
||||
});
|
||||
|
||||
const rule = await createRule({
|
||||
supertest,
|
||||
consumer: 'alerts',
|
||||
name: testRunUuid,
|
||||
ruleTypeId: RULE_TYPE_ID,
|
||||
schedule: { interval: '1m' },
|
||||
params: {
|
||||
size: 100,
|
||||
thresholdComparator: '>',
|
||||
threshold: [-1],
|
||||
index: ['alert-test-data'],
|
||||
timeField: 'date',
|
||||
esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`,
|
||||
timeWindowSize: 20,
|
||||
timeWindowUnit: 's',
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
group: 'query matched',
|
||||
id: connector.id,
|
||||
params: { level: 'info', message: ' {{context.message}}' },
|
||||
frequency: {
|
||||
summary: false,
|
||||
notify_when: RuleNotifyWhen.THROTTLE,
|
||||
throttle: '1m',
|
||||
},
|
||||
},
|
||||
{
|
||||
group: 'recovered',
|
||||
id: connector.id,
|
||||
params: { level: 'info', message: ' {{context.message}}' },
|
||||
frequency: {
|
||||
summary: false,
|
||||
notify_when: RuleNotifyWhen.THROTTLE,
|
||||
throttle: '1m',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
ruleIdList = [rule.id];
|
||||
|
||||
await openRulesSection();
|
||||
await testSubjects.existOrFail('rulesList');
|
||||
await navigateToConnectors();
|
||||
await deleteConnector(connector.name);
|
||||
|
||||
await retry.try(async () => {
|
||||
const resultToast = await toasts.getToastElement(1);
|
||||
const toastText = await resultToast.getVisibleText();
|
||||
expect(toastText).toEqual('Deleted 1 connector');
|
||||
});
|
||||
|
||||
await openRulesSection();
|
||||
await openFirstRule(rule.name);
|
||||
|
||||
const editButton = await testSubjects.find('openEditRuleFlyoutButton');
|
||||
await editButton.click();
|
||||
expect(await testSubjects.exists('hasActionsDisabled')).toEqual(false);
|
||||
|
||||
expect(await testSubjects.exists('addNewActionConnectorActionGroup-0')).toEqual(false);
|
||||
expect(await testSubjects.exists('alertActionAccordion-0')).toEqual(true);
|
||||
expect(await testSubjects.exists('addNewActionConnectorActionGroup-1')).toEqual(false);
|
||||
expect(await testSubjects.exists('alertActionAccordion-1')).toEqual(true);
|
||||
|
||||
await testSubjects.click('createActionConnectorButton-0');
|
||||
|
||||
await testSubjects.existOrFail('connectorAddModal');
|
||||
await testSubjects.setValue('nameInput', 'new connector');
|
||||
await retry.try(async () => {
|
||||
// At times we find the driver controlling the ComboBox in tests
|
||||
// can select the wrong item, this ensures we always select the correct index
|
||||
await comboBox.set('connectorIndexesComboBox', 'test-index');
|
||||
expect(
|
||||
await comboBox.isOptionSelected(
|
||||
await testSubjects.find('connectorIndexesComboBox'),
|
||||
'test-index'
|
||||
)
|
||||
).toEqual(true);
|
||||
});
|
||||
await testSubjects.click('connectorAddModal > saveActionButtonModal');
|
||||
await testSubjects.missingOrFail('deleteIdsConfirmation');
|
||||
|
||||
expect(await testSubjects.exists('addNewActionConnectorActionGroup-0')).toEqual(true);
|
||||
expect(await testSubjects.exists('addNewActionConnectorActionGroup-1')).toEqual(true);
|
||||
|
||||
await openRulesSection();
|
||||
await testSubjects.existOrFail('rulesList');
|
||||
await navigateToConnectors();
|
||||
await deleteConnector('new connector');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edit rule with legacy rule-level notify values', () => {
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
ruleIdList.map(async (ruleId) => {
|
||||
await supertest
|
||||
.delete(`/api/alerting/rule/${ruleId}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.set('x-elastic-internal-origin', 'foo');
|
||||
})
|
||||
);
|
||||
await Promise.all(
|
||||
connectorIdList.map(async (connectorId) => {
|
||||
await supertest
|
||||
.delete(`/api/actions/connector/${connectorId}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.set('x-elastic-internal-origin', 'foo');
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should convert rule-level params to action-level params and save the alert successfully', async () => {
|
||||
const testRunUuid = uuidv4();
|
||||
const RULE_TYPE_ID = '.es-query';
|
||||
|
||||
const connector1 = await createSlackConnector({
|
||||
supertest,
|
||||
name: `slack-${testRunUuid}-${0}`,
|
||||
});
|
||||
|
||||
const connector2 = await createSlackConnector({
|
||||
supertest,
|
||||
name: `slack-${testRunUuid}-${1}`,
|
||||
});
|
||||
|
||||
connectorIdList = [connector1.id, connector2.id];
|
||||
|
||||
const rule = await createRule({
|
||||
supertest,
|
||||
consumer: 'alerts',
|
||||
name: `test-rule-${testRunUuid}`,
|
||||
ruleTypeId: RULE_TYPE_ID,
|
||||
schedule: { interval: '1m' },
|
||||
params: {
|
||||
size: 100,
|
||||
thresholdComparator: '>',
|
||||
threshold: [-1],
|
||||
index: ['alert-test-data'],
|
||||
timeField: 'date',
|
||||
esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`,
|
||||
timeWindowSize: 20,
|
||||
timeWindowUnit: 's',
|
||||
},
|
||||
actions: [connector1, connector2].map((connector) => ({
|
||||
id: connector.id,
|
||||
group: 'query matched',
|
||||
params: {
|
||||
message: 'from alert 1s',
|
||||
level: 'warn',
|
||||
},
|
||||
frequency: {
|
||||
summary: false,
|
||||
notify_when: RuleNotifyWhen.THROTTLE,
|
||||
throttle: '2d',
|
||||
},
|
||||
})),
|
||||
});
|
||||
ruleIdList = [rule.id];
|
||||
|
||||
const updatedRuleName = `Changed rule ${rule.name}`;
|
||||
|
||||
await openRulesSection();
|
||||
await testSubjects.existOrFail('rulesList');
|
||||
await openFirstRule(rule.name);
|
||||
|
||||
const editButton = await testSubjects.find('openEditRuleFlyoutButton');
|
||||
await editButton.click();
|
||||
const notifyWhenSelect = await testSubjects.find('notifyWhenSelect');
|
||||
expect(await notifyWhenSelect.getVisibleText()).toEqual('On custom action intervals');
|
||||
const throttleInput = await testSubjects.find('throttleInput');
|
||||
const throttleUnitInput = await testSubjects.find('throttleUnitInput');
|
||||
expect(await throttleInput.getAttribute('value')).toEqual('2');
|
||||
expect(await throttleUnitInput.getAttribute('value')).toEqual('d');
|
||||
await testSubjects.setValue('ruleNameInput', updatedRuleName, {
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
|
||||
await find.clickByCssSelector('[data-test-subj="saveEditedRuleButton"]:not(disabled)');
|
||||
|
||||
await retry.try(async () => {
|
||||
const resultToast = await toasts.getToastElement(1);
|
||||
const toastText = await resultToast.getVisibleText();
|
||||
expect(toastText).toEqual(`Updated '${updatedRuleName}'`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('View In App', () => {
|
||||
const ruleName = uuidv4();
|
||||
const RULE_TYPE_ID = '.es-query';
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
ruleIdList.map(async (ruleId) => {
|
||||
await supertest
|
||||
.delete(`/api/alerting/rule/${ruleId}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.set('x-elastic-internal-origin', 'foo');
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('renders a disabled rule details view in app button', async () => {
|
||||
const rule = await createRule({
|
||||
supertest,
|
||||
consumer: 'alerts',
|
||||
name: ruleName,
|
||||
ruleTypeId: RULE_TYPE_ID,
|
||||
params: {
|
||||
size: 100,
|
||||
thresholdComparator: '>',
|
||||
threshold: [-1],
|
||||
index: ['alert-test-data'],
|
||||
timeField: 'date',
|
||||
esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`,
|
||||
timeWindowSize: 20,
|
||||
timeWindowUnit: 's',
|
||||
},
|
||||
actions: [],
|
||||
});
|
||||
|
||||
ruleIdList = [rule.id];
|
||||
|
||||
await openRulesSection();
|
||||
await testSubjects.existOrFail('rulesList');
|
||||
await openFirstRule(rule.name);
|
||||
|
||||
expect(await svlRuleDetailsUI.isViewInAppDisabled()).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue