Skip to content

Commit

Permalink
[8.9] [Security Solution] Tests: Filter by rule execution status (#16…
Browse files Browse the repository at this point in the history
…0502) (#161618)

# Backport

This will backport the following commits from `main` to `8.9`:
- [[Security Solution] Tests: Filter by rule execution status
(#160502)](#160502)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Nikita
Indik","email":"[email protected]"},"sourceCommit":{"committedDate":"2023-07-11T08:12:37Z","message":"[Security
Solution] Tests: Filter by rule execution status
(#160502)\n\n**Resolves:
https://github.com/elastic/kibana/issues/138903**\r\n\r\n##
Summary\r\n\r\nAdds an E2E Cypress test to check filtering by execution
status in the\r\nrules table.\r\n<img width=\"953\" alt=\"Screenshot
2023-06-26 at 14 10
10\"\r\nsrc=\"https://github.com/elastic/kibana/assets/15949146/e1eb67ed-779c-42ad-8194-04a26598cfbc\">","sha":"c30a7d47eb4a467734b08bfea1d8d3c3c301b5cb","branchLabelMapping":{"^v8.10.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["test","test_ui_functional","release_note:skip","Team:Detections
and Resp","Team: SecuritySolution","Feature:Rule
Management","Team:Detection Rule
Management","v8.9.0","v8.10.0"],"number":160502,"url":"https://github.com/elastic/kibana/pull/160502","mergeCommit":{"message":"[Security
Solution] Tests: Filter by rule execution status
(#160502)\n\n**Resolves:
https://github.com/elastic/kibana/issues/138903**\r\n\r\n##
Summary\r\n\r\nAdds an E2E Cypress test to check filtering by execution
status in the\r\nrules table.\r\n<img width=\"953\" alt=\"Screenshot
2023-06-26 at 14 10
10\"\r\nsrc=\"https://github.com/elastic/kibana/assets/15949146/e1eb67ed-779c-42ad-8194-04a26598cfbc\">","sha":"c30a7d47eb4a467734b08bfea1d8d3c3c301b5cb"}},"sourceBranch":"main","suggestedTargetBranches":["8.9"],"targetPullRequestStates":[{"branch":"8.9","label":"v8.9.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.10.0","labelRegex":"^v8.10.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/160502","number":160502,"mergeCommit":{"message":"[Security
Solution] Tests: Filter by rule execution status
(#160502)\n\n**Resolves:
https://github.com/elastic/kibana/issues/138903**\r\n\r\n##
Summary\r\n\r\nAdds an E2E Cypress test to check filtering by execution
status in the\r\nrules table.\r\n<img width=\"953\" alt=\"Screenshot
2023-06-26 at 14 10
10\"\r\nsrc=\"https://github.com/elastic/kibana/assets/15949146/e1eb67ed-779c-42ad-8194-04a26598cfbc\">","sha":"c30a7d47eb4a467734b08bfea1d8d3c3c301b5cb"}}]}]
BACKPORT-->

Co-authored-by: Nikita Indik <[email protected]>
  • Loading branch information
kibanamachine and nikitaindik authored Jul 11, 2023
1 parent 4115904 commit d844b83
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* 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 { cleanKibana, resetRulesTableState, deleteAlertsAndRules } from '../../tasks/common';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { esArchiverResetKibana } from '../../tasks/es_archiver';
import {
expectRulesWithExecutionStatus,
filterByExecutionStatus,
expectNumberOfRulesShownOnPage,
} from '../../tasks/rule_filters';

import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';

import { waitForRulesTableToBeLoaded } from '../../tasks/alerts_detection_rules';

import { createRule, waitForRulesToFinishExecution } from '../../tasks/api_calls/rules';
import { deleteIndex, createIndex, createDocument } from '../../tasks/api_calls/elasticsearch';

import { getNewRule } from '../../objects/rule';

describe('Rule management filters', () => {
before(() => {
cleanKibana();
});

beforeEach(() => {
login();
// Make sure persisted rules table state is cleared
resetRulesTableState();
deleteAlertsAndRules();
esArchiverResetKibana();
});

describe('Last response filter', () => {
it('Filters rules by last response', function () {
deleteIndex('test_index');

createIndex('test_index', {
'@timestamp': {
type: 'date',
},
});

createDocument('test_index', {});

createRule(
getNewRule({
name: 'Successful rule',
rule_id: 'successful_rule',
index: ['test_index'],
})
);

createRule(
getNewRule({
name: 'Warning rule',
rule_id: 'warning_rule',
index: ['non_existent_index'],
})
);

createRule(
getNewRule({
name: 'Failed rule',
rule_id: 'failed_rule',
index: ['test_index'],
// Setting a crazy large "Additional look-back time" to force a failure
from: 'now-9007199254746990s',
})
);

waitForRulesToFinishExecution(['successful_rule', 'warning_rule', 'failed_rule'], new Date());

visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);

waitForRulesTableToBeLoaded();

// Initial table state - before filtering by status
expectNumberOfRulesShownOnPage(3);
expectRulesWithExecutionStatus(1, 'Succeeded');
expectRulesWithExecutionStatus(1, 'Warning');
expectRulesWithExecutionStatus(1, 'Failed');

// Table state after filtering by Succeeded status
filterByExecutionStatus('Succeeded');
expectNumberOfRulesShownOnPage(1);
expectRulesWithExecutionStatus(1, 'Succeeded');

// Table state after filtering by Warning status
filterByExecutionStatus('Warning');
expectNumberOfRulesShownOnPage(1);
expectRulesWithExecutionStatus(1, 'Warning');

// Table state after filtering by Failed status
filterByExecutionStatus('Failed');
expectNumberOfRulesShownOnPage(1);
expectRulesWithExecutionStatus(1, 'Failed');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,9 @@ export const REFRESH_SETTINGS_SWITCH = '[data-test-subj="refreshSettingsSwitch"]
export const REFRESH_SETTINGS_SELECTION_NOTE = '[data-test-subj="refreshSettingsSelectionNote"]';

export const REFRESH_RULES_STATUS = '[data-test-subj="refreshRulesStatus"]';

export const RULE_EXECUTION_STATUS_BADGE = '[data-test-subj="ruleExecutionStatus"]';

export const EXECUTION_STATUS_FILTER_BUTTON = '[data-test-subj="executionStatusFilterButton"]';

export const EXECUTION_STATUS_FILTER_OPTION = '[data-test-subj="executionStatusFilterOption"]';
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { rootRequest } from '../common';

export const deleteIndex = (index: string) => {
Expand All @@ -16,6 +15,24 @@ export const deleteIndex = (index: string) => {
});
};

export const createIndex = (indexName: string, properties: Record<string, unknown>) =>
rootRequest({
method: 'PUT',
url: `${Cypress.env('ELASTICSEARCH_URL')}/${indexName}`,
body: {
mappings: {
properties,
},
},
});

export const createDocument = (indexName: string, document: Record<string, unknown>) =>
rootRequest({
method: 'POST',
url: `${Cypress.env('ELASTICSEARCH_URL')}/${indexName}/_doc`,
body: document,
});

export const waitForNewDocumentToBeIndexed = (index: string, initialNumberOfDocuments: number) => {
cy.waitUntil(
() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@

import moment from 'moment';
import { rootRequest } from '../common';
import { DETECTION_ENGINE_RULES_URL } from '../../../common/constants';
import {
DETECTION_ENGINE_RULES_URL,
DETECTION_ENGINE_RULES_URL_FIND,
} from '../../../common/constants';
import type { RuleCreateProps, RuleResponse } from '../../../common/detection_engine/rule_schema';
import { internalAlertingSnoozeRule } from '../../urls/routes';
import type { FetchRulesResponse } from '../../../public/detection_engine/rule_management/logic/types';

export const createRule = (
rule: RuleCreateProps
Expand Down Expand Up @@ -72,3 +76,28 @@ export const importRule = (ndjsonPath: string) => {
.should('be.equal', 200);
});
};

export const waitForRulesToFinishExecution = (ruleIds: string[], afterDate?: Date) =>
cy.waitUntil(
() =>
rootRequest<FetchRulesResponse>({
method: 'GET',
url: DETECTION_ENGINE_RULES_URL_FIND,
}).then((response) => {
const areAllRulesFinished = ruleIds.every((ruleId) =>
response.body.data.some((rule) => {
const ruleExecutionDate = rule.execution_summary?.last_execution?.date;

const isDateOk = afterDate
? !!(ruleExecutionDate && new Date(ruleExecutionDate) > afterDate)
: true;

return (
rule.rule_id === ruleId && typeof rule.execution_summary !== 'undefined' && isDateOk
);
})
);
return areAllRulesFinished;
}),
{ interval: 500, timeout: 12000 }
);
27 changes: 27 additions & 0 deletions x-pack/plugins/security_solution/cypress/tasks/rule_filters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* 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 {
RULE_EXECUTION_STATUS_BADGE,
EXECUTION_STATUS_FILTER_BUTTON,
EXECUTION_STATUS_FILTER_OPTION,
} from '../screens/alerts_detection_rules';

export const expectRulesWithExecutionStatus = (expectedCount: number, status: string) => {
cy.get(`${RULE_EXECUTION_STATUS_BADGE}:contains("${status}")`).should(
'have.length',
expectedCount
);
};

export const expectNumberOfRulesShownOnPage = (expectedCount: number) =>
cy.get(RULE_EXECUTION_STATUS_BADGE).should('have.length', expectedCount);

export const filterByExecutionStatus = (status: string) => {
cy.get(EXECUTION_STATUS_FILTER_BUTTON).click();
cy.get(`${EXECUTION_STATUS_FILTER_OPTION}:contains("${status}")`).click();
};
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const RuleExecutionStatusSelectorComponent = ({
isSelected={isExecutionStatusPopoverOpen}
hasActiveFilters={selectedStatus !== undefined}
numActiveFilters={selectedStatus !== undefined ? 1 : 0}
data-test-subj="executionStatusFilterButton"
>
{i18n.COLUMN_LAST_RESPONSE}
</EuiFilterButton>
Expand Down Expand Up @@ -108,11 +109,13 @@ const RuleExecutionStatusSelectorComponent = ({
css={`
margin-top: 4px; // aligns the badge within the option
`}
data-test-subj="executionStatusFilterOption"
>
<RuleStatusBadge status={status} showTooltip={false} />
</div>
);
}}
data-test-subj="executionStatusFilterSelectableList"
>
{(list) => (
<div
Expand Down

0 comments on commit d844b83

Please sign in to comment.