Skip to content

Commit

Permalink
fixed tests
Browse files Browse the repository at this point in the history
  • Loading branch information
gmmorris committed Nov 5, 2020
1 parent 01c7c7d commit e9f2cd0
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,33 @@
*/

import uuid from 'uuid';
import { range } from 'lodash';
import { range, random, pick } from 'lodash';
import { AlertType } from '../../../../plugins/alerts/server';
import { DEFAULT_INSTANCES_TO_GENERATE, ALERTING_EXAMPLE_APP_ID } from '../../common/constants';

const ACTION_GROUPS = [
{ id: 'small', name: 'small', tshirtSize: 1 },
{ id: 'medium', name: 'medium', tshirtSize: 2 },
{ id: 'large', name: 'large', tshirtSize: 3 },
];

export const alertType: AlertType = {
id: 'example.always-firing',
name: 'Always firing',
actionGroups: [{ id: 'default', name: 'default' }],
defaultActionGroupId: 'default',
actionGroups: ACTION_GROUPS.map((actionGroup) => pick(actionGroup, ['id', 'name'])),
defaultActionGroupId: 'small',
async executor({ services, params: { instances = DEFAULT_INSTANCES_TO_GENERATE }, state }) {
const count = (state.count ?? 0) + 1;

range(instances)
.map(() => ({ id: uuid.v4() }))
.forEach((instance: { id: string }) => {
.map(() => ({ id: uuid.v4(), tshirtSize: random(1, 3) }))
.forEach((instance: { id: string; tshirtSize: number }) => {
services
.alertInstanceFactory(instance.id)
.replaceState({ triggerdOnCycle: count })
.scheduleActions('default');
.scheduleActions(
ACTION_GROUPS.find((actionGroup) => actionGroup.tshirtSize === instance.tshirtSize)!.id
);
});

return {
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/security_solution/common/shared_exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
export { NonEmptyString } from './detection_engine/schemas/types/non_empty_string';
export { DefaultArray } from './detection_engine/schemas/types/default_array';
export { DefaultUuid } from './detection_engine/schemas/types/default_uuid';
export { siemRuleActionGroups } from './detection_engine/signals/siem_rule_action_groups';
export { DefaultStringArray } from './detection_engine/schemas/types/default_string_array';
export {
DefaultVersionNumber,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ import {
import { AlertAction } from '../../../../../../alerts/common';
import { useKibana } from '../../../../common/lib/kibana';
import { FORM_ERRORS_TITLE } from './translations';
import { siemRuleActionGroups } from '../../../../../common';

type ThrottleSelectField = typeof SelectField;

const DEFAULT_ACTION_GROUP_ID = 'default';
const DEFAULT_ACTION_GROUP = siemRuleActionGroups[0];
const DEFAULT_ACTION_MESSAGE =
'Rule {{context.rule.name}} generated {{state.signals_count}} alerts';

Expand Down Expand Up @@ -52,12 +53,19 @@ export const RuleActionsField: ThrottleSelectField = ({ field, messageVariables
[field.value]
);

const setActionPropByIndex = (prop: 'id' | 'group', value: string, index: number) => {
const updatedActions = [...(actions as Array<Partial<AlertAction>>)];
updatedActions[index] = deepMerge(updatedActions[index], { [prop]: value });
field.setValue(updatedActions);
};
const setActionIdByIndex = useCallback(
(id: string, index: number) => {
const updatedActions = [...(actions as Array<Partial<AlertAction>>)];
updatedActions[index] = deepMerge(updatedActions[index], { id });
field.setValue(updatedActions);
},
(id: string, index: number) => setActionPropByIndex('id', id, index),
// eslint-disable-next-line react-hooks/exhaustive-deps
[field.setValue, actions]
);

const setActionGroupIdByIndex = useCallback(
(group: string, index: number) => setActionPropByIndex('group', group, index),
// eslint-disable-next-line react-hooks/exhaustive-deps
[field.setValue, actions]
);
Expand Down Expand Up @@ -118,7 +126,9 @@ export const RuleActionsField: ThrottleSelectField = ({ field, messageVariables
docLinks={docLinks}
capabilities={capabilities}
messageVariables={messageVariables}
defaultActionGroupId={DEFAULT_ACTION_GROUP_ID}
defaultActionGroupId={DEFAULT_ACTION_GROUP.id}
actionGroups={siemRuleActionGroups}
setActionGroupIdByIndex={setActionGroupIdByIndex}
setActionIdByIndex={setActionIdByIndex}
setAlertProperty={setAlertProperty}
setActionParamsProperty={setActionParamsProperty}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
import { Logger } from 'src/core/server';
import { schema } from '@kbn/config-schema';
import { NOTIFICATIONS_ID, SERVER_APP_ID } from '../../../../common/constants';
import { siemRuleActionGroups } from '../../../../common';

import { NotificationAlertTypeDefinition } from './types';
import { getSignalsCount } from './get_signals_count';
import { RuleAlertAttributes } from '../signals/types';
import { siemRuleActionGroups } from '../signals/siem_rule_action_groups';
import { scheduleNotificationActions } from './schedule_notification_actions';
import { getNotificationResultsLink } from './utils';
import { parseScheduleDates } from '../../../../common/detection_engine/parse_schedule_dates';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {
createSearchAfterReturnTypeFromResponse,
} from './utils';
import { signalParamsSchema } from './signal_params_schema';
import { siemRuleActionGroups } from './siem_rule_action_groups';
import { siemRuleActionGroups } from '../../../../common';
import { findMlSignals } from './find_ml_signals';
import { findThresholdSignals } from './find_threshold_signals';
import { bulkCreateMlSignals } from './bulk_create_ml_signals';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,6 @@ describe('action_form', () => {
};

describe('action_form in alert', () => {
let wrapper: ReactWrapper<any>;

async function setup(customActions?: AlertAction[]) {
const { loadAllActions } = jest.requireMock('../../lib/action_connector_api');
loadAllActions.mockResolvedValueOnce([
Expand Down Expand Up @@ -217,7 +215,7 @@ describe('action_form', () => {
mutedInstanceIds: [],
} as unknown) as Alert;

wrapper = mountWithIntl(
const wrapper = mountWithIntl(
<ActionForm
actions={initialAlert.actions}
messageVariables={[
Expand All @@ -228,6 +226,10 @@ describe('action_form', () => {
setActionIdByIndex={(id: string, index: number) => {
initialAlert.actions[index].id = id;
}}
actionGroups={[{ id: 'default', name: 'Default' }]}
setActionGroupIdByIndex={(group: string, index: number) => {
initialAlert.actions[index].group = group;
}}
setAlertProperty={(_updatedActions: AlertAction[]) => {}}
setActionParamsProperty={(key: string, value: any, index: number) =>
(initialAlert.actions[index] = { ...initialAlert.actions[index], [key]: value })
Expand Down Expand Up @@ -297,13 +299,16 @@ describe('action_form', () => {
await nextTick();
wrapper.update();
});

return wrapper;
}

it('renders available action cards', async () => {
await setup();
const wrapper = await setup();
const actionOption = wrapper.find(
`[data-test-subj="${actionType.id}-ActionTypeSelectOption"]`
);
wrapper.debug();
expect(actionOption.exists()).toBeTruthy();
expect(
wrapper
Expand All @@ -314,60 +319,80 @@ describe('action_form', () => {
});

it('does not render action types disabled by config', async () => {
await setup();
const wrapper = await setup();
const actionOption = wrapper.find(
'[data-test-subj="disabled-by-config-ActionTypeSelectOption"]'
);
expect(actionOption.exists()).toBeFalsy();
});

it('render action types which is preconfigured only (disabled by config and with preconfigured connectors)', async () => {
await setup();
const wrapper = await setup();
const actionOption = wrapper.find('[data-test-subj="preconfigured-ActionTypeSelectOption"]');
expect(actionOption.exists()).toBeTruthy();
});

it('renders available action groups for the selected action type', async () => {
const wrapper = await setup();
const actionOption = wrapper.find(
`[data-test-subj="${actionType.id}-ActionTypeSelectOption"]`
);
actionOption.first().simulate('click');
const actionGroupsSelect = wrapper.find(
`[data-test-subj="addNewActionConnectorActionGroup-0"]`
);
expect((actionGroupsSelect.first().props() as any).options).toMatchInlineSnapshot(`
Array [
Object {
"data-test-subj": "addNewActionConnectorActionGroup-0-option-default",
"inputDisplay": "Default",
"value": "default",
},
]
`);
});

it('renders available connectors for the selected action type', async () => {
await setup();
const wrapper = await setup();
const actionOption = wrapper.find(
`[data-test-subj="${actionType.id}-ActionTypeSelectOption"]`
);
actionOption.first().simulate('click');
const combobox = wrapper.find(`[data-test-subj="selectActionConnector-${actionType.id}"]`);
expect((combobox.first().props() as any).options).toMatchInlineSnapshot(`
Array [
Object {
"id": "test",
"key": "test",
"label": "Test connector ",
},
Object {
"id": "test2",
"key": "test2",
"label": "Test connector 2 (preconfigured)",
},
]
`);
Array [
Object {
"id": "test",
"key": "test",
"label": "Test connector ",
},
Object {
"id": "test2",
"key": "test2",
"label": "Test connector 2 (preconfigured)",
},
]
`);
});

it('renders only preconfigured connectors for the selected preconfigured action type', async () => {
await setup();
const wrapper = await setup();
const actionOption = wrapper.find('[data-test-subj="preconfigured-ActionTypeSelectOption"]');
actionOption.first().simulate('click');
const combobox = wrapper.find('[data-test-subj="selectActionConnector-preconfigured"]');
expect((combobox.first().props() as any).options).toMatchInlineSnapshot(`
Array [
Object {
"id": "test3",
"key": "test3",
"label": "Preconfigured Only (preconfigured)",
},
]
`);
Array [
Object {
"id": "test3",
"key": "test3",
"label": "Preconfigured Only (preconfigured)",
},
]
`);
});

it('does not render "Add connector" button for preconfigured only action type', async () => {
await setup();
const wrapper = await setup();
const actionOption = wrapper.find('[data-test-subj="preconfigured-ActionTypeSelectOption"]');
actionOption.first().simulate('click');
const preconfigPannel = wrapper.find('[data-test-subj="alertActionAccordion-default"]');
Expand All @@ -378,7 +403,7 @@ describe('action_form', () => {
});

it('renders action types disabled by license', async () => {
await setup();
const wrapper = await setup();
const actionOption = wrapper.find(
'[data-test-subj="disabled-by-license-ActionTypeSelectOption"]'
);
Expand All @@ -391,7 +416,7 @@ describe('action_form', () => {
});

it(`shouldn't render action types without params component`, async () => {
await setup();
const wrapper = await setup();
const actionOption = wrapper.find(
`[data-test-subj="${actionTypeWithoutParams.id}-ActionTypeSelectOption"]`
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export const ActionForm = ({
const [activeActionItem, setActiveActionItem] = useState<ActiveActionConnectorState | undefined>(
undefined
);
const [isAddActionPanelOpen, setIsAddActionPanelOpen] = useState<boolean>(actions.length === 0);
const [isAddActionPanelOpen, setIsAddActionPanelOpen] = useState<boolean>(true);
const [connectors, setConnectors] = useState<ActionConnector[]>([]);
const [isLoadingConnectors, setIsLoadingConnectors] = useState<boolean>(false);
const [isLoadingActionTypes, setIsLoadingActionTypes] = useState<boolean>(false);
Expand Down Expand Up @@ -341,7 +341,7 @@ export const ActionForm = ({
singleSelection={{ asPlainText: true }}
options={optionsList}
id={`selectActionConnector-${actionItem.id}`}
data-test-subj={`selectActionConnector-${index}`}
data-test-subj={`selectActionConnector-${actionItem.actionTypeId}`}
selectedOptions={getSelectedOptions(actionItem.id)}
onChange={(selectedOptions) => {
setActionIdByIndex(selectedOptions[0].id ?? '', index);
Expand Down

0 comments on commit e9f2cd0

Please sign in to comment.