Skip to content

Commit

Permalink
Merge branch 'main' into further-serve-refactors
Browse files Browse the repository at this point in the history
  • Loading branch information
delanni committed Jun 5, 2023
2 parents 570f866 + c57589e commit 5415ba7
Show file tree
Hide file tree
Showing 67 changed files with 2,177 additions and 543 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* 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.
*/

import { loggerMock, type MockedLogger } from '@kbn/logging-mocks';
import { SavedObjectsType } from '@kbn/core-saved-objects-server';
import { type SavedObjectSanitizedDoc } from '@kbn/core-saved-objects-server';
import { ValidationHelper } from './validation';
import { typedef, typedef1, typedef2 } from './validation_fixtures';
import { SavedObjectTypeRegistry } from '@kbn/core-saved-objects-base-server-internal';

const defaultVersion = '8.10.0';
const modelVirtualVersion = '10.1.0';
const typeA = 'my-typeA';
const typeB = 'my-typeB';
const typeC = 'my-typeC';

describe('Saved Objects type validation helper', () => {
let helper: ValidationHelper;
let logger: MockedLogger;
let typeRegistry: SavedObjectTypeRegistry;

const createMockObject = (
type: string,
attr: Partial<SavedObjectSanitizedDoc>
): SavedObjectSanitizedDoc => ({
type,
id: 'test-id',
references: [],
attributes: {},
...attr,
});
const registerType = (name: string, parts: Partial<SavedObjectsType>) => {
typeRegistry.registerType({
name,
hidden: false,
namespaceType: 'single',
mappings: { properties: {} },
...parts,
});
};
beforeEach(() => {
logger = loggerMock.create();
typeRegistry = new SavedObjectTypeRegistry();
});

afterEach(() => {
jest.resetAllMocks();
});

describe('validation helper', () => {
beforeEach(() => {
registerType(typeA, typedef);
registerType(typeB, typedef1);
registerType(typeC, typedef2);
});

it('should validate objects against stack versions', () => {
helper = new ValidationHelper({
logger,
registry: typeRegistry,
kibanaVersion: defaultVersion,
});
const data = createMockObject(typeA, { attributes: { foo: 'hi', count: 1 } });
expect(() => helper.validateObjectForCreate(typeA, data)).not.toThrowError();
});

it('should validate objects against model versions', () => {
helper = new ValidationHelper({
logger,
registry: typeRegistry,
kibanaVersion: modelVirtualVersion,
});
const data = createMockObject(typeB, { attributes: { foo: 'hi', count: 1 } });
expect(() => helper.validateObjectForCreate(typeB, data)).not.toThrowError();
});

it('should fail validation against invalid objects when version requested does not support a field', () => {
helper = new ValidationHelper({
logger,
registry: typeRegistry,
kibanaVersion: defaultVersion,
});
const validationError = new Error(
'[attributes.count]: definition for this key is missing: Bad Request'
);
const data = createMockObject(typeC, { attributes: { foo: 'hi', count: 1 } });
expect(() => helper.validateObjectForCreate(typeC, data)).toThrowError(validationError);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
import type { PublicMethodsOf } from '@kbn/utility-types';
import type { Logger } from '@kbn/logging';
import type { ISavedObjectTypeRegistry } from '@kbn/core-saved-objects-server';
import { SavedObjectsTypeValidator } from '@kbn/core-saved-objects-base-server-internal';
import {
SavedObjectsTypeValidator,
modelVersionToVirtualVersion,
} from '@kbn/core-saved-objects-base-server-internal';
import {
SavedObjectsErrorHelpers,
type SavedObjectSanitizedDoc,
Expand Down Expand Up @@ -91,7 +94,7 @@ export class ValidationHelper {
}
const validator = this.getTypeValidator(type);
try {
validator.validate(doc, this.kibanaVersion);
validator.validate(doc);
} catch (error) {
throw SavedObjectsErrorHelpers.createBadRequestError(error.message);
}
Expand All @@ -100,10 +103,30 @@ export class ValidationHelper {
private getTypeValidator(type: string): SavedObjectsTypeValidator {
if (!this.typeValidatorMap[type]) {
const savedObjectType = this.registry.getType(type);

const stackVersionSchemas =
typeof savedObjectType?.schemas === 'function'
? savedObjectType.schemas()
: savedObjectType?.schemas ?? {};

const modelVersionCreateSchemas =
typeof savedObjectType?.modelVersions === 'function'
? savedObjectType.modelVersions()
: savedObjectType?.modelVersions ?? {};

const combinedSchemas = { ...stackVersionSchemas };
Object.entries(modelVersionCreateSchemas).reduce((map, [key, modelVersion]) => {
if (modelVersion.schemas?.create) {
const virtualVersion = modelVersionToVirtualVersion(key);
combinedSchemas[virtualVersion] = modelVersion.schemas!.create!;
}
return map;
}, {});

this.typeValidatorMap[type] = new SavedObjectsTypeValidator({
logger: this.logger.get('type-validator'),
type,
validationMap: savedObjectType!.schemas ?? {},
validationMap: combinedSchemas,
defaultVersion: this.kibanaVersion,
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* 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.
*/

import { schema } from '@kbn/config-schema';
import { SavedObjectsType } from '@kbn/core-saved-objects-server';

export const typedef: Partial<SavedObjectsType> = {
mappings: {
properties: {
foo: {
type: 'keyword',
},
count: {
type: 'integer',
},
},
},
schemas: {
'8.9.0': schema.object({
foo: schema.string(),
}),
'8.10.0': schema.object({
foo: schema.string(),
count: schema.number(),
}),
},
switchToModelVersionAt: '8.10.0',
};

export const typedef1: Partial<SavedObjectsType> = {
mappings: {
properties: {
foo: {
type: 'keyword',
},
count: {
type: 'integer',
},
},
},
schemas: {
'8.9.0': schema.object({
foo: schema.string(),
}),
'8.10.0': schema.object({
foo: schema.string(),
count: schema.number(),
}),
},
switchToModelVersionAt: '8.10.0',
modelVersions: {
'1': {
changes: [
{
type: 'mappings_addition',
addedMappings: {
count: {
properties: {
count: {
type: 'integer',
},
},
},
},
},
],
schemas: {
create: schema.object({
foo: schema.string(),
count: schema.number(),
}),
},
},
},
};

export const typedef2: Partial<SavedObjectsType> = {
mappings: {
properties: {
foo: {
type: 'keyword',
},
count: {
type: 'integer',
},
},
},
schemas: {
'8.9.0': schema.object({
foo: schema.string(),
}),
},
switchToModelVersionAt: '8.10.0',
modelVersions: {
'1': {
changes: [
{
type: 'mappings_addition',
addedMappings: {
count: {
properties: {
count: {
type: 'integer',
},
},
},
},
},
],
schemas: {
create: schema.object({
foo: schema.string(),
count: schema.number(),
}),
},
},
},
};

0 comments on commit 5415ba7

Please sign in to comment.