Skip to content

Commit

Permalink
update zdt version check to detect root field changes
Browse files Browse the repository at this point in the history
  • Loading branch information
pgayvallet committed Mar 28, 2024
1 parent d32322f commit 98efb6a
Show file tree
Hide file tree
Showing 8 changed files with 328 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,32 @@ describe('getUpdatedRootFields', () => {

expect(updatedFields).toEqual(['namespace', 'references']);
});

it('ignores fields not being present on the base mapping for the diff', () => {
const updatedFields = getUpdatedRootFields({
properties: {
...getBaseMappings().properties,
someUnknownField: {
type: 'text',
},
},
});

expect(updatedFields).toEqual([]);
});

it('ignores fields not being present on the base mapping even with nested props', () => {
const updatedFields = getUpdatedRootFields({
properties: {
...getBaseMappings().properties,
someTypeProps: {
properties: {
foo: { type: 'text' },
},
},
},
});

expect(updatedFields).toEqual([]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export const init: ModelStage<
case 'greater':
const additiveMappingChanges = generateAdditiveMappingDiff({
types,
meta: currentMappings._meta ?? {},
mapping: currentMappings,
deletedTypes: context.deletedTypes,
});
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,13 @@ jest.doMock('@kbn/core-saved-objects-base-server-internal', () => {
getVirtualVersionMap: getVirtualVersionMapMock,
};
});

export const getUpdatedRootFieldsMock = jest.fn();

jest.doMock('../../core/compare_mappings', () => {
const actual = jest.requireActual('../../core/compare_mappings');
return {
...actual,
getUpdatedRootFields: getUpdatedRootFieldsMock,
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
compareVirtualVersionsMock,
getVirtualVersionMapMock,
getVirtualVersionsFromMappingsMock,
getUpdatedRootFieldsMock,
} from './check_version_compatibility.test.mocks';
import type { SavedObjectsType } from '@kbn/core-saved-objects-server';
import type {
Expand All @@ -30,6 +31,7 @@ describe('checkVersionCompatibility', () => {
compareVirtualVersionsMock.mockReset().mockReturnValue({});
getVirtualVersionMapMock.mockReset().mockReturnValue({});
getVirtualVersionsFromMappingsMock.mockReset().mockReturnValue({ status: 'equal' });
getUpdatedRootFieldsMock.mockReset().mockReturnValue([]);

types = [createType({ name: 'foo' }), createType({ name: 'bar' })];

Expand Down Expand Up @@ -88,24 +90,112 @@ describe('checkVersionCompatibility', () => {
});
});

it('returns the result of the compareModelVersions call', () => {
const expected: CompareModelVersionResult = {
status: 'lesser',
details: {
greater: [],
lesser: [],
equal: [],
},
};
compareVirtualVersionsMock.mockReturnValue(expected);

const result = checkVersionCompatibility({
it('calls getUpdatedRootFields with the correct parameters', () => {
checkVersionCompatibility({
types,
mappings,
source: 'mappingVersions',
deletedTypes,
});

expect(result).toEqual(expected);
expect(getUpdatedRootFieldsMock).toHaveBeenCalledTimes(1);
expect(getUpdatedRootFieldsMock).toHaveBeenCalledWith(mappings);
});

describe('without updated root fields', () => {
it('returns the result of the compareModelVersions call', () => {
const expected: CompareModelVersionResult = {
status: 'lesser',
details: { greater: [], lesser: [], equal: [] },
};
compareVirtualVersionsMock.mockReturnValue(expected);

const result = checkVersionCompatibility({
types,
mappings,
source: 'mappingVersions',
deletedTypes,
});

expect(result).toEqual({
status: expected.status,
versionDetails: expected.details,
updatedRootFields: [],
});
});
});

describe('with updated root fields', () => {
beforeEach(() => {
getUpdatedRootFieldsMock.mockReturnValue(['rootA']);
});

it('returns the correct status for `greater` version status check', () => {
const expected: CompareModelVersionResult = {
status: 'greater',
details: { greater: [], lesser: [], equal: [] },
};
compareVirtualVersionsMock.mockReturnValue(expected);

const result = checkVersionCompatibility({
types,
mappings,
source: 'mappingVersions',
deletedTypes,
});

expect(result.status).toEqual('greater');
});

it('returns the correct status for `lesser` version status check', () => {
const expected: CompareModelVersionResult = {
status: 'lesser',
details: { greater: [], lesser: [], equal: [] },
};
compareVirtualVersionsMock.mockReturnValue(expected);

const result = checkVersionCompatibility({
types,
mappings,
source: 'mappingVersions',
deletedTypes,
});

expect(result.status).toEqual('conflict');
});

it('returns the correct status for `equal` version status check', () => {
const expected: CompareModelVersionResult = {
status: 'equal',
details: { greater: [], lesser: [], equal: [] },
};
compareVirtualVersionsMock.mockReturnValue(expected);

const result = checkVersionCompatibility({
types,
mappings,
source: 'mappingVersions',
deletedTypes,
});

expect(result.status).toEqual('greater');
});

it('returns the correct status for `conflict` version status check', () => {
const expected: CompareModelVersionResult = {
status: 'conflict',
details: { greater: [], lesser: [], equal: [] },
};
compareVirtualVersionsMock.mockReturnValue(expected);

const result = checkVersionCompatibility({
types,
mappings,
source: 'mappingVersions',
deletedTypes,
});

expect(result.status).toEqual('conflict');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import {
compareVirtualVersions,
getVirtualVersionMap,
type IndexMapping,
type CompareModelVersionResult,
type CompareModelVersionStatus,
type CompareModelVersionDetails,
} from '@kbn/core-saved-objects-base-server-internal';
import { getUpdatedRootFields } from '../../core/compare_mappings';

interface CheckVersionCompatibilityOpts {
mappings: IndexMapping;
Expand All @@ -22,12 +24,20 @@ interface CheckVersionCompatibilityOpts {
deletedTypes: string[];
}

type CheckVersionCompatibilityStatus = 'greater' | 'lesser' | 'equal' | 'conflict';

interface CheckVersionCompatibilityResult {
status: CheckVersionCompatibilityStatus;
versionDetails: CompareModelVersionDetails;
updatedRootFields: string[];
}

export const checkVersionCompatibility = ({
mappings,
types,
source,
deletedTypes,
}: CheckVersionCompatibilityOpts): CompareModelVersionResult => {
}: CheckVersionCompatibilityOpts): CheckVersionCompatibilityResult => {
const appVersions = getVirtualVersionMap(types);
const indexVersions = getVirtualVersionsFromMappings({
mappings,
Expand All @@ -37,5 +47,34 @@ export const checkVersionCompatibility = ({
if (!indexVersions) {
throw new Error(`Cannot check version: ${source} not present in the mapping meta`);
}
return compareVirtualVersions({ appVersions, indexVersions, deletedTypes });

const updatedRootFields = getUpdatedRootFields(mappings);
const modelVersionStatus = compareVirtualVersions({ appVersions, indexVersions, deletedTypes });
const status = getCompatibilityStatus(modelVersionStatus.status, updatedRootFields.length > 0);

return {
status,
updatedRootFields,
versionDetails: modelVersionStatus.details,
};
};

const getCompatibilityStatus = (
versionStatus: CompareModelVersionStatus,
hasUpdatedRootFields: boolean
): CheckVersionCompatibilityStatus => {
if (!hasUpdatedRootFields) {
return versionStatus;
}
switch (versionStatus) {
case 'lesser':
// lower model versions but additional root mappings => conflict
return 'conflict';
case 'equal':
// no change on model versions but additional root mappings => greater
return 'greater';
default:
// greater and conflict are not impacted
return versionStatus;
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export const getBaseMappingsMock = jest.fn();

jest.doMock('../../core/build_active_mappings', () => {
const actual = jest.requireActual('../../core/build_active_mappings');
return {
...actual,
getBaseMappings: getBaseMappingsMock,
};
});

export const getUpdatedRootFieldsMock = jest.fn();

jest.doMock('../../core/compare_mappings', () => {
const actual = jest.requireActual('../../core/compare_mappings');
return {
...actual,
getUpdatedRootFields: getUpdatedRootFieldsMock,
};
});
Loading

0 comments on commit 98efb6a

Please sign in to comment.