mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Co-authored-by: Steph Milovic <stephanie.milovic@elastic.co>
This commit is contained in:
parent
87f7fd0027
commit
6af011eb8b
14 changed files with 401 additions and 210 deletions
|
@ -20,6 +20,7 @@ import { getNewRule } from '../../objects/rule';
|
|||
import { refreshPage } from '../../tasks/security_header';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { openEventsViewerFieldsBrowser } from '../../tasks/hosts/events';
|
||||
import { assertFieldDisplayed, createField } from '../../tasks/create_runtime_field';
|
||||
|
||||
describe('Create DataView runtime field', () => {
|
||||
before(() => {
|
||||
|
@ -36,13 +37,8 @@ describe('Create DataView runtime field', () => {
|
|||
waitForAlertsToPopulate(500);
|
||||
openEventsViewerFieldsBrowser();
|
||||
|
||||
cy.get('[data-test-subj="create-field"]').click();
|
||||
cy.get('.indexPatternFieldEditorMaskOverlay').find('[data-test-subj="input"]').type(fieldName);
|
||||
cy.get('[data-test-subj="fieldSaveButton"]').click();
|
||||
|
||||
cy.get(
|
||||
`[data-test-subj="events-viewer-panel"] [data-test-subj="dataGridHeaderCell-${fieldName}"]`
|
||||
).should('exist');
|
||||
createField(fieldName);
|
||||
assertFieldDisplayed(fieldName, 'alerts');
|
||||
});
|
||||
|
||||
it('adds field to timeline', () => {
|
||||
|
@ -53,12 +49,7 @@ describe('Create DataView runtime field', () => {
|
|||
populateTimeline();
|
||||
openTimelineFieldsBrowser();
|
||||
|
||||
cy.get('[data-test-subj="create-field"]').click();
|
||||
cy.get('.indexPatternFieldEditorMaskOverlay').find('[data-test-subj="input"]').type(fieldName);
|
||||
cy.get('[data-test-subj="fieldSaveButton"]').click();
|
||||
|
||||
cy.get(`[data-test-subj="timeline"] [data-test-subj="header-text-${fieldName}"]`).should(
|
||||
'exist'
|
||||
);
|
||||
createField(fieldName);
|
||||
assertFieldDisplayed(fieldName);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,37 +10,43 @@ import {
|
|||
loginWithUserAndWaitForPageWithoutDateRange,
|
||||
} from '../../tasks/login';
|
||||
|
||||
import { HOSTS_URL } from '../../urls/navigation';
|
||||
import { waitForAllHostsToBeLoaded } from '../../tasks/hosts/all_hosts';
|
||||
import { HOSTS_URL, TIMELINES_URL } from '../../urls/navigation';
|
||||
import {
|
||||
clickOutOfSourcererTimeline,
|
||||
clickTimelineRadio,
|
||||
addIndexToDefault,
|
||||
clickAlertCheckbox,
|
||||
deleteAlertsIndex,
|
||||
deselectSourcererOptions,
|
||||
isCustomRadio,
|
||||
isDataViewSelection,
|
||||
isHostsStatValue,
|
||||
isNotCustomRadio,
|
||||
isKibanaDataViewOption,
|
||||
isNotSourcererOption,
|
||||
isNotSourcererSelection,
|
||||
isSourcererOptions,
|
||||
isSourcererSelection,
|
||||
openAdvancedSettings,
|
||||
openDataViewSelection,
|
||||
openSourcerer,
|
||||
resetSourcerer,
|
||||
setSourcererOption,
|
||||
unsetSourcererOption,
|
||||
saveSourcerer,
|
||||
waitForAlertsIndexToExist,
|
||||
} from '../../tasks/sourcerer';
|
||||
import { cleanKibana, postDataView } from '../../tasks/common';
|
||||
import { openTimelineUsingToggle } from '../../tasks/security_main';
|
||||
import { populateTimeline } from '../../tasks/timeline';
|
||||
import { SERVER_SIDE_EVENT_COUNT } from '../../screens/timeline';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { createUsersAndRoles, secReadCasesAll, secReadCasesAllUser } from '../../tasks/privileges';
|
||||
import { TOASTER } from '../../screens/configure_cases';
|
||||
import { DEFAULT_ALERTS_INDEX, DEFAULT_INDEX_PATTERN } from '../../../common/constants';
|
||||
import { SOURCERER } from '../../screens/sourcerer';
|
||||
|
||||
const usersToCreate = [secReadCasesAllUser];
|
||||
const rolesToCreate = [secReadCasesAll];
|
||||
// Skipped at the moment as this has flake due to click handler issues. This has been raised with team members
|
||||
// and the code is being re-worked and then these tests will be unskipped
|
||||
const siemDataViewTitle = 'Security Default Data View';
|
||||
const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,beats*,siem-read*,.kibana*,fakebeat-*'];
|
||||
|
||||
describe('Sourcerer', () => {
|
||||
beforeEach(() => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
deleteAlertsIndex();
|
||||
dataViews.forEach((dataView: string) => postDataView(dataView));
|
||||
});
|
||||
describe('permissions', () => {
|
||||
before(() => {
|
||||
|
@ -51,88 +57,175 @@ describe('Sourcerer', () => {
|
|||
cy.get(TOASTER).should('have.text', 'Write role required to generate data');
|
||||
});
|
||||
});
|
||||
// Originially written in December 2020, flakey from day1
|
||||
// has always been skipped with intentions to fix, see note at top of file
|
||||
describe.skip('Default scope', () => {
|
||||
|
||||
describe('Default scope', () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
loginAndWaitForPage(HOSTS_URL);
|
||||
});
|
||||
|
||||
it('has SIEM index patterns selected on initial load', () => {
|
||||
it('correctly loads SIEM data view', () => {
|
||||
openSourcerer();
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isSourcererOptions(DEFAULT_INDEX_PATTERN.filter((pattern) => pattern !== 'auditbeat-*'));
|
||||
});
|
||||
|
||||
describe('Modified badge', () => {
|
||||
it('Selecting new data view does not add a modified badge', () => {
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
openDataViewSelection();
|
||||
isKibanaDataViewOption(dataViews);
|
||||
cy.get(SOURCERER.selectListDefaultOption).should(`contain`, siemDataViewTitle);
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
});
|
||||
|
||||
it('shows modified badge when index patterns change and removes when reset', () => {
|
||||
openSourcerer();
|
||||
openDataViewSelection();
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
openAdvancedSettings();
|
||||
const patterns = dataViews[1].split(',');
|
||||
deselectSourcererOptions([patterns[0]]);
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`exist`);
|
||||
resetSourcerer();
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
});
|
||||
});
|
||||
|
||||
it('disables save when no patterns are selected', () => {
|
||||
openSourcerer();
|
||||
openAdvancedSettings();
|
||||
cy.get(SOURCERER.saveButton).should('be.enabled');
|
||||
deselectSourcererOptions(['auditbeat-*']);
|
||||
cy.get(SOURCERER.saveButton).should('be.disabled');
|
||||
});
|
||||
|
||||
it('adds a pattern to the default index and correctly filters out auditbeat-*', () => {
|
||||
openSourcerer();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
});
|
||||
|
||||
it('has Kibana index patterns in the options', () => {
|
||||
openSourcerer();
|
||||
isSourcererOptions([`metrics-*`, `logs-*`]);
|
||||
});
|
||||
|
||||
it('selected DATA_VIEW gets added to sourcerer', () => {
|
||||
setSourcererOption(`metrics-*`);
|
||||
openSourcerer();
|
||||
isSourcererSelection(`metrics-*`);
|
||||
});
|
||||
|
||||
it('does not return data without correct pattern selected', () => {
|
||||
waitForAllHostsToBeLoaded();
|
||||
isNotSourcererSelection('beats*');
|
||||
addIndexToDefault('beats*');
|
||||
isHostsStatValue('4 ');
|
||||
setSourcererOption(`metrics-*`);
|
||||
unsetSourcererOption(`auditbeat-*`);
|
||||
isHostsStatValue('0 ');
|
||||
});
|
||||
|
||||
it('reset button restores to original state', () => {
|
||||
setSourcererOption(`metrics-*`);
|
||||
openSourcerer();
|
||||
isSourcererSelection(`metrics-*`);
|
||||
resetSourcerer();
|
||||
openSourcerer();
|
||||
isNotSourcererSelection(`metrics-*`);
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isSourcererSelection('beats*');
|
||||
});
|
||||
});
|
||||
// Originially written in December 2020, flakey from day1
|
||||
// has always been skipped with intentions to fix
|
||||
describe.skip('Timeline scope', () => {
|
||||
|
||||
describe('Timeline scope', () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
loginAndWaitForPage(HOSTS_URL);
|
||||
loginAndWaitForPage(TIMELINES_URL);
|
||||
});
|
||||
|
||||
const alertPatterns = ['.siem-signals-default'];
|
||||
const rawPatterns = ['auditbeat-*'];
|
||||
const allPatterns = [...alertPatterns, ...rawPatterns];
|
||||
|
||||
it('Radio buttons select correct sourcerer patterns', () => {
|
||||
it('correctly loads SIEM data view before and after signals index exists', () => {
|
||||
openTimelineUsingToggle();
|
||||
openSourcerer('timeline');
|
||||
allPatterns.forEach((ss) => isSourcererSelection(ss, 'timeline'));
|
||||
clickTimelineRadio('raw');
|
||||
rawPatterns.forEach((ss) => isSourcererSelection(ss, 'timeline'));
|
||||
alertPatterns.forEach((ss) => isNotSourcererSelection(ss, 'timeline'));
|
||||
clickTimelineRadio('alert');
|
||||
alertPatterns.forEach((ss) => isSourcererSelection(ss, 'timeline'));
|
||||
rawPatterns.forEach((ss) => isNotSourcererSelection(ss, 'timeline'));
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isNotSourcererSelection(`${DEFAULT_ALERTS_INDEX}-default`);
|
||||
isSourcererOptions(
|
||||
[...DEFAULT_INDEX_PATTERN, `${DEFAULT_ALERTS_INDEX}-default`].filter(
|
||||
(pattern) => pattern !== 'auditbeat-*'
|
||||
)
|
||||
);
|
||||
waitForAlertsIndexToExist();
|
||||
isSourcererOptions(DEFAULT_INDEX_PATTERN.filter((pattern) => pattern !== 'auditbeat-*'));
|
||||
isNotSourcererOption(`${DEFAULT_ALERTS_INDEX}-default`);
|
||||
});
|
||||
|
||||
it('Adding an option results in the custom radio becoming active', () => {
|
||||
openTimelineUsingToggle();
|
||||
openSourcerer('timeline');
|
||||
isNotCustomRadio();
|
||||
clickOutOfSourcererTimeline();
|
||||
const luckyOption = 'logs-*';
|
||||
setSourcererOption(luckyOption, 'timeline');
|
||||
openSourcerer('timeline');
|
||||
isCustomRadio();
|
||||
});
|
||||
describe('Modified badge', () => {
|
||||
it('Selecting new data view does not add a modified badge', () => {
|
||||
openTimelineUsingToggle();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
openDataViewSelection();
|
||||
isKibanaDataViewOption(dataViews);
|
||||
cy.get(SOURCERER.selectListDefaultOption).should(`contain`, siemDataViewTitle);
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
});
|
||||
|
||||
it('Selected index patterns are properly queried', () => {
|
||||
openTimelineUsingToggle();
|
||||
populateTimeline();
|
||||
openSourcerer('timeline');
|
||||
deselectSourcererOptions(rawPatterns, 'timeline');
|
||||
cy.get(SERVER_SIDE_EVENT_COUNT).should(($count) => expect(+$count.text()).to.eql(0));
|
||||
it('shows modified badge when index patterns change and removes when reset', () => {
|
||||
openTimelineUsingToggle();
|
||||
openSourcerer('timeline');
|
||||
openDataViewSelection();
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
openAdvancedSettings();
|
||||
const patterns = dataViews[1].split(',');
|
||||
deselectSourcererOptions([patterns[0]]);
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`exist`);
|
||||
resetSourcerer();
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
});
|
||||
});
|
||||
describe('Alerts checkbox', () => {
|
||||
beforeEach(() => {
|
||||
waitForAlertsIndexToExist();
|
||||
});
|
||||
const defaultPatterns = [`auditbeat-*`, `${DEFAULT_ALERTS_INDEX}-default`];
|
||||
it('alerts checkbox behaves as expected', () => {
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
defaultPatterns.forEach((pattern) => isSourcererSelection(pattern));
|
||||
openDataViewSelection();
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
dataViews[1]
|
||||
.split(',')
|
||||
.filter((pattern) => pattern !== 'fakebeat-*')
|
||||
.forEach((pattern) => isSourcererSelection(pattern));
|
||||
|
||||
clickAlertCheckbox();
|
||||
isNotSourcererSelection(`auditbeat-*`);
|
||||
isSourcererSelection(`${DEFAULT_ALERTS_INDEX}-default`);
|
||||
cy.get(SOURCERER.alertCheckbox).uncheck({ force: true });
|
||||
defaultPatterns.forEach((pattern) => isSourcererSelection(pattern));
|
||||
});
|
||||
|
||||
it('shows alerts badge when index patterns change and removes when reset', () => {
|
||||
clickAlertCheckbox();
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeAlerts).should(`exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeAlertsOption).should(`exist`);
|
||||
resetSourcerer();
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeAlerts).should(`not.exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeAlertsOption).should(`not.exist`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const CREATE_FIELD_BUTTON = '[data-test-subj="create-field"]';
|
||||
|
||||
export const RUNTIME_FIELD_INPUT = '.indexPatternFieldEditorMaskOverlay [data-test-subj="input"]';
|
||||
|
||||
export const SAVE_FIELD_BUTTON = '[data-test-subj="fieldSaveButton"]';
|
|
@ -5,26 +5,28 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export const SOURCERER_TRIGGER = '[data-test-subj="sourcerer-trigger"]';
|
||||
export const SOURCERER_INPUT =
|
||||
'[data-test-subj="sourcerer-combo-box"] [data-test-subj="comboBoxInput"]';
|
||||
export const SOURCERER_OPTIONS =
|
||||
'[data-test-subj="comboBoxOptionsList sourcerer-combo-box-optionsList"]';
|
||||
export const SOURCERER_SAVE_BUTTON = 'button[data-test-subj="sourcerer-save"]';
|
||||
export const SOURCERER_RESET_BUTTON = 'button[data-test-subj="sourcerer-reset"]';
|
||||
export const SOURCERER_POPOVER_TITLE = '.euiPopoverTitle';
|
||||
export const HOSTS_STAT = '[data-test-subj="stat-hosts"] [data-test-subj="stat-title"]';
|
||||
|
||||
export const SOURCERER_TIMELINE = {
|
||||
trigger: '[data-test-subj="sourcerer-timeline-trigger"]',
|
||||
advancedSettings: '[data-test-subj="advanced-settings"]',
|
||||
sourcerer: '[data-test-subj="timeline-sourcerer"]',
|
||||
sourcererInput: '[data-test-subj="timeline-sourcerer"] [data-test-subj="comboBoxInput"]',
|
||||
sourcererOptions: '[data-test-subj="comboBoxOptionsList timeline-sourcerer-optionsList"]',
|
||||
radioRaw: '[data-test-subj="timeline-sourcerer-radio"] label.euiRadio__label[for="raw"]',
|
||||
radioAlert: '[data-test-subj="timeline-sourcerer-radio"] label.euiRadio__label[for="alert"]',
|
||||
radioAll: '[data-test-subj="timeline-sourcerer-radio"] label.euiRadio__label[for="all"]',
|
||||
radioCustom: '[data-test-subj="timeline-sourcerer-radio"] input.euiRadio__input[id="custom"]',
|
||||
radioCustomLabel:
|
||||
'[data-test-subj="timeline-sourcerer-radio"] label.euiRadio__label[for="custom"]',
|
||||
export const SOURCERER = {
|
||||
alertCheckbox: '[data-test-subj="sourcerer-alert-only-checkbox"]',
|
||||
advancedSettings: '[data-test-subj="sourcerer-advanced-options-toggle"]',
|
||||
comboBoxInput: '[data-test-subj="sourcerer-combo-box"] [data-test-subj="comboBoxInput"]',
|
||||
comboBoxOptions: '[data-test-subj="sourcerer-combo-option"]',
|
||||
badgeModified: '[data-test-subj="sourcerer-modified-badge"]',
|
||||
badgeModifiedOption: '[data-test-subj="security-modified-option-badge"]',
|
||||
badgeAlerts: '[data-test-subj="sourcerer-alerts-badge"]',
|
||||
badgeAlertsOption: '[data-test-subj="security-alerts-option-badge"]',
|
||||
siemDefaultIndexInput:
|
||||
'[data-test-subj="advancedSetting-editField-securitySolution:defaultIndex"]',
|
||||
popoverTitle: '[data-test-subj="sourcerer-title"]',
|
||||
resetButton: 'button[data-test-subj="sourcerer-reset"]',
|
||||
saveButton: 'button[data-test-subj="sourcerer-save"]',
|
||||
selectActiveOption: 'button[data-test-subj="sourcerer-select"]',
|
||||
selectListOption: '.euiSuperSelect__item [data-test-subj="dataView-option-super"]',
|
||||
selectListDefaultOption: '.euiSuperSelect__item [data-test-subj="security-option-super"]',
|
||||
tooltip: '[data-test-subj="sourcerer-tooltip"]',
|
||||
triggerTimeline: '[data-test-subj="timeline-sourcerer-trigger"]',
|
||||
trigger: '[data-test-subj="sourcerer-trigger"]',
|
||||
wrapper: '[data-test-subj="sourcerer-popover"]',
|
||||
wrapperTimeline: '[data-test-subj="timeline-sourcerer-popover"]',
|
||||
};
|
||||
|
||||
export const HOSTS_STAT = '[data-test-subj="stat-hosts"] [data-test-subj="stat-title"]';
|
||||
|
|
|
@ -136,15 +136,3 @@ export const createSignalsIndex = () => {
|
|||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
});
|
||||
};
|
||||
|
||||
export const removeSignalsIndex = () => {
|
||||
cy.request({ url: '/api/detection_engine/index', failOnStatusCode: false }).then((response) => {
|
||||
if (response.status === 200) {
|
||||
cy.request({
|
||||
method: 'DELETE',
|
||||
url: `api/detection_engine/index`,
|
||||
headers: { 'kbn-xsrf': 'delete-signals' },
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -155,6 +155,22 @@ export const deleteCases = () => {
|
|||
});
|
||||
};
|
||||
|
||||
export const postDataView = (indexPattern: string) => {
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: `/api/index_patterns/index_pattern`,
|
||||
body: {
|
||||
index_pattern: {
|
||||
fieldAttrs: '{}',
|
||||
title: indexPattern,
|
||||
timeFieldName: '@timestamp',
|
||||
fields: '{}',
|
||||
},
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds-via-config' },
|
||||
});
|
||||
};
|
||||
|
||||
export const scrollToBottom = () => cy.scrollTo('bottom');
|
||||
|
||||
export const waitForPageToBeLoaded = () => {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 {
|
||||
CREATE_FIELD_BUTTON,
|
||||
RUNTIME_FIELD_INPUT,
|
||||
SAVE_FIELD_BUTTON,
|
||||
} from '../screens/create_runtime_field';
|
||||
|
||||
export const createField = (fieldName: string): Cypress.Chainable<JQuery<HTMLElement>> => {
|
||||
cy.get(CREATE_FIELD_BUTTON).click();
|
||||
cy.get(RUNTIME_FIELD_INPUT).type(fieldName);
|
||||
return cy.get(SAVE_FIELD_BUTTON).click();
|
||||
};
|
||||
|
||||
export const assertFieldDisplayed = (fieldName: string, view: 'alerts' | 'timeline' = 'timeline') =>
|
||||
view === 'alerts'
|
||||
? cy
|
||||
.get(
|
||||
`[data-test-subj="events-viewer-panel"] [data-test-subj="dataGridHeaderCell-${fieldName}"]`
|
||||
)
|
||||
.should('exist')
|
||||
: cy
|
||||
.get(`[data-test-subj="timeline"] [data-test-subj="header-text-${fieldName}"]`)
|
||||
.should('exist');
|
|
@ -295,6 +295,12 @@ export const loginAndWaitForPage = (url: string, role?: ROLES) => {
|
|||
);
|
||||
cy.get('[data-test-subj="headerGlobalNav"]');
|
||||
};
|
||||
export const waitForPage = (url: string) => {
|
||||
cy.visit(
|
||||
`${url}?timerange=(global:(linkTo:!(timeline),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)))`
|
||||
);
|
||||
cy.get('[data-test-subj="headerGlobalNav"]');
|
||||
};
|
||||
|
||||
export const loginAndWaitForPageWithoutDateRange = (url: string, role?: ROLES) => {
|
||||
login(role);
|
||||
|
|
|
@ -5,133 +5,179 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
HOSTS_STAT,
|
||||
SOURCERER_INPUT,
|
||||
SOURCERER_OPTIONS,
|
||||
SOURCERER_POPOVER_TITLE,
|
||||
SOURCERER_RESET_BUTTON,
|
||||
SOURCERER_SAVE_BUTTON,
|
||||
SOURCERER_TIMELINE,
|
||||
SOURCERER_TRIGGER,
|
||||
} from '../screens/sourcerer';
|
||||
import { HOSTS_STAT, SOURCERER } from '../screens/sourcerer';
|
||||
import { TIMELINE_TITLE } from '../screens/timeline';
|
||||
import { HOSTS_URL } from '../urls/navigation';
|
||||
import { waitForPage } from './login';
|
||||
import { openTimelineUsingToggle } from './security_main';
|
||||
import { DEFAULT_ALERTS_INDEX } from '../../common/constants';
|
||||
import { waitForAlertsIndexToBeCreated } from './alerts';
|
||||
import { createCustomRuleActivated } from './api_calls/rules';
|
||||
import { getNewRule } from '../objects/rule';
|
||||
|
||||
export const openSourcerer = (sourcererScope?: string) => {
|
||||
if (sourcererScope != null && sourcererScope === 'timeline') {
|
||||
return openTimelineSourcerer();
|
||||
}
|
||||
cy.get(SOURCERER_TRIGGER).should('be.enabled');
|
||||
cy.get(SOURCERER_TRIGGER).should('be.visible');
|
||||
cy.get(SOURCERER_TRIGGER).click();
|
||||
cy.get(SOURCERER.trigger).should('be.enabled');
|
||||
cy.get(SOURCERER.trigger).should('be.visible');
|
||||
cy.get(SOURCERER.trigger).click();
|
||||
cy.get(SOURCERER.wrapper).should('be.visible');
|
||||
};
|
||||
export const openTimelineSourcerer = () => {
|
||||
cy.get(SOURCERER_TIMELINE.trigger).should('be.enabled');
|
||||
cy.get(SOURCERER_TIMELINE.trigger).should('be.visible');
|
||||
cy.get(SOURCERER_TIMELINE.trigger).click();
|
||||
cy.get(SOURCERER_TIMELINE.advancedSettings).should(($div) => {
|
||||
if ($div.text() === 'Show Advanced') {
|
||||
$div.click();
|
||||
}
|
||||
expect(true).to.eq(true);
|
||||
});
|
||||
cy.get(SOURCERER.triggerTimeline).should('be.enabled');
|
||||
cy.get(SOURCERER.triggerTimeline).should('be.visible');
|
||||
cy.get(SOURCERER.triggerTimeline).first().click();
|
||||
cy.get(SOURCERER.wrapperTimeline).should('be.visible');
|
||||
};
|
||||
export const openAdvancedSettings = () => {
|
||||
cy.get(SOURCERER.advancedSettings).should('be.visible');
|
||||
cy.get(SOURCERER.advancedSettings).click();
|
||||
};
|
||||
export const openAdvancedSettings = () => {};
|
||||
|
||||
export const clickOutOfSelector = () => {
|
||||
return cy.get(SOURCERER_POPOVER_TITLE).first().click();
|
||||
return cy.get(SOURCERER.popoverTitle).first().click();
|
||||
};
|
||||
|
||||
const getScopedSelectors = (sourcererScope?: string): { input: string; options: string } =>
|
||||
sourcererScope != null && sourcererScope === 'timeline'
|
||||
? { input: SOURCERER_TIMELINE.sourcererInput, options: SOURCERER_TIMELINE.sourcererOptions }
|
||||
: { input: SOURCERER_INPUT, options: SOURCERER_OPTIONS };
|
||||
export const isDataViewSelection = (dataView: string) => {
|
||||
return cy.get(SOURCERER.selectActiveOption).should('contain', dataView);
|
||||
};
|
||||
|
||||
export const isSourcererSelection = (patternName: string, sourcererScope?: string) => {
|
||||
const { input } = getScopedSelectors(sourcererScope);
|
||||
return cy.get(input).find(`span[title="${patternName}"]`).should('exist');
|
||||
export const openDataViewSelection = () => cy.get(SOURCERER.selectActiveOption).click();
|
||||
export const isKibanaDataViewOption = (dataViews: string[]) => {
|
||||
return dataViews.every((dataView) => {
|
||||
return cy.get(SOURCERER.selectListOption).should(`contain`, dataView);
|
||||
});
|
||||
};
|
||||
|
||||
export const isSourcererSelection = (patternName: string) => {
|
||||
return cy.get(SOURCERER.comboBoxInput).find(`span[title="${patternName}"]`).should('exist');
|
||||
};
|
||||
|
||||
export const isHostsStatValue = (value: string) => {
|
||||
return cy.get(HOSTS_STAT).first().should('have.text', value);
|
||||
};
|
||||
|
||||
export const isNotSourcererSelection = (patternName: string, sourcererScope?: string) => {
|
||||
const { input } = getScopedSelectors(sourcererScope);
|
||||
return cy.get(input).find(`span[title="${patternName}"]`).should('not.exist');
|
||||
export const isNotSourcererSelection = (patternName: string) => {
|
||||
return cy.get(SOURCERER.comboBoxInput).find(`span[title="${patternName}"]`).should('not.exist');
|
||||
};
|
||||
export const isNotSourcererOption = (patternName: string) => {
|
||||
return cy
|
||||
.get(SOURCERER.comboBoxOptions)
|
||||
.find(`button[title="${patternName}"]`)
|
||||
.should('not.exist');
|
||||
};
|
||||
|
||||
export const isSourcererOptions = (patternNames: string[], sourcererScope?: string) => {
|
||||
const { input, options } = getScopedSelectors(sourcererScope);
|
||||
cy.get(input).click();
|
||||
export const isSourcererOptions = (patternNames: string[]) => {
|
||||
cy.get(SOURCERER.comboBoxInput).click();
|
||||
return patternNames.every((patternName) => {
|
||||
return cy
|
||||
.get(options)
|
||||
.find(`button.euiFilterSelectItem[title="${patternName}"]`)
|
||||
.its('length')
|
||||
.should('eq', 1);
|
||||
return cy.get(SOURCERER.comboBoxOptions).should(`contain`, patternName);
|
||||
});
|
||||
};
|
||||
|
||||
export const selectSourcererOption = (patternName: string, sourcererScope?: string) => {
|
||||
const { input, options } = getScopedSelectors(sourcererScope);
|
||||
cy.get(input).click();
|
||||
cy.get(options).find(`button.euiFilterSelectItem[title="${patternName}"]`).click();
|
||||
export const selectSourcererOption = (patternName: string) => {
|
||||
cy.get(SOURCERER.comboBoxInput).click();
|
||||
cy.get(SOURCERER.comboBoxOptions)
|
||||
.find(`button.euiFilterSelectItem[title="${patternName}"]`)
|
||||
.click();
|
||||
clickOutOfSelector();
|
||||
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
|
||||
return cy.get(SOURCERER.saveButton).click({ force: true });
|
||||
};
|
||||
|
||||
export const deselectSourcererOption = (patternName: string, sourcererScope?: string) => {
|
||||
const { input } = getScopedSelectors(sourcererScope);
|
||||
cy.get(input).find(`span[title="${patternName}"] button`).click();
|
||||
export const deselectSourcererOption = (patternName: string) => {
|
||||
cy.get(SOURCERER.comboBoxInput).find(`span[title="${patternName}"] button`).click();
|
||||
clickOutOfSelector();
|
||||
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
|
||||
return cy.get(SOURCERER.saveButton).click({ force: true });
|
||||
};
|
||||
|
||||
export const deselectSourcererOptions = (patternNames: string[], sourcererScope?: string) => {
|
||||
const { input } = getScopedSelectors(sourcererScope);
|
||||
export const deselectSourcererOptions = (patternNames: string[]) => {
|
||||
patternNames.forEach((patternName) =>
|
||||
cy.get(input).find(`span[title="${patternName}"] button`).click()
|
||||
cy.get(SOURCERER.comboBoxInput).find(`span[title="${patternName}"] button`).click()
|
||||
);
|
||||
};
|
||||
|
||||
export const saveSourcerer = () => {
|
||||
clickOutOfSelector();
|
||||
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
|
||||
return cy.get(SOURCERER.saveButton).click({ force: true });
|
||||
};
|
||||
|
||||
export const resetSourcerer = () => {
|
||||
cy.get(SOURCERER_RESET_BUTTON).click();
|
||||
clickOutOfSelector();
|
||||
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
|
||||
return cy.get(SOURCERER.resetButton).click();
|
||||
};
|
||||
|
||||
export const setSourcererOption = (patternName: string, sourcererScope?: string) => {
|
||||
openSourcerer(sourcererScope);
|
||||
isNotSourcererSelection(patternName, sourcererScope);
|
||||
selectSourcererOption(patternName, sourcererScope);
|
||||
isNotSourcererSelection(patternName);
|
||||
selectSourcererOption(patternName);
|
||||
};
|
||||
|
||||
export const unsetSourcererOption = (patternName: string, sourcererScope?: string) => {
|
||||
openSourcerer(sourcererScope);
|
||||
isSourcererSelection(patternName, sourcererScope);
|
||||
deselectSourcererOption(patternName, sourcererScope);
|
||||
};
|
||||
|
||||
export const clickTimelineRadio = (radioName: string) => {
|
||||
let theRadio = SOURCERER_TIMELINE.radioAll;
|
||||
if (radioName === 'alert') {
|
||||
theRadio = SOURCERER_TIMELINE.radioAlert;
|
||||
}
|
||||
if (radioName === 'raw') {
|
||||
theRadio = SOURCERER_TIMELINE.radioRaw;
|
||||
}
|
||||
return cy.get(theRadio).first().click();
|
||||
};
|
||||
|
||||
export const isCustomRadio = () => {
|
||||
return cy.get(SOURCERER_TIMELINE.radioCustom).should('be.enabled');
|
||||
};
|
||||
|
||||
export const isNotCustomRadio = () => {
|
||||
return cy.get(SOURCERER_TIMELINE.radioCustom).should('be.disabled');
|
||||
isSourcererSelection(patternName);
|
||||
deselectSourcererOption(patternName);
|
||||
};
|
||||
|
||||
export const clickOutOfSourcererTimeline = () => cy.get(TIMELINE_TITLE).first().click();
|
||||
|
||||
export const clickAlertCheckbox = () => cy.get(SOURCERER.alertCheckbox).check({ force: true });
|
||||
|
||||
export const addIndexToDefault = (index: string) => {
|
||||
cy.visit(`/app/management/kibana/settings?query=category:(securitySolution)`);
|
||||
cy.get(SOURCERER.siemDefaultIndexInput)
|
||||
.invoke('val')
|
||||
.then((patterns) => {
|
||||
cy.get(SOURCERER.siemDefaultIndexInput).type(`${patterns},${index}`);
|
||||
cy.get('body').then(($body) => {
|
||||
if ($body.find('[data-test-subj="toastCloseButton]"').length > 0) {
|
||||
cy.get('[data-test-subj="toastCloseButton]"').click();
|
||||
}
|
||||
});
|
||||
cy.get('button[data-test-subj="advancedSetting-saveButton"]').click();
|
||||
cy.get('.euiToast .euiButton--primary').click();
|
||||
waitForPage(HOSTS_URL);
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteAlertsIndex = () => {
|
||||
const alertsIndexUrl = `${Cypress.env(
|
||||
'ELASTICSEARCH_URL'
|
||||
)}/.internal.alerts-security.alerts-default-000001`;
|
||||
|
||||
cy.request({
|
||||
url: alertsIndexUrl,
|
||||
method: 'GET',
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
failOnStatusCode: false,
|
||||
}).then((response) => {
|
||||
if (response.status === 200) {
|
||||
cy.request({
|
||||
url: alertsIndexUrl,
|
||||
method: 'DELETE',
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const refreshUntilAlertsIndexExists = async () => {
|
||||
cy.waitUntil(
|
||||
() => {
|
||||
cy.reload();
|
||||
openTimelineUsingToggle();
|
||||
openSourcerer('timeline');
|
||||
openAdvancedSettings();
|
||||
|
||||
return cy
|
||||
.get(SOURCERER.comboBoxInput)
|
||||
.invoke('text')
|
||||
.then((txt) => txt.includes(`${DEFAULT_ALERTS_INDEX}-default`));
|
||||
},
|
||||
{ interval: 500, timeout: 12000 }
|
||||
);
|
||||
};
|
||||
|
||||
export const waitForAlertsIndexToExist = () => {
|
||||
waitForAlertsIndexToBeCreated();
|
||||
createCustomRuleActivated(getNewRule(), '1', '100m', 100);
|
||||
refreshUntilAlertsIndexExists();
|
||||
};
|
||||
|
|
|
@ -101,14 +101,18 @@ export const getDataViewSelectOptions = ({
|
|||
<span data-test-subj="security-option-super">
|
||||
<EuiIcon type="logoSecurity" size="s" /> {i18n.SECURITY_DEFAULT_DATA_VIEW_LABEL}
|
||||
{isModified && id === dataViewId && (
|
||||
<StyledBadge>{i18n.MODIFIED_BADGE_TITLE}</StyledBadge>
|
||||
<StyledBadge data-test-subj="security-modified-option-badge">
|
||||
{i18n.MODIFIED_BADGE_TITLE}
|
||||
</StyledBadge>
|
||||
)}
|
||||
</span>
|
||||
) : (
|
||||
<span data-test-subj="dataView-option-super">
|
||||
<EuiIcon type="logoKibana" size="s" /> {title}
|
||||
{isModified && id === dataViewId && (
|
||||
<StyledBadge>{i18n.MODIFIED_BADGE_TITLE}</StyledBadge>
|
||||
<StyledBadge data-test-subj="security-modified-option-badge">
|
||||
{i18n.MODIFIED_BADGE_TITLE}
|
||||
</StyledBadge>
|
||||
)}
|
||||
</span>
|
||||
),
|
||||
|
|
|
@ -29,7 +29,7 @@ import { useUpdateDataView } from './use_update_data_view';
|
|||
import { Trigger } from './trigger';
|
||||
import { AlertsCheckbox, SaveButtons, SourcererCallout } from './sub_components';
|
||||
|
||||
interface SourcererComponentProps {
|
||||
export interface SourcererComponentProps {
|
||||
scope: sourcererModel.SourcererScopeName;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,11 @@ export const TriggerComponent: FC<Props> = ({
|
|||
const badge = useMemo(() => {
|
||||
switch (isModified) {
|
||||
case 'modified':
|
||||
return <StyledBadge>{i18n.MODIFIED_BADGE_TITLE}</StyledBadge>;
|
||||
return (
|
||||
<StyledBadge data-test-subj="sourcerer-modified-badge">
|
||||
{i18n.MODIFIED_BADGE_TITLE}
|
||||
</StyledBadge>
|
||||
);
|
||||
case 'alerts':
|
||||
return (
|
||||
<StyledBadge data-test-subj="sourcerer-alerts-badge">
|
||||
|
|
|
@ -50,7 +50,6 @@ export const useDataView = (): { indexFieldsSearch: (selectedDataViewId: string)
|
|||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const indexFieldsSearch = useCallback(
|
||||
(selectedDataViewId: string) => {
|
||||
const asyncSearch = async () => {
|
||||
|
|
|
@ -199,6 +199,7 @@ export const QueryTabContentComponent: React.FC<Props> = ({
|
|||
// in order to include the exclude filters in the search that are not stored in the timeline
|
||||
selectedPatterns,
|
||||
} = useSourcererDataView(SourcererScopeName.timeline);
|
||||
|
||||
const { uiSettings } = useKibana().services;
|
||||
const ACTION_BUTTON_COUNT = 5;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue