From d418f91f44711e452204ed9670c31c921265d3a9 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Fri, 30 Jul 2021 15:10:16 -0400 Subject: [PATCH] Adding migration utility tests and some clean up --- x-pack/plugins/cases/common/api/cases/case.ts | 4 - .../cases/server/client/configure/client.ts | 5 +- .../migrations/cases.test.ts | 122 ++++++++++++++---- .../saved_object_types/migrations/cases.ts | 4 +- .../migrations/utils.test.ts | 112 ++++++++++++++++ .../saved_object_types/migrations/utils.ts | 5 +- 6 files changed, 215 insertions(+), 37 deletions(-) create mode 100644 x-pack/plugins/cases/server/saved_object_types/migrations/utils.test.ts diff --git a/x-pack/plugins/cases/common/api/cases/case.ts b/x-pack/plugins/cases/common/api/cases/case.ts index f76af5e95604d..37a491cdad4c0 100644 --- a/x-pack/plugins/cases/common/api/cases/case.ts +++ b/x-pack/plugins/cases/common/api/cases/case.ts @@ -87,10 +87,6 @@ const CaseBasicRt = rt.type({ owner: rt.string, }); -/** - * The external service fields. Exporting here for use in the service transformation code so I can define - * a type without the connector_id field. - */ export const CaseExternalServiceBasicRt = rt.type({ connector_id: rt.union([rt.string, rt.null]), connector_name: rt.string, diff --git a/x-pack/plugins/cases/server/client/configure/client.ts b/x-pack/plugins/cases/server/client/configure/client.ts index 395c9f990a19e..0e1d9eb891305 100644 --- a/x-pack/plugins/cases/server/client/configure/client.ts +++ b/x-pack/plugins/cases/server/client/configure/client.ts @@ -284,7 +284,7 @@ async function update( let error = null; const updateDate = new Date().toISOString(); let mappings: ConnectorMappingsAttributes[] = []; - const { connector } = queryWithoutVersion; + const { connector, ...queryWithoutVersionAndConnector } = queryWithoutVersion; try { const resMappings = await casesClientInternal.configuration.getMappings({ @@ -318,7 +318,8 @@ async function update( unsecuredSavedObjectsClient, configurationId: configuration.id, updatedAttributes: { - ...queryWithoutVersion, + ...queryWithoutVersionAndConnector, + ...(connector && { connector }), updated_at: updateDate, updated_by: user, }, diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts index 495fb9747d00e..00d99025aa5ad 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts @@ -9,14 +9,12 @@ import { SavedObjectSanitizedDoc } from 'kibana/server'; import { CaseAttributes, CaseFullExternalService, - CaseStatuses, - CaseType, CASE_SAVED_OBJECT, ConnectorTypes, - SECURITY_SOLUTION_OWNER, + noneConnectorId, } from '../../../common'; import { getNoneCaseConnector } from '../../common'; -import { ESCaseConnectorWithId } from '../../services/test_utils'; +import { createExternalService, ESCaseConnectorWithId } from '../../services/test_utils'; import { caseConnectorIdMigration } from './cases'; // eslint-disable-next-line @typescript-eslint/naming-convention @@ -29,29 +27,6 @@ const create_7_14_0_case = ({ attributes: { connector, external_service: externalService, - closed_at: null, - closed_by: null, - created_at: '2019-11-25T21:54:48.952Z', - created_by: { - full_name: 'elastic', - email: 'testemail@elastic.co', - username: 'elastic', - }, - description: 'This is a brand new case of a bad meanie defacing data', - title: 'Super Bad Security Issue', - status: CaseStatuses.open, - tags: ['defacement'], - type: CaseType.individual, - updated_at: '2019-11-25T21:54:48.952Z', - updated_by: { - full_name: 'elastic', - email: 'testemail@elastic.co', - username: 'elastic', - }, - settings: { - syncAlerts: true, - }, - owner: SECURITY_SOLUTION_OWNER, }, }); @@ -138,6 +113,32 @@ describe('7.15.0 connector ID migration', () => { expect(migratedConnector.attributes).not.toHaveProperty('external_service'); }); + it('does not create a reference when the external_service.connector_id is none', () => { + const caseSavedObject = create_7_14_0_case({ + externalService: createExternalService({ connector_id: noneConnectorId }), + }); + + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; + + expect(migratedConnector.references.length).toBe(0); + expect(migratedConnector.attributes.external_service).toMatchInlineSnapshot(` + Object { + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + } + `); + }); + it('preserves the existing references when migrating', () => { const caseSavedObject = { ...create_7_14_0_case(), @@ -280,4 +281,71 @@ describe('7.15.0 connector ID migration', () => { } `); }); + + it('migrates both connector and external_service when provided', () => { + const caseSavedObject = create_7_14_0_case({ + externalService: { + connector_id: '100', + connector_name: '.jira', + external_id: '100', + external_title: 'awesome', + external_url: 'http://www.google.com', + pushed_at: '2019-11-25T21:54:48.952Z', + pushed_by: { + full_name: 'elastic', + email: 'testemail@elastic.co', + username: 'elastic', + }, + }, + connector: { + id: '123', + fields: null, + name: 'connector', + type: ConnectorTypes.jira, + }, + }); + + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; + + expect(migratedConnector.references.length).toBe(2); + expect(migratedConnector.attributes.external_service).not.toHaveProperty('connector_id'); + expect(migratedConnector.attributes.external_service).toMatchInlineSnapshot(` + Object { + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + } + `); + expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); + expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` + Object { + "fields": null, + "name": "connector", + "type": ".jira", + } + `); + expect(migratedConnector.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "123", + "name": "connectorId", + "type": "action", + }, + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ] + `); + }); }); diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts index 0122a47caeb3f..b3cd1f538dee8 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts @@ -15,7 +15,7 @@ import { } from '../../../../../../src/core/server'; import { ACTION_SAVED_OBJECT_TYPE } from '../../../../actions/server'; import { ESConnectorFields, pushConnectorIdReferenceName } from '../../services'; -import { ConnectorTypes, CaseType } from '../../../common'; +import { ConnectorTypes, CaseType, noneConnectorId } from '../../../common'; import { transformConnectorIdToReference } from './utils'; interface UnsanitizedCaseConnector { @@ -52,7 +52,7 @@ const transformPushConnectorIdToReference = ( const { connector_id: pushConnectorId, ...restExternalService } = external_service ?? {}; const references = - pushConnectorId && pushConnectorId !== 'none' + pushConnectorId && pushConnectorId !== noneConnectorId ? [ { id: pushConnectorId, diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/utils.test.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/utils.test.ts new file mode 100644 index 0000000000000..d1692e61e94bc --- /dev/null +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/utils.test.ts @@ -0,0 +1,112 @@ +/* + * 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 { noneConnectorId } from '../../../common'; +import { createJiraConnector } from '../../services/test_utils'; +import { transformConnectorIdToReference } from './utils'; + +describe('migration utils', () => { + describe('transformConnectorIdToReference', () => { + it('returns the default none connector when the connector is undefined', () => { + expect(transformConnectorIdToReference().transformedConnector).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": null, + "name": "none", + "type": ".none", + }, + } + `); + }); + + it('returns the default none connector when the id is undefined', () => { + expect(transformConnectorIdToReference({ id: undefined }).transformedConnector) + .toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": null, + "name": "none", + "type": ".none", + }, + } + `); + }); + + it('returns the default none connector when the id is none', () => { + expect(transformConnectorIdToReference({ id: noneConnectorId }).transformedConnector) + .toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": null, + "name": "none", + "type": ".none", + }, + } + `); + }); + + it('returns the default none connector when the id is none and other fields are defined', () => { + expect( + transformConnectorIdToReference({ ...createJiraConnector(), id: noneConnectorId }) + .transformedConnector + ).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": null, + "name": "none", + "type": ".none", + }, + } + `); + }); + + it('returns an empty array of references when the connector is undefined', () => { + expect(transformConnectorIdToReference().references.length).toBe(0); + }); + + it('returns an empty array of references when the id is undefined', () => { + expect(transformConnectorIdToReference({ id: undefined }).references.length).toBe(0); + }); + + it('returns an empty array of references when the id is the none connector', () => { + expect(transformConnectorIdToReference({ id: noneConnectorId }).references.length).toBe(0); + }); + + it('returns an empty array of references when the id is the none connector and other fields are defined', () => { + expect( + transformConnectorIdToReference({ ...createJiraConnector(), id: noneConnectorId }) + .references.length + ).toBe(0); + }); + + it('returns a jira connector', () => { + const transformedFields = transformConnectorIdToReference(createJiraConnector()); + expect(transformedFields.transformedConnector).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + }, + } + `); + expect(transformedFields.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + }); + }); +}); diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/utils.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/utils.ts index e3ba75fbf449a..ad10d86160a57 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/utils.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/utils.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { noneConnectorId } from '../../../common'; import { SavedObjectReference } from '../../../../../../src/core/server'; import { ACTION_SAVED_OBJECT_TYPE } from '../../../../actions/server'; import { getNoneCaseConnector } from '../../common'; @@ -16,7 +17,7 @@ export const transformConnectorIdToReference = (connector?: { const { id: connectorId, ...restConnector } = connector ?? {}; const references = - connectorId && connectorId !== 'none' + connectorId && connectorId !== noneConnectorId ? [ { id: connectorId, @@ -29,7 +30,7 @@ export const transformConnectorIdToReference = (connector?: { const { id: ignoreNoneId, ...restNoneConnector } = getNoneCaseConnector(); let transformedConnector: object = { connector: restNoneConnector }; - if (connector && connectorId) { + if (connector && connectorId && references.length > 0) { transformedConnector = { connector: { ...restConnector } }; }