From 662b306cd2c9671b793d3cda12dbb808526e0b1e Mon Sep 17 00:00:00 2001 From: Joe Portner Date: Mon, 10 Jan 2022 12:17:28 -0500 Subject: [PATCH] PR review feedback --- .../import/import_saved_objects.test.ts | 10 +- .../import/import_saved_objects.ts | 9 +- .../import/lib/validate_references.test.ts | 734 +++++------------- .../import/lib/validate_references.ts | 51 +- .../import/resolve_import_errors.test.ts | 20 +- .../import/resolve_import_errors.ts | 8 +- 6 files changed, 232 insertions(+), 600 deletions(-) diff --git a/src/core/server/saved_objects/import/import_saved_objects.test.ts b/src/core/server/saved_objects/import/import_saved_objects.test.ts index 63be39e3b6c17..2f31b4cf3ead3 100644 --- a/src/core/server/saved_objects/import/import_saved_objects.test.ts +++ b/src/core/server/saved_objects/import/import_saved_objects.test.ts @@ -176,16 +176,16 @@ describe('#importSavedObjectsFromStream', () => { }); await importSavedObjectsFromStream(options); - expect(mockValidateReferences).toHaveBeenCalledWith( - collectedObjects, + expect(mockValidateReferences).toHaveBeenCalledWith({ + objects: collectedObjects, savedObjectsClient, namespace, - new Map([ + importStateMap: new Map([ // This importStateMap is a combination of the other two [`${collectedObjects[0].type}:${collectedObjects[0].id}`, {}], [`foo:bar`, { isOnlyReference: true, id: 'baz' }], - ]) - ); + ]), + }); }); test('executes import hooks', async () => { diff --git a/src/core/server/saved_objects/import/import_saved_objects.ts b/src/core/server/saved_objects/import/import_saved_objects.ts index 43180524d6062..0631d97b58a72 100644 --- a/src/core/server/saved_objects/import/import_saved_objects.ts +++ b/src/core/server/saved_objects/import/import_saved_objects.ts @@ -88,12 +88,12 @@ export async function importSavedObjectsFromStream({ importStateMap = new Map([...importStateMap, ...checkReferenceOriginsResult.importStateMap]); // Validate references - const validateReferencesResult = await validateReferences( - collectSavedObjectsResult.collectedObjects, + const validateReferencesResult = await validateReferences({ + objects: collectSavedObjectsResult.collectedObjects, savedObjectsClient, namespace, - importStateMap - ); + importStateMap, + }); errorAccumulator = [...errorAccumulator, ...validateReferencesResult]; if (createNewCopies) { @@ -101,7 +101,6 @@ export async function importSavedObjectsFromStream({ ...importStateMap, // preserve any entries for references that aren't included in collectedObjects ...regenerateIds(collectSavedObjectsResult.collectedObjects), ]); - // TODO: check reference origins! } else { // Check single-namespace objects for conflicts in this namespace, and check multi-namespace objects for conflicts across all namespaces const checkConflictsParams = { diff --git a/src/core/server/saved_objects/import/lib/validate_references.test.ts b/src/core/server/saved_objects/import/lib/validate_references.test.ts index ca0269314c4bf..2e6f1a5e0a9a2 100644 --- a/src/core/server/saved_objects/import/lib/validate_references.test.ts +++ b/src/core/server/saved_objects/import/lib/validate_references.test.ts @@ -6,600 +6,251 @@ * Side Public License, v 1. */ -import { getNonExistingReferenceAsKeys, validateReferences } from './validate_references'; +import type { ValidateReferencesParams } from './validate_references'; +import { validateReferences } from './validate_references'; import { savedObjectsClientMock } from '../../../mocks'; import { SavedObjectsErrorHelpers } from '../../service'; -describe('getNonExistingReferenceAsKeys()', () => { +function setup({ + objects = [], + namespace, + importStateMap = new Map(), + retries, +}: Partial> = {}) { const savedObjectsClient = savedObjectsClientMock.create(); + return { objects, savedObjectsClient, namespace, importStateMap, retries }; +} - beforeEach(() => { - jest.resetAllMocks(); - }); - - test('returns empty response when no objects exist', async () => { - const result = await getNonExistingReferenceAsKeys( - [], - savedObjectsClient, - undefined, - new Map() - ); - expect(result).toEqual([]); - expect(savedObjectsClient.bulkGet).toHaveBeenCalledTimes(0); - }); - - test('skips objects when ignoreMissingReferences is included in retry', async () => { - const savedObjects = [ - { - id: '2', - type: 'visualization', - attributes: {}, - references: [{ name: 'ref_0', type: 'index-pattern', id: '1' }], - }, - ]; - const retries = [ - { - type: 'visualization', - id: '2', - overwrite: false, - replaceReferences: [], - ignoreMissingReferences: true, - }, - ]; - const result = await getNonExistingReferenceAsKeys( - savedObjects, - savedObjectsClient, - undefined, - new Map(), - retries - ); - expect(result).toEqual([]); - expect(savedObjectsClient.bulkGet).not.toHaveBeenCalled(); - }); +function createNotFoundError({ type, id }: { type: string; id: string }) { + const error = SavedObjectsErrorHelpers.createGenericNotFoundError(type, id).output.payload; + return { type, id, error, attributes: {}, references: [] }; +} - test('skips references when an importStateMap entry indicates that we have already found an origin match with a different ID', async () => { - const savedObjects = [ - { - id: '2', - type: 'visualization', - attributes: {}, - references: [{ name: 'ref_0', type: 'index-pattern', id: '1' }], - }, - ]; - const result = await getNonExistingReferenceAsKeys( - savedObjects, - savedObjectsClient, - undefined, - new Map([[`index-pattern:1`, { isOnlyReference: true, destinationId: 'not-1' }]]) - ); - expect(result).toEqual([]); - expect(savedObjectsClient.bulkGet).not.toHaveBeenCalled(); - }); +describe('validateReferences()', () => { + test('does not call cluster and returns empty when no objects are passed in', async () => { + const params = setup(); - test('removes references that exist within savedObjects', async () => { - const savedObjects = [ - { - id: '1', - type: 'index-pattern', - attributes: {}, - references: [], - }, - { - id: '2', - type: 'visualization', - attributes: {}, - references: [ - { - name: 'ref_0', - type: 'index-pattern', - id: '1', - }, - ], - }, - ]; - const result = await getNonExistingReferenceAsKeys( - savedObjects, - savedObjectsClient, - undefined, - new Map() - ); + const result = await validateReferences(params); expect(result).toEqual([]); - expect(savedObjectsClient.bulkGet).toHaveBeenCalledTimes(0); + expect(params.savedObjectsClient.bulkGet).not.toHaveBeenCalled(); }); - test('removes references that exist within es', async () => { - const savedObjects = [ - { - id: '2', - type: 'visualization', - attributes: {}, - references: [ - { - name: 'ref_0', - type: 'index-pattern', - id: '1', - }, - ], - }, - ]; - savedObjectsClient.bulkGet.mockResolvedValueOnce({ - saved_objects: [ + test('returns errors when references are missing', async () => { + const params = setup({ + objects: [ { id: '1', - type: 'index-pattern', + type: 'visualization', attributes: {}, references: [], }, + { + id: '2', + type: 'visualization', + attributes: { title: 'My Visualization 2' }, + references: [{ name: 'ref_0', type: 'index-pattern', id: '3' }], + }, + { + id: '4', + type: 'visualization', + attributes: {}, + references: [ + { name: 'ref_0', type: 'index-pattern', id: '5' }, + { name: 'ref_1', type: 'index-pattern', id: '6' }, + { name: 'ref_2', type: 'search', id: '7' }, + { name: 'ref_3', type: 'search', id: '8' }, + ], + }, + ], + }); + params.savedObjectsClient.bulkGet.mockResolvedValue({ + saved_objects: [ + createNotFoundError({ type: 'index-pattern', id: '3' }), + createNotFoundError({ type: 'index-pattern', id: '5' }), + createNotFoundError({ type: 'index-pattern', id: '6' }), + createNotFoundError({ type: 'search', id: '7' }), + { id: '8', type: 'search', attributes: {}, references: [] }, ], }); - const result = await getNonExistingReferenceAsKeys( - savedObjects, - savedObjectsClient, - undefined, - new Map() - ); - expect(result).toEqual([]); - expect(savedObjectsClient.bulkGet).toMatchInlineSnapshot(` - [MockFunction] { - "calls": Array [ - Array [ - Array [ - Object { - "fields": Array [ - "id", - ], - "id": "1", - "type": "index-pattern", - }, - ], - Object { - "namespace": undefined, - }, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - } - `); - }); - test(`doesn't handle saved object types outside of ENFORCED_TYPES`, async () => { - const savedObjects = [ - { + const result = await validateReferences(params); + expect(result).toEqual([ + expect.objectContaining({ + type: 'visualization', id: '2', + error: { + type: 'missing_references', + references: [{ type: 'index-pattern', id: '3' }], + }, + }), + expect.objectContaining({ type: 'visualization', - attributes: {}, - references: [ - { - name: 'ref_0', - type: 'foo', - id: '1', - }, - ], - }, - ]; - const result = await getNonExistingReferenceAsKeys( - savedObjects, - savedObjectsClient, - undefined, - new Map() + id: '4', + error: { + type: 'missing_references', + references: [ + { type: 'index-pattern', id: '5' }, + { type: 'index-pattern', id: '6' }, + { type: 'search', id: '7' }, + ], + }, + }), + ]); + expect(params.savedObjectsClient.bulkGet).toHaveBeenCalledTimes(1); + expect(params.savedObjectsClient.bulkGet).toHaveBeenCalledWith( + [ + { type: 'index-pattern', id: '3', fields: ['id'] }, + { type: 'index-pattern', id: '5', fields: ['id'] }, + { type: 'index-pattern', id: '6', fields: ['id'] }, + { type: 'search', id: '7', fields: ['id'] }, + { type: 'search', id: '8', fields: ['id'] }, + ], + { namespace: undefined } ); - expect(result).toEqual([]); - expect(savedObjectsClient.bulkGet).toHaveBeenCalledTimes(0); }); - test('returns references within ENFORCED_TYPES when they are missing', async () => { - const savedObjects = [ - { - id: '2', - type: 'visualization', - attributes: {}, - references: [ - { - name: 'ref_0', - type: 'index-pattern', - id: '1', - }, - { - name: 'ref_1', - type: 'search', - id: '3', - }, - { - name: 'ref_2', - type: 'foo', - id: '4', - }, - ], - }, - ]; - savedObjectsClient.bulkGet.mockResolvedValueOnce({ - saved_objects: [ + test(`skips checking references when ignoreMissingReferences is included in retry`, async () => { + const params = setup({ + objects: [ { - id: '1', - type: 'index-pattern', - error: SavedObjectsErrorHelpers.createGenericNotFoundError('index-pattern', '1').output - .payload, + id: '2', + type: 'visualization', attributes: {}, - references: [], + references: [{ name: 'ref_0', type: 'index-pattern', id: '1' }], }, + ], + retries: [ { - id: '3', - type: 'search', - error: SavedObjectsErrorHelpers.createGenericNotFoundError('search', '3').output.payload, - attributes: {}, - references: [], + type: 'visualization', + id: '2', + overwrite: false, + replaceReferences: [], + ignoreMissingReferences: true, }, ], }); - const result = await getNonExistingReferenceAsKeys( - savedObjects, - savedObjectsClient, - undefined, - new Map() - ); - expect(result).toEqual(['index-pattern:1', 'search:3']); - expect(savedObjectsClient.bulkGet).toMatchInlineSnapshot(` - [MockFunction] { - "calls": Array [ - Array [ - Array [ - Object { - "fields": Array [ - "id", - ], - "id": "1", - "type": "index-pattern", - }, - Object { - "fields": Array [ - "id", - ], - "id": "3", - "type": "search", - }, - ], - Object { - "namespace": undefined, - }, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - } - `); - }); -}); -describe('validateReferences()', () => { - const savedObjectsClient = savedObjectsClientMock.create(); - - beforeEach(() => { - jest.resetAllMocks(); - }); - - test('returns empty when no objects are passed in', async () => { - const result = await validateReferences([], savedObjectsClient, undefined, new Map()); + const result = await validateReferences(params); expect(result).toEqual([]); - expect(savedObjectsClient.bulkGet).toHaveBeenCalledTimes(0); + expect(params.savedObjectsClient.bulkGet).not.toHaveBeenCalled(); }); - test('returns errors when references are missing', async () => { - savedObjectsClient.bulkGet.mockResolvedValue({ - saved_objects: [ - { - type: 'index-pattern', - id: '3', - error: SavedObjectsErrorHelpers.createGenericNotFoundError('index-pattern', '3').output - .payload, - attributes: {}, - references: [], - }, + test(`doesn't return errors when references exist in Elasticsearch`, async () => { + const params = setup({ + objects: [ { - type: 'index-pattern', - id: '5', - error: SavedObjectsErrorHelpers.createGenericNotFoundError('index-pattern', '5').output - .payload, + id: '2', + type: 'visualization', attributes: {}, - references: [], + references: [{ name: 'ref_0', type: 'index-pattern', id: '1' }], }, + ], + }); + params.savedObjectsClient.bulkGet.mockResolvedValue({ + saved_objects: [{ id: '1', type: 'index-pattern', attributes: {}, references: [] }], + }); + + const result = await validateReferences(params); + expect(result).toEqual([]); + expect(params.savedObjectsClient.bulkGet).toHaveBeenCalledTimes(1); + expect(params.savedObjectsClient.bulkGet).toHaveBeenCalledWith( + [{ type: 'index-pattern', id: '1', fields: ['id'] }], + { namespace: undefined } + ); + }); + + test(`skips checking references that exist within the saved objects`, async () => { + const params = setup({ + objects: [ { + id: '1', type: 'index-pattern', - id: '6', - error: SavedObjectsErrorHelpers.createGenericNotFoundError('index-pattern', '6').output - .payload, - attributes: {}, - references: [], - }, - { - type: 'search', - id: '7', - error: SavedObjectsErrorHelpers.createGenericNotFoundError('search', '7').output.payload, attributes: {}, references: [], }, { - id: '8', - type: 'search', + id: '2', + type: 'visualization', attributes: {}, - references: [], + references: [{ name: 'ref_0', type: 'index-pattern', id: '1' }], }, ], }); - const savedObjects = [ - { - id: '1', - type: 'visualization', - attributes: {}, - references: [], - }, - { - id: '2', - type: 'visualization', - attributes: { - title: 'My Visualization 2', - }, - references: [ - { - name: 'ref_0', - type: 'index-pattern', - id: '3', - }, - ], - }, - { - id: '4', - type: 'visualization', - attributes: { - title: 'My Visualization 4', - }, - references: [ - { - name: 'ref_0', - type: 'index-pattern', - id: '5', - }, - { - name: 'ref_1', - type: 'index-pattern', - id: '6', - }, - { - name: 'ref_2', - type: 'search', - id: '7', - }, - { - name: 'ref_3', - type: 'search', - id: '8', - }, - ], - }, - ]; - const result = await validateReferences(savedObjects, savedObjectsClient, undefined, new Map()); - expect(result).toMatchInlineSnapshot(` - Array [ - Object { - "error": Object { - "references": Array [ - Object { - "id": "3", - "type": "index-pattern", - }, - ], - "type": "missing_references", - }, - "id": "2", - "meta": Object { - "title": "My Visualization 2", - }, - "title": "My Visualization 2", - "type": "visualization", - }, - Object { - "error": Object { - "references": Array [ - Object { - "id": "5", - "type": "index-pattern", - }, - Object { - "id": "6", - "type": "index-pattern", - }, - Object { - "id": "7", - "type": "search", - }, - ], - "type": "missing_references", - }, - "id": "4", - "meta": Object { - "title": "My Visualization 4", - }, - "title": "My Visualization 4", - "type": "visualization", - }, - ] - `); - expect(savedObjectsClient.bulkGet).toMatchInlineSnapshot(` - [MockFunction] { - "calls": Array [ - Array [ - Array [ - Object { - "fields": Array [ - "id", - ], - "id": "3", - "type": "index-pattern", - }, - Object { - "fields": Array [ - "id", - ], - "id": "5", - "type": "index-pattern", - }, - Object { - "fields": Array [ - "id", - ], - "id": "6", - "type": "index-pattern", - }, - Object { - "fields": Array [ - "id", - ], - "id": "7", - "type": "search", - }, - Object { - "fields": Array [ - "id", - ], - "id": "8", - "type": "search", - }, - ], - Object { - "namespace": undefined, - }, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - } - `); - }); - test(`doesn't return errors when ignoreMissingReferences is included in retry`, async () => { - const savedObjects = [ - { - id: '2', - type: 'visualization', - attributes: {}, - references: [{ name: 'ref_0', type: 'index-pattern', id: '1' }], - }, - ]; - const retries = [ - { - type: 'visualization', - id: '2', - overwrite: false, - replaceReferences: [], - ignoreMissingReferences: true, - }, - ]; - const result = await validateReferences( - savedObjects, - savedObjectsClient, - undefined, - new Map(), - retries - ); + const result = await validateReferences(params); + expect(result).toEqual([]); expect(result).toEqual([]); - expect(savedObjectsClient.bulkGet).not.toHaveBeenCalled(); + expect(params.savedObjectsClient.bulkGet).not.toHaveBeenCalled(); }); - test(`doesn't return errors when references exist in Elasticsearch`, async () => { - savedObjectsClient.bulkGet.mockResolvedValue({ - saved_objects: [ + test(`skips checking references that are not part of ENFORCED_TYPES`, async () => { + // this test case intentionally includes a mix of references that *will* be checked, and references that *won't* be checked + const params = setup({ + objects: [ { - id: '1', - type: 'index-pattern', + id: '2', + type: 'visualization', attributes: {}, - references: [], + references: [ + { name: 'ref_0', type: 'index-pattern', id: '1' }, + { name: 'ref_2', type: 'foo', id: '2' }, + { name: 'ref_1', type: 'search', id: '3' }, + ], }, ], }); - const savedObjects = [ - { - id: '2', - type: 'visualization', - attributes: {}, - references: [ - { - name: 'ref_0', - type: 'index-pattern', - id: '1', - }, - ], - }, - ]; - const result = await validateReferences(savedObjects, savedObjectsClient, undefined, new Map()); - expect(result).toEqual([]); - expect(savedObjectsClient.bulkGet).toHaveBeenCalledTimes(1); - }); + params.savedObjectsClient.bulkGet.mockResolvedValueOnce({ + saved_objects: [ + { type: 'index-pattern', id: '1', attributes: {}, references: [] }, + { type: 'search', id: '3', attributes: {}, references: [] }, + ], + }); - test(`doesn't return errors when references exist within the saved objects`, async () => { - const savedObjects = [ - { - id: '1', - type: 'index-pattern', - attributes: {}, - references: [], - }, - { - id: '2', - type: 'visualization', - attributes: {}, - references: [ - { - name: 'ref_0', - type: 'index-pattern', - id: '1', - }, - ], - }, - ]; - const result = await validateReferences(savedObjects, savedObjectsClient, undefined, new Map()); + const result = await validateReferences(params); expect(result).toEqual([]); - expect(savedObjectsClient.bulkGet).toHaveBeenCalledTimes(0); + expect(params.savedObjectsClient.bulkGet).toHaveBeenCalledTimes(1); + expect(params.savedObjectsClient.bulkGet).toHaveBeenCalledWith( + [ + { type: 'index-pattern', id: '1', fields: ['id'] }, + // foo:2 is not included in the cluster call + { type: 'search', id: '3', fields: ['id'] }, + ], + { namespace: undefined } + ); }); - test(`doesn't validate references on types not part of ENFORCED_TYPES`, async () => { - const savedObjects = [ - { - id: '1', - type: 'dashboard', - attributes: {}, - references: [ - { - name: 'ref_0', - type: 'visualization', - id: '2', - }, - { - name: 'ref_1', - type: 'other-type', - id: '3', - }, - ], - }, - ]; - const result = await validateReferences(savedObjects, savedObjectsClient, undefined, new Map()); + test('skips checking references when an importStateMap entry indicates that we have already found an origin match with a different ID', async () => { + const params = setup({ + objects: [ + { + id: '2', + type: 'visualization', + attributes: {}, + references: [{ name: 'ref_0', type: 'index-pattern', id: '1' }], + }, + ], + importStateMap: new Map([ + [`index-pattern:1`, { isOnlyReference: true, destinationId: 'not-1' }], + ]), + }); + + const result = await validateReferences(params); expect(result).toEqual([]); - expect(savedObjectsClient.bulkGet).toHaveBeenCalledTimes(0); + expect(params.savedObjectsClient.bulkGet).not.toHaveBeenCalled(); }); - test('throws when bulkGet fails', async () => { - savedObjectsClient.bulkGet.mockResolvedValue({ + test('throws when bulkGet encounters an unexpected error', async () => { + const params = setup({ + objects: [ + { + id: '2', + type: 'visualization', + attributes: {}, + references: [{ name: 'ref_0', type: 'index-pattern', id: '1' }], + }, + ], + }); + params.savedObjectsClient.bulkGet.mockResolvedValue({ saved_objects: [ { id: '1', @@ -610,24 +261,9 @@ describe('validateReferences()', () => { }, ], }); - const savedObjects = [ - { - id: '2', - type: 'visualization', - attributes: {}, - references: [ - { - name: 'ref_0', - type: 'index-pattern', - id: '1', - }, - ], - }, - ]; - await expect( - validateReferences(savedObjects, savedObjectsClient, undefined, new Map()) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Error fetching references for imported objects"` + + await expect(() => validateReferences(params)).rejects.toThrowError( + 'Error fetching references for imported objects' ); }); }); diff --git a/src/core/server/saved_objects/import/lib/validate_references.ts b/src/core/server/saved_objects/import/lib/validate_references.ts index b6c7ebecd1aa3..69e036cf77a3a 100644 --- a/src/core/server/saved_objects/import/lib/validate_references.ts +++ b/src/core/server/saved_objects/import/lib/validate_references.ts @@ -23,22 +23,30 @@ const getObjectsToSkip = (retries: SavedObjectsImportRetry[] = []) => new Set() ); -export async function getNonExistingReferenceAsKeys( - savedObjects: SavedObject[], - savedObjectsClient: SavedObjectsClientContract, - namespace: string | undefined, - importStateMap: ImportStateMap, - retries?: SavedObjectsImportRetry[] -) { +export interface ValidateReferencesParams { + objects: Array>; + savedObjectsClient: SavedObjectsClientContract; + namespace: string | undefined; + importStateMap: ImportStateMap; + retries?: SavedObjectsImportRetry[]; +} + +async function getNonExistingReferenceAsKeys({ + objects, + savedObjectsClient, + namespace, + importStateMap, + retries, +}: ValidateReferencesParams) { const objectsToSkip = getObjectsToSkip(retries); const collector = new Map(); // Collect all references within objects - for (const savedObject of savedObjects) { - if (objectsToSkip.has(`${savedObject.type}:${savedObject.id}`)) { + for (const object of objects) { + if (objectsToSkip.has(`${object.type}:${object.id}`)) { // skip objects with retries that have specified `ignoreMissingReferences`, or that share an origin with an existing object that has a different ID continue; } - const filteredReferences = (savedObject.references || []).filter(filterReferencesToValidate); + const filteredReferences = (object.references || []).filter(filterReferencesToValidate); for (const { type, id } of filteredReferences) { const key = `${type}:${id}`; const { isOnlyReference, destinationId } = importStateMap.get(key) ?? {}; @@ -51,8 +59,8 @@ export async function getNonExistingReferenceAsKeys( } // Remove objects that could be references - for (const savedObject of savedObjects) { - collector.delete(`${savedObject.type}:${savedObject.id}`); + for (const object of objects) { + collector.delete(`${object.type}:${object.id}`); } if (collector.size === 0) { return []; @@ -81,25 +89,14 @@ export async function getNonExistingReferenceAsKeys( return [...collector.keys()]; } -export async function validateReferences( - savedObjects: Array>, - savedObjectsClient: SavedObjectsClientContract, - namespace: string | undefined, - importStateMap: ImportStateMap, - retries?: SavedObjectsImportRetry[] -) { +export async function validateReferences(params: ValidateReferencesParams) { + const { objects, retries } = params; const objectsToSkip = getObjectsToSkip(retries); const errorMap: { [key: string]: SavedObjectsImportFailure } = {}; - const nonExistingReferenceKeys = await getNonExistingReferenceAsKeys( - savedObjects, - savedObjectsClient, - namespace, - importStateMap, - retries - ); + const nonExistingReferenceKeys = await getNonExistingReferenceAsKeys(params); // Filter out objects with missing references, add to error object - savedObjects.forEach(({ type, id, references, attributes }) => { + objects.forEach(({ type, id, references, attributes }) => { if (objectsToSkip.has(`${type}:${id}`)) { // skip objects with retries that have specified `ignoreMissingReferences` return; diff --git a/src/core/server/saved_objects/import/resolve_import_errors.test.ts b/src/core/server/saved_objects/import/resolve_import_errors.test.ts index c7bf097241846..d950545de54f9 100644 --- a/src/core/server/saved_objects/import/resolve_import_errors.test.ts +++ b/src/core/server/saved_objects/import/resolve_import_errors.test.ts @@ -215,17 +215,17 @@ describe('#importSavedObjectsFromStream', () => { }); await resolveSavedObjectsImportErrors(options); - expect(mockValidateReferences).toHaveBeenCalledWith( - collectedObjects, + expect(mockValidateReferences).toHaveBeenCalledWith({ + objects: collectedObjects, savedObjectsClient, namespace, - new Map([ + importStateMap: new Map([ // This importStateMap is a combination of the other two [`${collectedObjects[0].type}:${collectedObjects[0].id}`, {}], [`foo:bar`, { isOnlyReference: true, id: 'baz' }], ]), - retries - ); + retries, + }); }); test('execute import hooks', async () => { @@ -273,13 +273,13 @@ describe('#importSavedObjectsFromStream', () => { ...object, references: [{ ...object.references[0], id: 'def' }], }; - expect(mockValidateReferences).toHaveBeenCalledWith( - [objectWithReplacedReferences], + expect(mockValidateReferences).toHaveBeenCalledWith({ + objects: [objectWithReplacedReferences], savedObjectsClient, namespace, - new Map(), // doesn't matter - retries - ); + importStateMap: new Map(), // doesn't matter + retries, + }); }); test('checks conflicts', async () => { diff --git a/src/core/server/saved_objects/import/resolve_import_errors.ts b/src/core/server/saved_objects/import/resolve_import_errors.ts index 7257692c455a1..61fbde5bb9d87 100644 --- a/src/core/server/saved_objects/import/resolve_import_errors.ts +++ b/src/core/server/saved_objects/import/resolve_import_errors.ts @@ -122,13 +122,13 @@ export async function resolveSavedObjectsImportErrors({ importStateMap = new Map([...importStateMap, ...checkReferenceOriginsResult.importStateMap]); // Validate references - const validateReferencesResult = await validateReferences( - collectSavedObjectsResult.collectedObjects, + const validateReferencesResult = await validateReferences({ + objects: collectSavedObjectsResult.collectedObjects, savedObjectsClient, namespace, importStateMap, - retries - ); + retries, + }); errorAccumulator = [...errorAccumulator, ...validateReferencesResult]; if (createNewCopies) {