[Security Solution] Exceptions: Cypress tests to cover mapping conflicts functionality (#151366)

## Summary

This PR adds cypress tests to cover new rule exceptions functionality
introduced in [this PR](https://github.com/elastic/kibana/pull/149149).

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Ievgen Sorokopud 2023-03-07 22:21:51 +01:00 committed by GitHub
parent 5da80301fc
commit 7f9139f070
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 216 additions and 37 deletions

View file

@ -226,10 +226,15 @@ export const useField = ({
</>
);
return (
<EuiToolTip position="bottom" content={tooltipContent}>
<EuiToolTip
data-test-subj="mappingConflictsTooltip"
position="bottom"
content={tooltipContent}
>
<>
{label}
<EuiIcon
data-test-subj="mappingConflictsWarningIcon"
tabIndex={0}
type="alert"
title={i18n.FIELD_CONFLICT_INDICES_WARNING_TITLE}

View file

@ -224,29 +224,40 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
id={'1'}
buttonContent={
<>
<EuiIcon tabIndex={0} type="alert" size="s" css={warningIconCss} />
<EuiIcon
data-test-subj="mappingConflictsAccordionIcon"
tabIndex={0}
type="alert"
size="s"
css={warningIconCss}
/>
{i18n.FIELD_CONFLICT_INDICES_WARNING_DESCRIPTION}
</>
}
arrowDisplay="none"
>
{conflictsInfo.map((info) => {
const groupDetails = info.groupedIndices.map(
({ name, count }) =>
`${count > 1 ? i18n.CONFLICT_MULTIPLE_INDEX_DESCRIPTION(name, count) : name}`
);
return (
<>
<EuiSpacer size="s" />
{`${
info.totalIndexCount > 1
? i18n.CONFLICT_MULTIPLE_INDEX_DESCRIPTION(info.type, info.totalIndexCount)
: info.type
}: ${groupDetails.join(', ')}`}
</>
);
})}
<EuiSpacer size="s" />
<div data-test-subj="mappingConflictsDescription">
{conflictsInfo.map((info) => {
const groupDetails = info.groupedIndices.map(
({ name, count }) =>
`${count > 1 ? i18n.CONFLICT_MULTIPLE_INDEX_DESCRIPTION(name, count) : name}`
);
return (
<>
<EuiSpacer size="s" />
{`${
info.totalIndexCount > 1
? i18n.CONFLICT_MULTIPLE_INDEX_DESCRIPTION(
info.type,
info.totalIndexCount
)
: info.type
}: ${groupDetails.join(', ')}`}
</>
);
})}
<EuiSpacer size="s" />
</div>
</EuiAccordion>
</>
);

View file

@ -30,13 +30,16 @@ import {
addExceptionEntryOperatorValue,
addExceptionFlyoutItemName,
closeExceptionBuilderFlyout,
searchExceptionEntryFieldWithPrefix,
selectCurrentEntryField,
showFieldConflictsWarningTooltipWithMessage,
showMappingConflictsWarningMessage,
} from '../../../tasks/exceptions';
import {
ADD_AND_BTN,
ADD_OR_BTN,
ADD_NESTED_BTN,
ENTRY_DELETE_BTN,
FIELD_INPUT,
LOADING_SPINNER,
EXCEPTION_ITEM_CONTAINER,
EXCEPTION_FIELD_LIST,
@ -64,18 +67,23 @@ import { getExceptionList } from '../../../objects/exception';
// to test in enzyme and very small changes can inadvertently add
// bugs. As the complexity within the builder grows, these should
// ensure the most basic logic holds.
describe('Exceptions flyout', () => {
describe('Exceptions flyout', { testIsolation: false }, () => {
before(() => {
esArchiverResetKibana();
// this is a made-up index that has just the necessary
// mappings to conduct tests, avoiding loading large
// amounts of data like in auditbeat_exceptions
esArchiverLoad('exceptions');
esArchiverLoad('conflicts_1');
esArchiverLoad('conflicts_2');
login();
createExceptionList(getExceptionList(), getExceptionList().list_id).then((response) =>
createCustomRule({
...getNewRule(),
dataSource: { index: ['auditbeat-*', 'exceptions-*'], type: 'indexPatterns' },
dataSource: {
index: ['auditbeat-*', 'exceptions-*', 'conflicts-*'],
type: 'indexPatterns',
},
exceptionLists: [
{
id: response.body.id,
@ -95,6 +103,10 @@ describe('Exceptions flyout', () => {
goToExceptionsTab();
});
afterEach(() => {
closeExceptionBuilderFlyout();
});
after(() => {
esArchiverUnload('exceptions');
});
@ -123,8 +135,6 @@ describe('Exceptions flyout', () => {
// add value again and button should be enabled again
addExceptionEntryFieldMatchAnyValue('test', 0);
cy.get(CONFIRM_BTN).should('be.enabled');
closeExceptionBuilderFlyout();
});
it('Validates custom fields correctly', () => {
@ -138,8 +148,6 @@ describe('Exceptions flyout', () => {
addExceptionEntryFieldValue('blooberty', 0);
addExceptionEntryFieldValueValue('blah', 0);
cy.get(CONFIRM_BTN).should('be.enabled');
closeExceptionBuilderFlyout();
});
it('Does not overwrite values and-ed together', () => {
@ -161,8 +169,6 @@ describe('Exceptions flyout', () => {
cy.get(LOADING_SPINNER).should('not.exist');
cy.get(FIELD_INPUT_PARENT).eq(0).should('have.text', 'agent.name');
cy.get(FIELD_INPUT_PARENT).eq(1).should('have.text', 'c');
closeExceptionBuilderFlyout();
});
it('Does not overwrite values or-ed together', () => {
@ -218,8 +224,6 @@ describe('Exceptions flyout', () => {
.eq(1)
.should('have.text', 'user.id.keyword');
cy.get(EXCEPTION_ITEM_CONTAINER).eq(1).should('not.exist');
closeExceptionBuilderFlyout();
});
it('Does not overwrite values of nested entry items', () => {
@ -290,19 +294,14 @@ describe('Exceptions flyout', () => {
.find(FIELD_INPUT_PARENT)
.eq(1)
.should('have.text', '@timestamp');
closeExceptionBuilderFlyout();
});
it('Contains custom index fields', () => {
// open add exception modal
openExceptionFlyoutFromEmptyViewerPrompt();
cy.get(FIELD_INPUT).eq(0).click({ force: true });
cy.get(FIELD_INPUT).eq(0).type('unique');
searchExceptionEntryFieldWithPrefix('unique');
cy.get(EXCEPTION_FIELD_LIST).contains('unique_value.test');
closeExceptionBuilderFlyout();
});
it('Validates auto-suggested fields correctly', () => {
@ -317,8 +316,28 @@ describe('Exceptions flyout', () => {
cy.get(VALUES_INPUT).eq(0).type(`{enter}`);
cy.get(VALUES_INPUT).eq(0).type(`{downarrow}{enter}`);
cy.get(CONFIRM_BTN).should('be.enabled');
});
closeExceptionBuilderFlyout();
it('Warns users about mapping conflicts on problematic field selection', async () => {
// open add exception modal
openExceptionFlyoutFromEmptyViewerPrompt();
// find 'doc_id' field which has mapping conflicts accross different indices
searchExceptionEntryFieldWithPrefix('doc_id');
const warningMessage =
'This field is defined as different types across the following indices or is unmapped. This can cause unexpected query results.boolean: conflicts-0002long: conflicts-0001';
// hovering field should show warning tooltip
showFieldConflictsWarningTooltipWithMessage(warningMessage);
// select problematic field
selectCurrentEntryField();
// check that we show warning after the field selection in form of accordion component
// underneath the field component and clicking on which reveals the extended warning message
// with conflicts details
showMappingConflictsWarningMessage(warningMessage);
});
// TODO - Add back in error states into modal

View file

@ -68,6 +68,18 @@ export const EXCEPTION_ITEM_CONTAINER = '[data-test-subj="exceptionEntriesContai
export const EXCEPTION_FIELD_LIST =
'[data-test-subj="comboBoxOptionsList fieldAutocompleteComboBox-optionsList"]';
export const EXCEPTION_FIELD_MAPPING_CONFLICTS_TOOLTIP =
'[data-test-subj="mappingConflictsTooltip"]';
export const EXCEPTION_FIELD_MAPPING_CONFLICTS_ICON =
'[data-test-subj="mappingConflictsWarningIcon"]';
export const EXCEPTION_FIELD_MAPPING_CONFLICTS_ACCORDION_ICON =
'[data-test-subj="mappingConflictsAccordionIcon"]';
export const EXCEPTION_FIELD_MAPPING_CONFLICTS_DESCRIPTION =
'[data-test-subj="mappingConflictsDescription"]';
export const EXCEPTION_FLYOUT_TITLE = '[data-test-subj="exceptionFlyoutTitle"]';
export const EXCEPTION_EDIT_FLYOUT_SAVE_BTN = '[data-test-subj="editExceptionConfirmButton"]';

View file

@ -24,6 +24,10 @@ import {
SHARED_LIST_SWITCH,
OS_SELECTION_SECTION,
OS_INPUT,
EXCEPTION_FIELD_MAPPING_CONFLICTS_ICON,
EXCEPTION_FIELD_MAPPING_CONFLICTS_TOOLTIP,
EXCEPTION_FIELD_MAPPING_CONFLICTS_ACCORDION_ICON,
EXCEPTION_FIELD_MAPPING_CONFLICTS_DESCRIPTION,
} from '../screens/exceptions';
export const addExceptionEntryFieldValueOfItemX = (
@ -39,6 +43,26 @@ export const addExceptionEntryFieldValueOfItemX = (
cy.get(EXCEPTION_FLYOUT_TITLE).click();
};
export const searchExceptionEntryFieldWithPrefix = (fieldPrefix: string, index = 0) => {
cy.get(FIELD_INPUT).eq(index).click({ force: true });
cy.get(FIELD_INPUT).eq(index).type(fieldPrefix);
};
export const showFieldConflictsWarningTooltipWithMessage = (message: string, index = 0) => {
cy.get(EXCEPTION_FIELD_MAPPING_CONFLICTS_ICON).eq(index).trigger('mouseover');
cy.get(EXCEPTION_FIELD_MAPPING_CONFLICTS_TOOLTIP).should('be.visible');
cy.get(EXCEPTION_FIELD_MAPPING_CONFLICTS_TOOLTIP).should('have.text', message);
};
export const showMappingConflictsWarningMessage = (message: string, index = 0) => {
cy.get(EXCEPTION_FIELD_MAPPING_CONFLICTS_ACCORDION_ICON).eq(index).click({ force: true });
cy.get(EXCEPTION_FIELD_MAPPING_CONFLICTS_DESCRIPTION).eq(index).should('have.text', message);
};
export const selectCurrentEntryField = (index = 0) => {
cy.get(FIELD_INPUT).eq(index).type(`{downarrow}{enter}`);
};
export const addExceptionEntryFieldValue = (field: string, index = 0) => {
cy.get(FIELD_INPUT).eq(index).type(`${field}{enter}`);
cy.get(EXCEPTION_FLYOUT_TITLE).click();

View file

@ -0,0 +1,27 @@
{
"type": "doc",
"value": {
"id": "k9V5UIYBpykOpthsKsB8",
"index": "conflicts-0001",
"source": {
"@timestamp": "2023-02-14T00:45:06.527Z",
"doc_id": 11111,
"my_field": "Value 1",
"title" : "Document 1"
}
}
}
{
"type": "doc",
"value": {
"id": "o9WEUIYBpykOpthswsA9",
"index": "conflicts-0001",
"source": {
"@timestamp": "2023-02-14T02:45:06.527Z",
"doc_id": 2222,
"my_field": "Value 2",
"title" : "Document 2"
}
}
}

View file

@ -0,0 +1,27 @@
{
"type": "index",
"value": {
"aliases": {
},
"index": "conflicts-0001",
"mappings": {
"dynamic": false,
"properties": {
"@timestamp":{
"type":"date"
},
"doc_id": {
"type": "long"
},
"my_field": {
"ignore_above": 1024,
"type": "keyword"
},
"title": {
"ignore_above": 1024,
"type": "keyword"
}
}
}
}
}

View file

@ -0,0 +1,27 @@
{
"type": "doc",
"value": {
"id": "tNWLUIYBpykOpthsMsB9",
"index": "conflicts-0002",
"source": {
"@timestamp": "2023-02-14T03:45:06.527Z",
"doc_id": false,
"my_unique_field": "Value 3",
"title" : "Document 3"
}
}
}
{
"type": "doc",
"value": {
"id": "ttWLUIYBpykOpthsUMAD",
"index": "conflicts-0002",
"source": {
"@timestamp": "2023-02-14T04:45:06.527Z",
"doc_id": true,
"my_unique_field": "Value 4",
"title" : "Document 4"
}
}
}

View file

@ -0,0 +1,27 @@
{
"type": "index",
"value": {
"aliases": {
},
"index": "conflicts-0002",
"mappings": {
"dynamic": false,
"properties": {
"@timestamp":{
"type":"date"
},
"doc_id": {
"type": "boolean"
},
"my_field": {
"ignore_above": 1024,
"type": "keyword"
},
"title": {
"ignore_above": 1024,
"type": "keyword"
}
}
}
}
}