Skip to content

Commit

Permalink
[Security Solution] Support rule id in wait for rule status helper (e…
Browse files Browse the repository at this point in the history
…lastic#153410)

**Relates to:** elastic#152900

## Summary

This PR adds an ability to wait for rule status by its rule id in functional tests. It is a result of splitting of elastic#150553 into isolated parts.

## Details

Based on what kind of id is used (SO id or rule id) it leads to different behaviour under the hood. SO id related functionality consumes ES Get API while rule id related functionality consumes ES Search API. This way it may require to add some delay to let ES to refresh the data if the testing logic consumes ES Search API while rule status was awaited via SO id so that handled by ES Get API. This PR removes such a delay at rule exporting functional tests.
  • Loading branch information
maximpn authored Mar 27, 2023
1 parent a73bf87 commit 519185f
Show file tree
Hide file tree
Showing 39 changed files with 571 additions and 596 deletions.
4 changes: 2 additions & 2 deletions x-pack/test/cases_api_integration/common/lib/alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { RiskEnrichmentFields } from '@kbn/security-solution-plugin/server/lib/d
import {
getRuleForSignalTesting,
createRule,
waitForRuleSuccessOrStatus,
waitForRuleSuccess,
waitForSignalsToBePresent,
getSignalsByIds,
getQuerySignalIds,
Expand All @@ -29,7 +29,7 @@ export const createSecuritySolutionAlerts = async (
): Promise<estypes.SearchResponse<DetectionAlert & RiskEnrichmentFields>> => {
const rule = getRuleForSignalTesting(['auditbeat-*']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signals = await getSignalsByIds(supertest, log, [id]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {
deleteSignalsIndex,
deleteAllRules,
getRuleForSignalTesting,
waitForRuleSuccessOrStatus,
waitForRuleSuccess,
waitForSignalsToBePresent,
getSignalsByIds,
createRule,
Expand Down Expand Up @@ -804,7 +804,7 @@ export default ({ getService }: FtrProviderContext): void => {
const postedCase = await createCase(supertest, postCaseReq);

const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signals = await getSignalsByIds(supertest, log, [id]);

Expand Down Expand Up @@ -864,7 +864,7 @@ export default ({ getService }: FtrProviderContext): void => {
});

const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signals = await getSignalsByIds(supertest, log, [id]);

Expand Down Expand Up @@ -917,7 +917,7 @@ export default ({ getService }: FtrProviderContext): void => {
});

const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signals = await getSignalsByIds(supertest, log, [id]);

Expand Down Expand Up @@ -986,7 +986,7 @@ export default ({ getService }: FtrProviderContext): void => {

const postedCase = await createCase(supertest, postCaseReq);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signals = await getSignalsByIds(supertest, log, [id]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
createRule,
waitForSignalsToBePresent,
getSignalsByIds,
waitForRuleSuccessOrStatus,
waitForRuleSuccess,
getRuleForSignalTesting,
} from '../../utils';

Expand Down Expand Up @@ -57,7 +57,7 @@ export default ({ getService }: FtrProviderContext) => {
it('should be able to execute and get 10 signals', async () => {
const rule = getRuleForSignalTesting(['auditbeat-*']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 10, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).equal(10);
Expand All @@ -66,7 +66,7 @@ export default ({ getService }: FtrProviderContext) => {
it('should be have set the signals in an open state initially', async () => {
const rule = getRuleForSignalTesting(['auditbeat-*']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 10, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
const everySignalOpen = signalsOpen.hits.hits.every(
Expand All @@ -78,7 +78,7 @@ export default ({ getService }: FtrProviderContext) => {
it('should be able to get a count of 10 closed signals when closing 10', async () => {
const rule = getRuleForSignalTesting(['auditbeat-*']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 10, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
const signalIds = signalsOpen.hits.hits.map((signal) => signal._id);
Expand All @@ -104,7 +104,7 @@ export default ({ getService }: FtrProviderContext) => {
it('should be able close 10 signals immediately and they all should be closed', async () => {
const rule = getRuleForSignalTesting(['auditbeat-*']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 10, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
const signalIds = signalsOpen.hits.hits.map((signal) => signal._id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
getWebHookAction,
getRuleWithWebHookAction,
getSimpleRuleOutputWithWebHookAction,
waitForRuleSuccessOrStatus,
waitForRuleSuccess,
createRule,
} from '../../utils';

Expand Down Expand Up @@ -77,7 +77,7 @@ export default ({ getService }: FtrProviderContext) => {
log,
getRuleWithWebHookAction(hookAction.id, true)
);
await waitForRuleSuccessOrStatus(supertest, log, rule.id);
await waitForRuleSuccess({ supertest, log, id: rule.id });
});

it('should be able to create a new webhook action and attach it to a rule with a meta field and run it correctly', async () => {
Expand All @@ -95,7 +95,7 @@ export default ({ getService }: FtrProviderContext) => {
};

const rule = await createRule(supertest, log, ruleWithAction);
await waitForRuleSuccessOrStatus(supertest, log, rule.id);
await waitForRuleSuccess({ supertest, log, id: rule.id });
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
deleteSignalsIndex,
getRuleForSignalTesting,
getSignalsById,
waitForRuleSuccessOrStatus,
waitForRuleSuccess,
waitForSignalsToBePresent,
} from '../../utils';

Expand Down Expand Up @@ -50,7 +50,7 @@ export default ({ getService }: FtrProviderContext) => {
it('should keep the original alias value such as "host_alias" from a source index when the value is indexed', async () => {
const rule = getRuleForSignalTesting(['host_alias']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 4, [id]);
const signalsOpen = await getSignalsById(supertest, log, id);
const hits = signalsOpen.hits.hits
Expand All @@ -62,7 +62,7 @@ export default ({ getService }: FtrProviderContext) => {
it('should copy alias data from a source index into the signals index in the same position when the target is ECS compatible', async () => {
const rule = getRuleForSignalTesting(['host_alias']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 4, [id]);
const signalsOpen = await getSignalsById(supertest, log, id);
const hits = signalsOpen.hits.hits
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
import expect from '@kbn/expect';
import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants';
import { ROLES } from '@kbn/security-solution-plugin/common/test';
import { RuleExecutionStatus } from '@kbn/security-solution-plugin/common/detection_engine/rule_monitoring';
import { ThresholdRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import {
createSignalsIndex,
deleteSignalsIndex,
deleteAllRules,
waitForRuleSuccessOrStatus,
waitForRulePartialFailure,
getRuleForSignalTesting,
createRuleWithAuth,
getThresholdRuleForSignalTesting,
Expand Down Expand Up @@ -65,12 +64,11 @@ export default ({ getService }: FtrProviderContext) => {
user: ROLES.detections_admin,
pass: 'changeme',
});
await waitForRuleSuccessOrStatus(
await waitForRulePartialFailure({
supertest,
log,
id,
RuleExecutionStatus['partial failure']
);
});
const { body } = await supertest
.get(DETECTION_ENGINE_RULES_URL)
.set('kbn-xsrf', 'true')
Expand Down Expand Up @@ -104,12 +102,11 @@ export default ({ getService }: FtrProviderContext) => {
user: ROLES.detections_admin,
pass: 'changeme',
});
await waitForRuleSuccessOrStatus(
await waitForRulePartialFailure({
supertest,
log,
id,
RuleExecutionStatus['partial failure']
);
});
const { body } = await supertest
.get(DETECTION_ENGINE_RULES_URL)
.set('kbn-xsrf', 'true')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import expect from '@kbn/expect';

import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants';
import { RuleExecutionStatus } from '@kbn/security-solution-plugin/common/detection_engine/rule_monitoring';
import { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema';
import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types';
import { ROLES } from '@kbn/security-solution-plugin/common/test';
Expand All @@ -26,12 +25,13 @@ import {
removeServerGeneratedPropertiesIncludingRuleId,
getSimpleMlRule,
getSimpleMlRuleOutput,
waitForRuleSuccessOrStatus,
waitForRuleSuccess,
getRuleForSignalTesting,
getRuleForSignalTestingWithTimestampOverride,
waitForAlertToComplete,
waitForSignalsToBePresent,
getThresholdRuleForSignalTesting,
waitForRulePartialFailure,
} from '../../utils';
import { createUserAndRole, deleteUserAndRole } from '../../../common/services/security_solution';

Expand Down Expand Up @@ -118,7 +118,7 @@ export default ({ getService }: FtrProviderContext) => {
.send(simpleRule)
.expect(200);

await waitForRuleSuccessOrStatus(supertest, log, body.id);
await waitForRuleSuccess({ supertest, log, id: body.id });
});

it('should create a single rule with a rule_id and an index pattern that does not match anything available and partial failure for the rule', async () => {
Expand All @@ -129,12 +129,11 @@ export default ({ getService }: FtrProviderContext) => {
.send(simpleRule)
.expect(200);

await waitForRuleSuccessOrStatus(
await waitForRulePartialFailure({
supertest,
log,
body.id,
RuleExecutionStatus['partial failure']
);
id: body.id,
});

const { body: rule } = await supertest
.get(DETECTION_ENGINE_RULES_URL)
Expand All @@ -157,7 +156,7 @@ export default ({ getService }: FtrProviderContext) => {
.send(simpleRule)
.expect(200);

await waitForRuleSuccessOrStatus(supertest, log, body.id, RuleExecutionStatus.succeeded);
await waitForRuleSuccess({ supertest, log, id: body.id });
});

it('should create a single rule without an input index', async () => {
Expand Down Expand Up @@ -519,12 +518,11 @@ export default ({ getService }: FtrProviderContext) => {
const bodyId = body.id;

await waitForAlertToComplete(supertest, log, bodyId);
await waitForRuleSuccessOrStatus(
await waitForRulePartialFailure({
supertest,
log,
bodyId,
RuleExecutionStatus['partial failure']
);
id: bodyId,
});

const { body: rule } = await supertest
.get(DETECTION_ENGINE_RULES_URL)
Expand All @@ -551,12 +549,11 @@ export default ({ getService }: FtrProviderContext) => {
.expect(200);
const bodyId = body.id;

await waitForRuleSuccessOrStatus(
await waitForRulePartialFailure({
supertest,
log,
bodyId,
RuleExecutionStatus['partial failure']
);
id: bodyId,
});
await waitForSignalsToBePresent(supertest, log, 2, [bodyId]);

const { body: rule } = await supertest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
getSimpleRuleWithoutRuleId,
removeServerGeneratedProperties,
removeServerGeneratedPropertiesIncludingRuleId,
waitForRuleSuccessOrStatus,
waitForRuleSuccess,
} from '../../utils';

// eslint-disable-next-line import/no-default-export
Expand Down Expand Up @@ -109,7 +109,7 @@ export default ({ getService }: FtrProviderContext): void => {
.send([simpleRule])
.expect(200);

await waitForRuleSuccessOrStatus(supertest, log, body[0].id);
await waitForRuleSuccess({ supertest, log, id: body[0].id });
});

it('should create a single rule without a rule_id', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import expect from 'expect';

import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants';
import { RuleExecutionStatus } from '@kbn/security-solution-plugin/common/detection_engine/rule_monitoring';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import {
binaryToString,
Expand All @@ -20,7 +19,7 @@ import {
getSimpleRuleOutput,
getWebHookAction,
removeServerGeneratedProperties,
waitForRuleSuccessOrStatus,
waitForRulePartialFailure,
} from '../../utils';

// eslint-disable-next-line import/no-default-export
Expand Down Expand Up @@ -54,19 +53,13 @@ export default ({ getService }: FtrProviderContext): void => {
it('should validate exported rule schema when its exported by its rule_id', async () => {
const ruleId = 'rule-1';

const rule = await createRule(supertest, log, getSimpleRule(ruleId, true));
await createRule(supertest, log, getSimpleRule(ruleId, true));

await waitForRuleSuccessOrStatus(
await waitForRulePartialFailure({
supertest,
log,
rule.id,
RuleExecutionStatus['partial failure']
);
// to properly execute the test on rule's data with runtime fields some delay is needed as
// ES Search API may return outdated data
// it causes a reliable delay so exported rule's SO contains runtime fields returned via ES Search API
// and will be removed after addressing this issue
await new Promise((r) => setTimeout(r, 1000));
ruleId,
});

const { body } = await supertest
.post(`${DETECTION_ENGINE_RULES_URL}/_export`)
Expand All @@ -86,26 +79,19 @@ export default ({ getService }: FtrProviderContext): void => {
const ruleId1 = 'rule-1';
const ruleId2 = 'rule-2';

const rule1 = await createRule(supertest, log, getSimpleRule(ruleId1, true));
const rule2 = await createRule(supertest, log, getSimpleRule(ruleId2, true));
await createRule(supertest, log, getSimpleRule(ruleId1, true));
await createRule(supertest, log, getSimpleRule(ruleId2, true));

await waitForRuleSuccessOrStatus(
await waitForRulePartialFailure({
supertest,
log,
rule1.id,
RuleExecutionStatus['partial failure']
);
await waitForRuleSuccessOrStatus(
ruleId: ruleId1,
});
await waitForRulePartialFailure({
supertest,
log,
rule2.id,
RuleExecutionStatus['partial failure']
);
// to properly execute the test on rule's data with runtime fields some delay is needed as
// ES Search API may return outdated data
// it causes a reliable delay so exported rule's SO contains runtime fields returned via ES Search API
// and will be removed after addressing this issue
await new Promise((r) => setTimeout(r, 1000));
ruleId: ruleId2,
});

const { body } = await supertest
.post(`${DETECTION_ENGINE_RULES_URL}/_export`)
Expand Down
Loading

0 comments on commit 519185f

Please sign in to comment.