Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,12 @@ describe('Detections Rules API', () => {
describe('createPrepackagedRules', () => {
beforeEach(() => {
fetchMock.mockClear();
fetchMock.mockResolvedValue('unknown');
fetchMock.mockResolvedValue({
rules_installed: 0,
rules_updated: 0,
timelines_installed: 0,
timelines_updated: 0,
});
});

test('check parameter url when creating pre-packaged rules', async () => {
Expand All @@ -423,7 +428,12 @@ describe('Detections Rules API', () => {
});
test('happy path', async () => {
const resp = await createPrepackagedRules({ signal: abortCtrl.signal });
expect(resp).toEqual(true);
expect(resp).toEqual({
rules_installed: 0,
rules_updated: 0,
timelines_installed: 0,
timelines_updated: 0,
});
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,25 @@ export const duplicateRules = async ({ rules }: DuplicateRulesProps): Promise<Bu
*
* @throws An error if response is not OK
*/
export const createPrepackagedRules = async ({ signal }: BasicFetchProps): Promise<boolean> => {
await KibanaServices.get().http.fetch<unknown>(DETECTION_ENGINE_PREPACKAGED_URL, {
export const createPrepackagedRules = async ({
signal,
}: BasicFetchProps): Promise<{
rules_installed: number;
rules_updated: number;
timelines_installed: number;
timelines_updated: number;
}> => {
const result = await KibanaServices.get().http.fetch<{
rules_installed: number;
rules_updated: number;
timelines_installed: number;
timelines_updated: number;
}>(DETECTION_ENGINE_PREPACKAGED_URL, {
method: 'PUT',
signal,
});

return true;
return result;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,21 @@ export const RULE_AND_TIMELINE_PREPACKAGED_FAILURE = i18n.translate(
export const RULE_AND_TIMELINE_PREPACKAGED_SUCCESS = i18n.translate(
'xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleAndTimelineSuccesDescription',
{
defaultMessage: 'Installed pre-packaged rules and timelines from elastic',
defaultMessage: 'Installed pre-packaged rules and timeline templates from elastic',
}
);

export const RULE_PREPACKAGED_SUCCESS = i18n.translate(
'xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleSuccesDescription',
{
defaultMessage: 'Installed pre-packaged rules from elastic',
}
);

export const TIMELINE_PREPACKAGED_SUCCESS = i18n.translate(
'xpack.securitySolution.containers.detectionEngine.createPrePackagedTimelineSuccesDescription',
{
defaultMessage: 'Installed pre-packaged timeline templates from elastic',
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { ReactElement } from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { ReturnPrePackagedRulesAndTimelines, usePrePackagedRules } from './use_pre_packaged_rules';
import * as api from './api';
import { shallow } from 'enzyme';
import * as i18n from './translations';

jest.mock('./api');
jest.mock('./api', () => ({
getPrePackagedRulesStatus: jest.fn(),
createPrepackagedRules: jest.fn(),
}));

describe('usePrePackagedRules', () => {
beforeEach(() => {
Expand Down Expand Up @@ -52,6 +57,21 @@ describe('usePrePackagedRules', () => {
});

test('fetch getPrePackagedRulesStatus', async () => {
(api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
rules_custom_installed: 33,
rules_installed: 12,
rules_not_installed: 0,
rules_not_updated: 0,
timelines_installed: 0,
timelines_not_installed: 0,
timelines_not_updated: 0,
});
(api.createPrepackagedRules as jest.Mock).mockResolvedValue({
rules_installed: 0,
rules_updated: 0,
timelines_installed: 0,
timelines_updated: 0,
});
await act(async () => {
const { result, waitForNextUpdate } = renderHook<unknown, ReturnPrePackagedRulesAndTimelines>(
() =>
Expand Down Expand Up @@ -87,7 +107,6 @@ describe('usePrePackagedRules', () => {
});

test('happy path to createPrePackagedRules', async () => {
const spyOnCreatePrepackagedRules = jest.spyOn(api, 'createPrepackagedRules');
await act(async () => {
const { result, waitForNextUpdate } = renderHook<unknown, ReturnPrePackagedRulesAndTimelines>(
() =>
Expand All @@ -106,7 +125,7 @@ describe('usePrePackagedRules', () => {
resp = await result.current.createPrePackagedRules();
}
expect(resp).toEqual(true);
expect(spyOnCreatePrepackagedRules).toHaveBeenCalled();
expect(api.createPrepackagedRules).toHaveBeenCalled();
expect(result.current).toEqual({
getLoadPrebuiltRulesAndTemplatesButton:
result.current.getLoadPrebuiltRulesAndTemplatesButton,
Expand All @@ -127,6 +146,253 @@ describe('usePrePackagedRules', () => {
});
});

test('getLoadPrebuiltRulesAndTemplatesButton - LOAD_PREPACKAGED_RULES', async () => {
(api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
rules_custom_installed: 0,
rules_installed: 0,
rules_not_installed: 1,
rules_not_updated: 0,
timelines_installed: 0,
timelines_not_installed: 0,
timelines_not_updated: 0,
});
(api.createPrepackagedRules as jest.Mock).mockResolvedValue({
rules_installed: 0,
rules_updated: 0,
timelines_installed: 0,
timelines_updated: 0,
});
await act(async () => {
const { result, waitForNextUpdate } = renderHook<unknown, ReturnPrePackagedRulesAndTimelines>(
() =>
usePrePackagedRules({
canUserCRUD: true,
hasIndexWrite: true,
isAuthenticated: true,
hasEncryptionKey: true,
isSignalIndexExists: true,
})
);
await waitForNextUpdate();
await waitForNextUpdate();

const button = result.current.getLoadPrebuiltRulesAndTemplatesButton({
isDisabled: false,
onClick: jest.fn(),
'data-test-subj': 'button',
});
const wrapper = shallow(button as ReactElement);
expect(wrapper.find('[data-test-subj="button"]').text()).toEqual(i18n.LOAD_PREPACKAGED_RULES);
});
});

test('getLoadPrebuiltRulesAndTemplatesButton - LOAD_PREPACKAGED_TIMELINE_TEMPLATES', async () => {
(api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
rules_custom_installed: 0,
rules_installed: 0,
rules_not_installed: 0,
rules_not_updated: 0,
timelines_installed: 0,
timelines_not_installed: 1,
timelines_not_updated: 0,
});
(api.createPrepackagedRules as jest.Mock).mockResolvedValue({
rules_installed: 0,
rules_updated: 0,
timelines_installed: 0,
timelines_updated: 0,
});
await act(async () => {
const { result, waitForNextUpdate } = renderHook<unknown, ReturnPrePackagedRulesAndTimelines>(
() =>
usePrePackagedRules({
canUserCRUD: true,
hasIndexWrite: true,
isAuthenticated: true,
hasEncryptionKey: true,
isSignalIndexExists: true,
})
);
await waitForNextUpdate();
await waitForNextUpdate();

const button = result.current.getLoadPrebuiltRulesAndTemplatesButton({
isDisabled: false,
onClick: jest.fn(),
'data-test-subj': 'button',
});
const wrapper = shallow(button as ReactElement);
expect(wrapper.find('[data-test-subj="button"]').text()).toEqual(
i18n.LOAD_PREPACKAGED_TIMELINE_TEMPLATES
);
});
});

test('getLoadPrebuiltRulesAndTemplatesButton - LOAD_PREPACKAGED_RULES_AND_TEMPLATES', async () => {
(api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
rules_custom_installed: 0,
rules_installed: 0,
rules_not_installed: 1,
rules_not_updated: 0,
timelines_installed: 0,
timelines_not_installed: 1,
timelines_not_updated: 0,
});
(api.createPrepackagedRules as jest.Mock).mockResolvedValue({
rules_installed: 0,
rules_updated: 0,
timelines_installed: 0,
timelines_updated: 0,
});
await act(async () => {
const { result, waitForNextUpdate } = renderHook<unknown, ReturnPrePackagedRulesAndTimelines>(
() =>
usePrePackagedRules({
canUserCRUD: true,
hasIndexWrite: true,
isAuthenticated: true,
hasEncryptionKey: true,
isSignalIndexExists: true,
})
);
await waitForNextUpdate();
await waitForNextUpdate();

const button = result.current.getLoadPrebuiltRulesAndTemplatesButton({
isDisabled: false,
onClick: jest.fn(),
'data-test-subj': 'button',
});
const wrapper = shallow(button as ReactElement);
expect(wrapper.find('[data-test-subj="button"]').text()).toEqual(
i18n.LOAD_PREPACKAGED_RULES_AND_TEMPLATES
);
});
});

test('getReloadPrebuiltRulesAndTemplatesButton - missing rules and templates', async () => {
(api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
rules_custom_installed: 0,
rules_installed: 1,
rules_not_installed: 1,
rules_not_updated: 0,
timelines_installed: 0,
timelines_not_installed: 1,
timelines_not_updated: 0,
});
(api.createPrepackagedRules as jest.Mock).mockResolvedValue({
rules_installed: 0,
rules_updated: 0,
timelines_installed: 0,
timelines_updated: 0,
});
await act(async () => {
const { result, waitForNextUpdate } = renderHook<unknown, ReturnPrePackagedRulesAndTimelines>(
() =>
usePrePackagedRules({
canUserCRUD: true,
hasIndexWrite: true,
isAuthenticated: true,
hasEncryptionKey: true,
isSignalIndexExists: true,
})
);
await waitForNextUpdate();
await waitForNextUpdate();

const button = result.current.getReloadPrebuiltRulesAndTemplatesButton({
isDisabled: false,
onClick: jest.fn(),
});
const wrapper = shallow(button as ReactElement);
expect(wrapper.find('[data-test-subj="reloadPrebuiltRulesBtn"]').text()).toEqual(
'Install 1 Elastic prebuilt rule and 1 Elastic prebuilt timeline '
);
});
});

test('getReloadPrebuiltRulesAndTemplatesButton - missing rules', async () => {
(api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
rules_custom_installed: 0,
rules_installed: 1,
rules_not_installed: 1,
rules_not_updated: 0,
timelines_installed: 0,
timelines_not_installed: 0,
timelines_not_updated: 0,
});
(api.createPrepackagedRules as jest.Mock).mockResolvedValue({
rules_installed: 0,
rules_updated: 0,
timelines_installed: 0,
timelines_updated: 0,
});
await act(async () => {
const { result, waitForNextUpdate } = renderHook<unknown, ReturnPrePackagedRulesAndTimelines>(
() =>
usePrePackagedRules({
canUserCRUD: true,
hasIndexWrite: true,
isAuthenticated: true,
hasEncryptionKey: true,
isSignalIndexExists: true,
})
);
await waitForNextUpdate();
await waitForNextUpdate();

const button = result.current.getReloadPrebuiltRulesAndTemplatesButton({
isDisabled: false,
onClick: jest.fn(),
});
const wrapper = shallow(button as ReactElement);
expect(wrapper.find('[data-test-subj="reloadPrebuiltRulesBtn"]').text()).toEqual(
'Install 1 Elastic prebuilt rule '
);
});
});

test('getReloadPrebuiltRulesAndTemplatesButton - missing templates', async () => {
(api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
rules_custom_installed: 0,
rules_installed: 1,
rules_not_installed: 0,
rules_not_updated: 0,
timelines_installed: 1,
timelines_not_installed: 1,
timelines_not_updated: 0,
});
(api.createPrepackagedRules as jest.Mock).mockResolvedValue({
rules_installed: 0,
rules_updated: 0,
timelines_installed: 0,
timelines_updated: 0,
});
await act(async () => {
const { result, waitForNextUpdate } = renderHook<unknown, ReturnPrePackagedRulesAndTimelines>(
() =>
usePrePackagedRules({
canUserCRUD: true,
hasIndexWrite: true,
isAuthenticated: true,
hasEncryptionKey: true,
isSignalIndexExists: true,
})
);
await waitForNextUpdate();
await waitForNextUpdate();

const button = result.current.getReloadPrebuiltRulesAndTemplatesButton({
isDisabled: false,
onClick: jest.fn(),
});
const wrapper = shallow(button as ReactElement);
expect(wrapper.find('[data-test-subj="reloadPrebuiltRulesBtn"]').text()).toEqual(
'Install 1 Elastic prebuilt timeline '
);
});
});

test('unhappy path to createPrePackagedRules', async () => {
const spyOnCreatePrepackagedRules = jest.spyOn(api, 'createPrepackagedRules');
spyOnCreatePrepackagedRules.mockImplementation(() => {
Expand Down
Loading