From d12d9c28888cf005b156882634eb983bf684e40e Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Tue, 13 Apr 2021 15:41:54 -0400 Subject: [PATCH 1/2] Adding mocks --- x-pack/plugins/cases/server/client/client.ts | 1 - .../plugins/cases/server/client/index.test.ts | 53 ------ x-pack/plugins/cases/server/client/mocks.ts | 170 +++++++----------- .../server/connectors/case/index.test.ts | 60 ++----- x-pack/plugins/cases/server/services/mocks.ts | 126 ++++++++----- 5 files changed, 163 insertions(+), 247 deletions(-) delete mode 100644 x-pack/plugins/cases/server/client/index.test.ts diff --git a/x-pack/plugins/cases/server/client/client.ts b/x-pack/plugins/cases/server/client/client.ts index 702329f7bcca2..cb2201b8721f2 100644 --- a/x-pack/plugins/cases/server/client/client.ts +++ b/x-pack/plugins/cases/server/client/client.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import Boom from '@hapi/boom'; import { CasesClientArgs } from './types'; import { CasesSubClient, createCasesSubClient } from './cases/client'; diff --git a/x-pack/plugins/cases/server/client/index.test.ts b/x-pack/plugins/cases/server/client/index.test.ts deleted file mode 100644 index 455e4ae106688..0000000000000 --- a/x-pack/plugins/cases/server/client/index.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 { - elasticsearchServiceMock, - loggingSystemMock, - savedObjectsClientMock, -} from '../../../../../src/core/server/mocks'; -import { nullUser } from '../common'; -import { - connectorMappingsServiceMock, - createCaseServiceMock, - createConfigureServiceMock, - createUserActionServiceMock, - createAlertServiceMock, -} from '../services/mocks'; -import { createAuthorizationMock } from '../authorization/mock'; - -jest.mock('./client'); -import { CasesClientHandler } from './client'; -import { createExternalCasesClient } from './index'; - -const logger = loggingSystemMock.create().get('case'); -const esClient = elasticsearchServiceMock.createElasticsearchClient(); -const caseConfigureService = createConfigureServiceMock(); -const alertsService = createAlertServiceMock(); -const caseService = createCaseServiceMock(); -const connectorMappingsService = connectorMappingsServiceMock(); -const savedObjectsClient = savedObjectsClientMock.create(); -const userActionService = createUserActionServiceMock(); -const authorization = createAuthorizationMock(); - -describe('createExternalCasesClient()', () => { - test('it creates the client correctly', async () => { - createExternalCasesClient({ - scopedClusterClient: esClient, - alertsService, - caseConfigureService, - caseService, - connectorMappingsService, - user: nullUser, - savedObjectsClient, - userActionService, - logger, - authorization, - }); - expect(CasesClientHandler).toHaveBeenCalledTimes(1); - }); -}); diff --git a/x-pack/plugins/cases/server/client/mocks.ts b/x-pack/plugins/cases/server/client/mocks.ts index cf964e5e53c4f..03ad31fc2c1bb 100644 --- a/x-pack/plugins/cases/server/client/mocks.ts +++ b/x-pack/plugins/cases/server/client/mocks.ts @@ -5,115 +5,81 @@ * 2.0. */ -import { ElasticsearchClient, KibanaRequest } from 'kibana/server'; -import { DeeplyMockedKeys } from 'packages/kbn-utility-types/target/jest'; -import { - loggingSystemMock, - elasticsearchServiceMock, - savedObjectsServiceMock, -} from '../../../../../src/core/server/mocks'; -import { - AlertServiceContract, - CaseConfigureService, - CaseService, - CaseUserActionService, - ConnectorMappingsService, -} from '../services'; -import { CasesClient } from './types'; -import { authenticationMock } from '../routes/api/__fixtures__'; -import { featuresPluginMock } from '../../../features/server/mocks'; +import { PublicContract, PublicMethodsOf } from '@kbn/utility-types'; + +import { CasesClient, CasesClientInternal } from '.'; +import { AttachmentsSubClient } from './attachments/client'; +import { CasesSubClient } from './cases/client'; import { CasesClientFactory } from './factory'; -import { KibanaFeature } from '../../../features/common'; - -export type CasesClientPluginContractMock = jest.Mocked; -export const createExternalCasesClientMock = (): CasesClientPluginContractMock => ({ - addComment: jest.fn(), - create: jest.fn(), - get: jest.fn(), - push: jest.fn(), - getAlerts: jest.fn(), - getFields: jest.fn(), - getMappings: jest.fn(), - getUserActions: jest.fn(), - update: jest.fn(), - updateAlertsStatus: jest.fn(), - find: jest.fn(), -}); - -export const createCasesClientWithMockSavedObjectsClient = async ({ - savedObjectsClient, - badAuth = false, - omitFromContext = [], -}: { - savedObjectsClient: any; - badAuth?: boolean; - omitFromContext?: string[]; -}): Promise<{ - client: CasesClient; - services: { - userActionService: jest.Mocked; - alertsService: jest.Mocked; +import { SubCasesClient } from './sub_cases/client'; +import { UserActionsSubClient } from './user_actions/client'; + +type CasesSubClientMock = jest.Mocked; + +const createCasesSubClientMock = (): CasesSubClientMock => { + return { + create: jest.fn(), + find: jest.fn(), + get: jest.fn(), + push: jest.fn(), + update: jest.fn(), }; - esClient: DeeplyMockedKeys; -}> => { - const esClient = elasticsearchServiceMock.createElasticsearchClient(); - const log = loggingSystemMock.create().get('case'); - - const auth = badAuth ? authenticationMock.createInvalid() : authenticationMock.create(); - const caseService = new CaseService(log, auth); - const caseConfigureServicePlugin = new CaseConfigureService(log); - const connectorMappingsServicePlugin = new ConnectorMappingsService(log); - - const caseConfigureService = await caseConfigureServicePlugin.setup(); - - const connectorMappingsService = await connectorMappingsServicePlugin.setup(); - const userActionService = { - getUserActions: jest.fn(), - postUserActions: jest.fn(), +}; + +type AttachmentsSubClientMock = jest.Mocked; + +const createAttachmentsSubClientMock = (): AttachmentsSubClientMock => { + return { + add: jest.fn(), }; +}; - const alertsService = { - initialize: jest.fn(), - updateAlertsStatus: jest.fn(), - getAlerts: jest.fn(), +type UserActionsSubClientMock = jest.Mocked; + +const createUserActionsSubClientMock = (): UserActionsSubClientMock => { + return { + getAll: jest.fn(), }; +}; - // since the cases saved objects are hidden we need to use getScopedClient(), we'll just have it return the mock client - // that is passed in to createRouteContext - const savedObjectsService = savedObjectsServiceMock.createStartContract(); - savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); - - // create a fake feature - const featureStart = featuresPluginMock.createStart(); - featureStart.getKibanaFeatures.mockReturnValue([ - // all the authorization class cares about is the `cases` field in the kibana feature so just cast it to that - ({ cases: ['securitySolution'] } as unknown) as KibanaFeature, - ]); - - const factory = new CasesClientFactory(log); - factory.initialize({ - alertsService, - caseConfigureService, - caseService, - connectorMappingsService, - userActionService, - featuresPluginStart: featureStart, - getSpace: async (req: KibanaRequest) => undefined, - // intentionally not passing the security plugin so that security will be disabled - }); - - // create a single reference to the caseClient so we can mock its methods - const casesClient = await factory.create({ - savedObjectsService, - // Since authorization is disabled for these unit tests we don't need any information from the request object - // so just pass in an empty one - request: {} as KibanaRequest, - scopedClusterClient: esClient, - }); +type SubCasesClientMock = jest.Mocked; +const createSubCasesClientMock = (): SubCasesClientMock => { return { - client: casesClient, - services: { userActionService, alertsService }, - esClient, + delete: jest.fn(), + find: jest.fn(), + get: jest.fn(), + update: jest.fn(), + }; +}; + +type CasesClientInternalMock = jest.Mocked; + +export interface CasesClientMock extends CasesClient { + cases: CasesSubClientMock; + attachments: AttachmentsSubClientMock; + userActions: UserActionsSubClientMock; + subCases: SubCasesClientMock; +} + +export const createCasesClientMock = (): CasesClientMock => { + const client: PublicContract = { + casesClientInternal: (jest.fn() as unknown) as CasesClientInternalMock, + cases: createCasesSubClientMock(), + attachments: createAttachmentsSubClientMock(), + userActions: createUserActionsSubClientMock(), + subCases: createSubCasesClientMock(), }; + return (client as unknown) as CasesClientMock; +}; + +export type CasesClientFactoryMock = jest.Mocked; + +export const createCasesClientFactory = (): CasesClientFactoryMock => { + const factory: PublicMethodsOf = { + initialize: jest.fn(), + create: jest.fn(), + }; + + return (factory as unknown) as CasesClientFactoryMock; }; diff --git a/x-pack/plugins/cases/server/connectors/case/index.test.ts b/x-pack/plugins/cases/server/connectors/case/index.test.ts index edf7e3d3fdbf1..876b8909b9317 100644 --- a/x-pack/plugins/cases/server/connectors/case/index.test.ts +++ b/x-pack/plugins/cases/server/connectors/case/index.test.ts @@ -6,7 +6,7 @@ */ import { omit } from 'lodash/fp'; -import { KibanaRequest, Logger } from '../../../../../../src/core/server'; +import { Logger } from '../../../../../../src/core/server'; import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; import { actionsMock } from '../../../../actions/server/mocks'; import { validateParams } from '../../../../actions/server/lib'; @@ -19,52 +19,28 @@ import { CaseResponse, CasesResponse, } from '../../../common/api'; -import { - connectorMappingsServiceMock, - createCaseServiceMock, - createConfigureServiceMock, - createUserActionServiceMock, - createAlertServiceMock, -} from '../../services/mocks'; import { CaseActionType, CaseActionTypeExecutorOptions, CaseExecutorParams } from './types'; import { getActionType } from '.'; -import { createExternalCasesClientMock } from '../../client/mocks'; -import { CasesClientFactory } from '../../client/factory'; -import { featuresPluginMock } from '../../../../features/server/mocks'; -import { securityMock } from '../../../../security/server/mocks'; - -const mockCasesClient = createExternalCasesClientMock(); -jest.mock('../../client', () => ({ - createExternalCasesClient: () => mockCasesClient, -})); +import { + CasesClientMock, + createCasesClientFactory, + createCasesClientMock, +} from '../../client/mocks'; const services = actionsMock.createServices(); let caseActionType: CaseActionType; describe('case connector', () => { + let mockCasesClient: CasesClientMock; + beforeEach(() => { - jest.resetAllMocks(); const logger = loggingSystemMock.create().get() as jest.Mocked; - const caseService = createCaseServiceMock(); - const caseConfigureService = createConfigureServiceMock(); - const connectorMappingsService = connectorMappingsServiceMock(); - const userActionService = createUserActionServiceMock(); - const alertsService = createAlertServiceMock(); - const factory = new CasesClientFactory(logger); - - factory.initialize({ - alertsService, - caseConfigureService, - caseService, - connectorMappingsService, - userActionService, - featuresPluginStart: featuresPluginMock.createStart(), - getSpace: async (req: KibanaRequest) => undefined, - securityPluginSetup: securityMock.createSetup(), - securityPluginStart: securityMock.createStart(), - }); + mockCasesClient = createCasesClientMock(); + + const factory = createCasesClientFactory(); + factory.create.mockReturnValue(Promise.resolve(mockCasesClient)); caseActionType = getActionType({ logger, factory, @@ -983,7 +959,7 @@ describe('case connector', () => { owner: 'securitySolution', }; - mockCasesClient.create.mockReturnValue(Promise.resolve(createReturn)); + mockCasesClient.cases.create.mockReturnValue(Promise.resolve(createReturn)); const actionId = 'some-id'; const params: CaseExecutorParams = { @@ -1019,7 +995,7 @@ describe('case connector', () => { const result = await caseActionType.executor(executorOptions); expect(result).toEqual({ actionId, status: 'ok', data: createReturn }); - expect(mockCasesClient.create).toHaveBeenCalledWith({ + expect(mockCasesClient.cases.create).toHaveBeenCalledWith({ ...params.subActionParams, connector: { id: 'jira', @@ -1081,7 +1057,7 @@ describe('case connector', () => { }, ]; - mockCasesClient.update.mockReturnValue(Promise.resolve(updateReturn)); + mockCasesClient.cases.update.mockReturnValue(Promise.resolve(updateReturn)); const actionId = 'some-id'; const params: CaseExecutorParams = { @@ -1109,7 +1085,7 @@ describe('case connector', () => { const result = await caseActionType.executor(executorOptions); expect(result).toEqual({ actionId, status: 'ok', data: updateReturn }); - expect(mockCasesClient.update).toHaveBeenCalledWith({ + expect(mockCasesClient.cases.update).toHaveBeenCalledWith({ // Null values have been striped out. cases: [ { @@ -1171,7 +1147,7 @@ describe('case connector', () => { owner: 'securitySolution', }; - mockCasesClient.addComment.mockReturnValue(Promise.resolve(commentReturn)); + mockCasesClient.attachments.add.mockReturnValue(Promise.resolve(commentReturn)); const actionId = 'some-id'; const params: CaseExecutorParams = { @@ -1196,7 +1172,7 @@ describe('case connector', () => { const result = await caseActionType.executor(executorOptions); expect(result).toEqual({ actionId, status: 'ok', data: commentReturn }); - expect(mockCasesClient.addComment).toHaveBeenCalledWith({ + expect(mockCasesClient.attachments.add).toHaveBeenCalledWith({ caseId: 'case-id', comment: { comment: 'a comment', diff --git a/x-pack/plugins/cases/server/services/mocks.ts b/x-pack/plugins/cases/server/services/mocks.ts index 77129e45348b1..5e5b4ff31309e 100644 --- a/x-pack/plugins/cases/server/services/mocks.ts +++ b/x-pack/plugins/cases/server/services/mocks.ts @@ -5,12 +5,14 @@ * 2.0. */ +import { PublicMethodsOf } from '@kbn/utility-types'; import { AlertServiceContract, CaseConfigureService, CaseService, CaseUserActionService, ConnectorMappingsService, + AttachmentService, } from '.'; export type CaseServiceMock = jest.Mocked; @@ -18,61 +20,87 @@ export type CaseConfigureServiceMock = jest.Mocked; export type ConnectorMappingsServiceMock = jest.Mocked; export type CaseUserActionServiceMock = jest.Mocked; export type AlertServiceMock = jest.Mocked; +export type AttachmentServiceMock = jest.Mocked; -export const createCaseServiceMock = (): CaseServiceMock => ({ - createSubCase: jest.fn(), - deleteCase: jest.fn(), - deleteComment: jest.fn(), - deleteSubCase: jest.fn(), - findCases: jest.fn(), - findSubCases: jest.fn(), - findSubCasesByCaseId: jest.fn(), - getAllCaseComments: jest.fn(), - getAllSubCaseComments: jest.fn(), - getCase: jest.fn(), - getCases: jest.fn(), - getComment: jest.fn(), - getMostRecentSubCase: jest.fn(), - getSubCase: jest.fn(), - getSubCases: jest.fn(), - getTags: jest.fn(), - getReporters: jest.fn(), - getUser: jest.fn(), - postNewCase: jest.fn(), - postNewComment: jest.fn(), - patchCase: jest.fn(), - patchCases: jest.fn(), - patchComment: jest.fn(), - patchComments: jest.fn(), - patchSubCase: jest.fn(), - patchSubCases: jest.fn(), - findSubCaseStatusStats: jest.fn(), - getCommentsByAssociation: jest.fn(), - getCaseCommentStats: jest.fn(), - findSubCasesGroupByCase: jest.fn(), - findCaseStatusStats: jest.fn(), - findCasesGroupedByID: jest.fn(), -}); +export const createCaseServiceMock = (): CaseServiceMock => { + const service: PublicMethodsOf = { + createSubCase: jest.fn(), + deleteCase: jest.fn(), + deleteSubCase: jest.fn(), + findCases: jest.fn(), + findSubCases: jest.fn(), + findSubCasesByCaseId: jest.fn(), + getAllCaseComments: jest.fn(), + getAllSubCaseComments: jest.fn(), + getCase: jest.fn(), + getCases: jest.fn(), + getMostRecentSubCase: jest.fn(), + getSubCase: jest.fn(), + getSubCases: jest.fn(), + getTags: jest.fn(), + getReporters: jest.fn(), + getUser: jest.fn(), + postNewCase: jest.fn(), + patchCase: jest.fn(), + patchCases: jest.fn(), + patchSubCase: jest.fn(), + patchSubCases: jest.fn(), + findSubCaseStatusStats: jest.fn(), + getCommentsByAssociation: jest.fn(), + getCaseCommentStats: jest.fn(), + findSubCasesGroupByCase: jest.fn(), + findCaseStatusStats: jest.fn(), + findCasesGroupedByID: jest.fn(), + }; -export const createConfigureServiceMock = (): CaseConfigureServiceMock => ({ - delete: jest.fn(), - get: jest.fn(), - find: jest.fn(), - patch: jest.fn(), - post: jest.fn(), -}); + // the cast here is required because jest.Mocked tries to include private members and would throw an error + return (service as unknown) as CaseServiceMock; +}; -export const connectorMappingsServiceMock = (): ConnectorMappingsServiceMock => ({ - find: jest.fn(), - post: jest.fn(), -}); +export const createConfigureServiceMock = (): CaseConfigureServiceMock => { + const service: PublicMethodsOf = { + delete: jest.fn(), + get: jest.fn(), + find: jest.fn(), + patch: jest.fn(), + post: jest.fn(), + }; -export const createUserActionServiceMock = (): CaseUserActionServiceMock => ({ - getUserActions: jest.fn(), - postUserActions: jest.fn(), -}); + // the cast here is required because jest.Mocked tries to include private members and would throw an error + return (service as unknown) as CaseConfigureServiceMock; +}; + +export const connectorMappingsServiceMock = (): ConnectorMappingsServiceMock => { + const service: PublicMethodsOf = { find: jest.fn(), post: jest.fn() }; + + // the cast here is required because jest.Mocked tries to include private members and would throw an error + return (service as unknown) as ConnectorMappingsServiceMock; +}; + +export const createUserActionServiceMock = (): CaseUserActionServiceMock => { + const service: PublicMethodsOf = { + getAll: jest.fn(), + bulkCreate: jest.fn(), + }; + + // the cast here is required because jest.Mocked tries to include private members and would throw an error + return (service as unknown) as CaseUserActionServiceMock; +}; export const createAlertServiceMock = (): AlertServiceMock => ({ updateAlertsStatus: jest.fn(), getAlerts: jest.fn(), }); + +export const createAttachmentServiceMock = (): AttachmentServiceMock => { + const service: PublicMethodsOf = { + get: jest.fn(), + delete: jest.fn(), + create: jest.fn(), + update: jest.fn(), + bulkUpdate: jest.fn(), + }; + + // the cast here is required because jest.Mocked tries to include private members and would throw an error + return (service as unknown) as AttachmentServiceMock; +}; From be2897f6a45a885579866ed91e86184be857a1e7 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Tue, 13 Apr 2021 16:24:01 -0400 Subject: [PATCH 2/2] fixing types and removing unneeded functions --- .../__fixtures__/create_mock_so_repository.ts | 305 ------------------ .../server/routes/api/__fixtures__/index.ts | 4 - .../api/__fixtures__/mock_actions_client.ts | 34 -- .../routes/api/__fixtures__/mock_router.ts | 42 --- .../routes/api/__fixtures__/route_contexts.ts | 95 ------ .../routes/api/__mocks__/request_responses.ts | 140 +------- 6 files changed, 1 insertion(+), 619 deletions(-) delete mode 100644 x-pack/plugins/cases/server/routes/api/__fixtures__/create_mock_so_repository.ts delete mode 100644 x-pack/plugins/cases/server/routes/api/__fixtures__/mock_actions_client.ts delete mode 100644 x-pack/plugins/cases/server/routes/api/__fixtures__/mock_router.ts delete mode 100644 x-pack/plugins/cases/server/routes/api/__fixtures__/route_contexts.ts diff --git a/x-pack/plugins/cases/server/routes/api/__fixtures__/create_mock_so_repository.ts b/x-pack/plugins/cases/server/routes/api/__fixtures__/create_mock_so_repository.ts deleted file mode 100644 index a6acd917e4eea..0000000000000 --- a/x-pack/plugins/cases/server/routes/api/__fixtures__/create_mock_so_repository.ts +++ /dev/null @@ -1,305 +0,0 @@ -/* - * 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 { - SavedObjectsClientContract, - SavedObjectsErrorHelpers, - SavedObjectsBulkGetObject, - SavedObjectsBulkUpdateObject, - SavedObjectsFindOptions, -} from 'src/core/server'; - -import { - CASE_COMMENT_SAVED_OBJECT, - CASE_SAVED_OBJECT, - CASE_CONFIGURE_SAVED_OBJECT, - CASE_CONNECTOR_MAPPINGS_SAVED_OBJECT, - SUB_CASE_SAVED_OBJECT, - CASE_USER_ACTION_SAVED_OBJECT, -} from '../../../../common/constants'; - -export const createMockSavedObjectsRepository = ({ - caseSavedObject = [], - caseCommentSavedObject = [], - caseConfigureSavedObject = [], - caseMappingsSavedObject = [], - caseUserActionsSavedObject = [], -}: { - caseSavedObject?: any[]; - caseCommentSavedObject?: any[]; - caseConfigureSavedObject?: any[]; - caseMappingsSavedObject?: any[]; - caseUserActionsSavedObject?: any[]; -} = {}) => { - const mockSavedObjectsClientContract = ({ - bulkGet: jest.fn((objects: SavedObjectsBulkGetObject[]) => { - return { - saved_objects: objects.map(({ id, type }) => { - if (type === CASE_COMMENT_SAVED_OBJECT) { - const result = caseCommentSavedObject.filter((s) => s.id === id); - if (!result.length) { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); - } - return result; - } - const result = caseSavedObject.filter((s) => s.id === id); - if (!result.length) { - return { - id, - type, - error: { - statusCode: 404, - error: 'Not Found', - message: 'Saved object [cases/not-exist] not found', - }, - }; - } - return result[0]; - }), - }; - }), - bulkCreate: jest.fn(), - bulkUpdate: jest.fn((objects: Array>) => { - return { - saved_objects: objects.map(({ id, type, attributes }) => { - if (type === CASE_COMMENT_SAVED_OBJECT) { - if (!caseCommentSavedObject.find((s) => s.id === id)) { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); - } - } else if (type === CASE_SAVED_OBJECT) { - if (!caseSavedObject.find((s) => s.id === id)) { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); - } - } - - return { - id, - type, - updated_at: '2019-11-22T22:50:55.191Z', - version: 'WzE3LDFd', - attributes, - }; - }), - }; - }), - get: jest.fn((type, id) => { - if (type === CASE_COMMENT_SAVED_OBJECT) { - const result = caseCommentSavedObject.filter((s) => s.id === id); - if (!result.length) { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); - } - return result[0]; - } else if (type === CASE_SAVED_OBJECT) { - const result = caseSavedObject.filter((s) => s.id === id); - if (!result.length) { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); - } - return result[0]; - } else { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); - } - }), - find: jest.fn((findArgs: SavedObjectsFindOptions) => { - // References can be an array so we need to loop through it looking for the bad-guy - const hasReferenceIncludeBadGuy = (args: SavedObjectsFindOptions) => { - const references = args.hasReference; - if (references) { - return Array.isArray(references) - ? references.some((ref) => ref.id === 'bad-guy') - : references.id === 'bad-guy'; - } else { - return false; - } - }; - if (hasReferenceIncludeBadGuy(findArgs)) { - throw SavedObjectsErrorHelpers.createBadRequestError('Error thrown for testing'); - } - - if ( - (findArgs.type === CASE_CONFIGURE_SAVED_OBJECT && - caseConfigureSavedObject[0] && - caseConfigureSavedObject[0].id === 'throw-error-find') || - (findArgs.type === CASE_SAVED_OBJECT && - caseSavedObject[0] && - caseSavedObject[0].id === 'throw-error-find') - ) { - throw SavedObjectsErrorHelpers.createGenericNotFoundError('Error thrown for testing'); - } - if (findArgs.type === CASE_CONNECTOR_MAPPINGS_SAVED_OBJECT && caseMappingsSavedObject[0]) { - return { - page: 1, - per_page: 5, - total: 1, - saved_objects: caseMappingsSavedObject, - }; - } - - if (findArgs.type === CASE_CONFIGURE_SAVED_OBJECT) { - return { - page: 1, - per_page: 5, - total: caseConfigureSavedObject.length, - saved_objects: caseConfigureSavedObject, - }; - } - - if (findArgs.type === CASE_COMMENT_SAVED_OBJECT) { - return { - page: 1, - per_page: 5, - total: caseCommentSavedObject.length, - saved_objects: caseCommentSavedObject, - }; - } - - // Currently not supporting sub cases in this mock library - if (findArgs.type === SUB_CASE_SAVED_OBJECT) { - return { - page: 1, - per_page: 0, - total: 0, - saved_objects: [], - }; - } - - if (findArgs.type === CASE_USER_ACTION_SAVED_OBJECT) { - return { - page: 1, - per_page: 5, - total: caseUserActionsSavedObject.length, - saved_objects: caseUserActionsSavedObject, - }; - } - - return { - page: 1, - per_page: 5, - total: caseSavedObject.length, - saved_objects: caseSavedObject, - }; - }), - create: jest.fn((type, attributes, references) => { - if (attributes.description === 'Throw an error' || attributes.comment === 'Throw an error') { - throw SavedObjectsErrorHelpers.createBadRequestError('Error thrown for testing'); - } - - if ( - type === CASE_CONFIGURE_SAVED_OBJECT && - attributes.connector.id === 'throw-error-create' - ) { - throw SavedObjectsErrorHelpers.createBadRequestError('Error thrown for testing'); - } - - if (type === CASE_COMMENT_SAVED_OBJECT) { - const newCommentObj = { - type, - id: 'mock-comment', - attributes, - ...references, - updated_at: '2019-12-02T22:48:08.327Z', - version: 'WzksMV0=', - }; - caseCommentSavedObject = [...caseCommentSavedObject, newCommentObj]; - return newCommentObj; - } - - if (type === CASE_CONFIGURE_SAVED_OBJECT) { - const newConfiguration = { - type, - id: 'mock-configuration', - attributes, - updated_at: '2020-04-09T09:43:51.778Z', - version: attributes.connector.id === 'no-version' ? undefined : 'WzksMV0=', - }; - - caseConfigureSavedObject = [newConfiguration]; - return newConfiguration; - } - - return { - type, - id: 'mock-it', - attributes, - references: [], - updated_at: '2019-12-02T22:48:08.327Z', - version: 'WzksMV0=', - }; - }), - update: jest.fn((type, id, attributes) => { - if (type === CASE_COMMENT_SAVED_OBJECT) { - const foundComment = caseCommentSavedObject.findIndex((s: { id: string }) => s.id === id); - if (foundComment === -1) { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); - } - const comment = caseCommentSavedObject[foundComment]; - caseCommentSavedObject.splice(foundComment, 1, { - ...comment, - id, - type, - updated_at: '2019-11-22T22:50:55.191Z', - version: 'WzE3LDFd', - attributes: { - ...comment.attributes, - ...attributes, - }, - }); - } else if (type === CASE_SAVED_OBJECT) { - if (!caseSavedObject.find((s) => s.id === id)) { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); - } - } - - if (type === CASE_CONFIGURE_SAVED_OBJECT) { - return { - id, - type, - updated_at: '2019-11-22T22:50:55.191Z', - attributes, - version: attributes.connector?.id === 'no-version' ? undefined : 'WzE3LDFd', - }; - } - - return { - id, - type, - updated_at: '2019-11-22T22:50:55.191Z', - version: 'WzE3LDFd', - attributes, - }; - }), - delete: jest.fn((type: string, id: string) => { - let result = caseSavedObject.filter((s) => s.id === id); - - if (type === CASE_COMMENT_SAVED_OBJECT) { - result = caseCommentSavedObject.filter((s) => s.id === id); - } - - if (type === CASE_CONFIGURE_SAVED_OBJECT) { - result = caseConfigureSavedObject.filter((s) => s.id === id); - } - - if (type === CASE_COMMENT_SAVED_OBJECT && id === 'bad-guy') { - throw SavedObjectsErrorHelpers.createBadRequestError('Error thrown for testing'); - } - - if (!result.length) { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); - } - - if ( - type === CASE_CONFIGURE_SAVED_OBJECT && - caseConfigureSavedObject[0].id === 'throw-error-delete' - ) { - throw new Error('Error thrown for testing'); - } - return {}; - }), - deleteByNamespace: jest.fn(), - } as unknown) as jest.Mocked; - - return mockSavedObjectsClientContract; -}; diff --git a/x-pack/plugins/cases/server/routes/api/__fixtures__/index.ts b/x-pack/plugins/cases/server/routes/api/__fixtures__/index.ts index 1abd44aec1552..25f9b05471a0d 100644 --- a/x-pack/plugins/cases/server/routes/api/__fixtures__/index.ts +++ b/x-pack/plugins/cases/server/routes/api/__fixtures__/index.ts @@ -6,8 +6,4 @@ */ export * from './mock_saved_objects'; -export { createMockSavedObjectsRepository } from './create_mock_so_repository'; -export { createRouteContext } from './route_contexts'; export { authenticationMock } from './authc_mock'; -export { createRoute } from './mock_router'; -export { createActionsClient } from './mock_actions_client'; diff --git a/x-pack/plugins/cases/server/routes/api/__fixtures__/mock_actions_client.ts b/x-pack/plugins/cases/server/routes/api/__fixtures__/mock_actions_client.ts deleted file mode 100644 index d153c328cbb91..0000000000000 --- a/x-pack/plugins/cases/server/routes/api/__fixtures__/mock_actions_client.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 { SavedObjectsErrorHelpers } from 'src/core/server'; -import { actionsClientMock } from '../../../../../actions/server/mocks'; -import { - getActions, - getActionTypes, - getActionExecuteResults, -} from '../__mocks__/request_responses'; - -export const createActionsClient = () => { - const actionsMock = actionsClientMock.create(); - actionsMock.getAll.mockImplementation(() => Promise.resolve(getActions())); - actionsMock.listTypes.mockImplementation(() => Promise.resolve(getActionTypes())); - actionsMock.get.mockImplementation(({ id }) => { - const actions = getActions(); - const action = actions.find((a) => a.id === id); - if (action) { - return Promise.resolve(action); - } else { - return Promise.reject(SavedObjectsErrorHelpers.createGenericNotFoundError('action', id)); - } - }); - actionsMock.execute.mockImplementation(({ actionId }) => - Promise.resolve(getActionExecuteResults(actionId)) - ); - - return actionsMock; -}; diff --git a/x-pack/plugins/cases/server/routes/api/__fixtures__/mock_router.ts b/x-pack/plugins/cases/server/routes/api/__fixtures__/mock_router.ts deleted file mode 100644 index 18cce1b087e5d..0000000000000 --- a/x-pack/plugins/cases/server/routes/api/__fixtures__/mock_router.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 { loggingSystemMock, httpServiceMock } from '../../../../../../../src/core/server/mocks'; -import { CaseService, CaseConfigureService, ConnectorMappingsService } from '../../../services'; -import { authenticationMock } from '../__fixtures__'; -import { RouteDeps } from '../types'; - -export const createRoute = async ( - api: (deps: RouteDeps) => void, - method: 'get' | 'post' | 'delete' | 'patch', - badAuth = false -) => { - const httpService = httpServiceMock.createSetupContract(); - const router = httpService.createRouter(); - - const log = loggingSystemMock.create().get('cases'); - const auth = badAuth ? authenticationMock.createInvalid() : authenticationMock.create(); - const caseService = new CaseService(log, auth); - const caseConfigureServicePlugin = new CaseConfigureService(log); - const connectorMappingsServicePlugin = new ConnectorMappingsService(log); - const caseConfigureService = await caseConfigureServicePlugin.setup(); - const connectorMappingsService = await connectorMappingsServicePlugin.setup(); - - api({ - caseConfigureService, - caseService, - connectorMappingsService, - router, - userActionService: { - postUserActions: jest.fn(), - getUserActions: jest.fn(), - }, - logger: log, - }); - - return router[method].mock.calls[0][1]; -}; diff --git a/x-pack/plugins/cases/server/routes/api/__fixtures__/route_contexts.ts b/x-pack/plugins/cases/server/routes/api/__fixtures__/route_contexts.ts deleted file mode 100644 index 284b01ce99325..0000000000000 --- a/x-pack/plugins/cases/server/routes/api/__fixtures__/route_contexts.ts +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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 { - elasticsearchServiceMock, - loggingSystemMock, - savedObjectsServiceMock, -} from 'src/core/server/mocks'; - -import { KibanaRequest } from 'kibana/server'; -import { - AlertService, - CaseService, - CaseConfigureService, - ConnectorMappingsService, - CaseUserActionService, -} from '../../../services'; -import { authenticationMock } from '../__fixtures__'; -import { createActionsClient } from './mock_actions_client'; -import { featuresPluginMock } from '../../../../../features/server/mocks'; -import { CasesClientFactory } from '../../../client/factory'; -import { xpackMocks } from '../../../../../../mocks'; -import { KibanaFeature } from '../../../../../features/common'; - -export const createRouteContext = async (client: any, badAuth = false) => { - const actionsMock = createActionsClient(); - - const log = loggingSystemMock.create().get('case'); - const esClient = elasticsearchServiceMock.createElasticsearchClient(); - - const authc = badAuth ? authenticationMock.createInvalid() : authenticationMock.create(); - - const caseService = new CaseService(log, authc); - const caseConfigureServicePlugin = new CaseConfigureService(log); - const connectorMappingsServicePlugin = new ConnectorMappingsService(log); - const caseUserActionsServicePlugin = new CaseUserActionService(log); - - const connectorMappingsService = await connectorMappingsServicePlugin.setup(); - const caseConfigureService = await caseConfigureServicePlugin.setup(); - const userActionService = await caseUserActionsServicePlugin.setup(); - const alertsService = new AlertService(); - - // since the cases saved objects are hidden we need to use getScopedClient(), we'll just have it return the mock client - // that is passed in to createRouteContext - const savedObjectsService = savedObjectsServiceMock.createStartContract(); - savedObjectsService.getScopedClient.mockReturnValue(client); - - const contextMock = xpackMocks.createRequestHandlerContext(); - // The tests check the calls on the saved object soClient, so we need to make sure it is the same one returned by - // getScopedClient and .client - contextMock.core.savedObjects.getClient = jest.fn(() => client); - contextMock.core.savedObjects.client = client; - - // create a fake feature - const featureStart = featuresPluginMock.createStart(); - featureStart.getKibanaFeatures.mockReturnValue([ - // all the authorization class cares about is the `cases` field in the kibana feature so just cast it to that - ({ cases: ['securitySolution'] } as unknown) as KibanaFeature, - ]); - - const factory = new CasesClientFactory(log); - factory.initialize({ - alertsService, - caseConfigureService, - caseService, - connectorMappingsService, - userActionService, - featuresPluginStart: featureStart, - getSpace: async (req: KibanaRequest) => undefined, - // intentionally not passing the security plugin so that security will be disabled - }); - - // create a single reference to the caseClient so we can mock its methods - const caseClient = await factory.create({ - savedObjectsService, - // Since authorization is disabled for these unit tests we don't need any information from the request object - // so just pass in an empty one - request: {} as KibanaRequest, - scopedClusterClient: esClient, - }); - - const context = { - ...contextMock, - actions: { getActionsClient: () => actionsMock }, - cases: { - getCasesClient: async () => caseClient, - }, - }; - - return { context, services: { userActionService } }; -}; diff --git a/x-pack/plugins/cases/server/routes/api/__mocks__/request_responses.ts b/x-pack/plugins/cases/server/routes/api/__mocks__/request_responses.ts index 7419452f27c0a..32e42fea5c207 100644 --- a/x-pack/plugins/cases/server/routes/api/__mocks__/request_responses.ts +++ b/x-pack/plugins/cases/server/routes/api/__mocks__/request_responses.ts @@ -5,14 +5,7 @@ * 2.0. */ -import { - ActionTypeConnector, - CasePostRequest, - CasesConfigureRequest, - ConnectorTypes, -} from '../../../../common/api'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { FindActionResult } from '../../../../../actions/server/types'; +import { CasePostRequest, ConnectorTypes } from '../../../../common/api'; export const newCase: CasePostRequest = { title: 'My new case', @@ -29,134 +22,3 @@ export const newCase: CasePostRequest = { }, owner: 'securitySolution', }; - -export const getActions = (): FindActionResult[] => [ - { - id: 'e90075a5-c386-41e3-ae21-ba4e61510695', - actionTypeId: '.webhook', - name: 'Test', - config: { - method: 'post', - url: 'https://example.com', - headers: null, - }, - isPreconfigured: false, - referencedByCount: 0, - }, - { - id: '123', - actionTypeId: '.servicenow', - name: 'ServiceNow', - config: { - apiUrl: 'https://dev102283.service-now.com', - }, - isPreconfigured: false, - referencedByCount: 0, - }, - { - id: '456', - actionTypeId: '.jira', - name: 'Connector without isCaseOwned', - config: { - apiUrl: 'https://elastic.jira.com', - }, - isPreconfigured: false, - referencedByCount: 0, - }, - { - id: '789', - actionTypeId: '.resilient', - name: 'Connector without mapping', - config: { - apiUrl: 'https://elastic.resilient.com', - }, - isPreconfigured: false, - referencedByCount: 0, - }, - { - id: 'for-mock-case-id-3', - actionTypeId: '.jira', - name: 'For mock case id 3', - config: { - apiUrl: 'https://elastic.jira.com', - }, - isPreconfigured: false, - referencedByCount: 0, - }, -]; - -export const getActionTypes = (): ActionTypeConnector[] => [ - { - id: '.email', - name: 'Email', - minimumLicenseRequired: 'gold', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - }, - { - id: '.index', - name: 'Index', - minimumLicenseRequired: 'basic', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - }, - { - id: '.servicenow', - name: 'ServiceNow', - minimumLicenseRequired: 'platinum', - enabled: false, - enabledInConfig: true, - enabledInLicense: true, - }, - { - id: '.jira', - name: 'Jira', - minimumLicenseRequired: 'gold', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - }, - { - id: '.resilient', - name: 'IBM Resilient', - minimumLicenseRequired: 'platinum', - enabled: false, - enabledInConfig: true, - enabledInLicense: true, - }, -]; - -export const getActionExecuteResults = (actionId = '123') => ({ - status: 'ok' as const, - data: { - title: 'RJ2-200', - id: '10663', - pushedDate: '2020-12-17T00:32:40.738Z', - url: 'https://siem-kibana.atlassian.net/browse/RJ2-200', - comments: [], - }, - actionId, -}); - -export const newConfiguration: CasesConfigureRequest = { - connector: { - id: '456', - name: 'My connector 2', - type: ConnectorTypes.jira, - fields: null, - }, - closure_type: 'close-by-pushing', -}; - -export const executePushResponse = { - status: 'ok', - data: { - title: 'RJ2-200', - id: '10663', - pushedDate: '2020-12-17T00:32:40.738Z', - url: 'https://siem-kibana.atlassian.net/browse/RJ2-200', - comments: [], - }, -};