Skip to content

Commit

Permalink
Merge branch 'master' into fix/kbn-client/basepath-and-export-reponse…
Browse files Browse the repository at this point in the history
…-type
  • Loading branch information
kibanamachine committed Apr 15, 2021
2 parents 25bcb84 + b09e418 commit 0a63444
Show file tree
Hide file tree
Showing 200 changed files with 5,319 additions and 4,998 deletions.
3 changes: 3 additions & 0 deletions packages/kbn-io-ts-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
export { jsonRt } from './json_rt';
export { mergeRt } from './merge_rt';
export { strictKeysRt } from './strict_keys_rt';
export { isoToEpochRt } from './iso_to_epoch_rt';
export { toNumberRt } from './to_number_rt';
export { toBooleanRt } from './to_boolean_rt';
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/*
* 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.
* 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 { isoToEpochRt } from './index';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/*
* 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.
* 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 * as t from 'io-ts';
Expand All @@ -17,9 +18,7 @@ export const isoToEpochRt = new t.Type<number, string, unknown>(
(input, context) =>
either.chain(t.string.validate(input, context), (str) => {
const epochDate = new Date(str).getTime();
return isNaN(epochDate)
? t.failure(input, context)
: t.success(epochDate);
return isNaN(epochDate) ? t.failure(input, context) : t.success(epochDate);
}),
(output) => new Date(output).toISOString()
);
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/*
* 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.
* 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 * as t from 'io-ts';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/*
* 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.
* 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 * as t from 'io-ts';
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pageLoadAssetSize:
remoteClusters: 51327
reporting: 183418
rollup: 97204
ruleRegistry: 100000
savedObjects: 108518
savedObjectsManagement: 101836
savedObjectsTagging: 59482
Expand Down
97 changes: 54 additions & 43 deletions src/core/server/saved_objects/serialization/serializer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ describe('#rawToSavedObject', () => {
_id: 'foo:bar',
_source: {
type: 'foo',
hello: {},
},
});
expect(actual).not.toHaveProperty('version');
Expand All @@ -171,7 +170,6 @@ describe('#rawToSavedObject', () => {
_primary_term: 1,
_source: {
type: 'foo',
hello: {},
},
});
expect(actual).toHaveProperty('version', encodeVersion(4, 1));
Expand All @@ -184,7 +182,6 @@ describe('#rawToSavedObject', () => {
_seq_no: 4,
_source: {
type: 'foo',
hello: {},
},
})
).toThrowErrorMatchingInlineSnapshot(`"_primary_term from elasticsearch must be an integer"`);
Expand All @@ -197,7 +194,6 @@ describe('#rawToSavedObject', () => {
_primary_term: 1,
_source: {
type: 'foo',
hello: {},
},
})
).toThrowErrorMatchingInlineSnapshot(`"_seq_no from elasticsearch must be an integer"`);
Expand Down Expand Up @@ -249,7 +245,7 @@ describe('#rawToSavedObject', () => {

test('it does not pass unknown properties through', () => {
const actual = singleNamespaceSerializer.rawToSavedObject({
_id: 'universe',
_id: 'hello:universe',
_source: {
type: 'hello',
hello: {
Expand All @@ -270,7 +266,7 @@ describe('#rawToSavedObject', () => {

test('it does not create attributes if [type] is missing', () => {
const actual = singleNamespaceSerializer.rawToSavedObject({
_id: 'universe',
_id: 'hello:universe',
_source: {
type: 'hello',
},
Expand All @@ -285,14 +281,14 @@ describe('#rawToSavedObject', () => {
test('it fails for documents which do not specify a type', () => {
expect(() =>
singleNamespaceSerializer.rawToSavedObject({
_id: 'universe',
_id: 'hello:universe',
_source: {
hello: {
world: 'earth',
},
} as any,
})
).toThrow(/Expected "undefined" to be a saved object type/);
).toThrow(`Raw document 'hello:universe' is missing _source.type field`);
});

test('it is complimentary with savedObjectToRaw', () => {
Expand Down Expand Up @@ -325,29 +321,30 @@ describe('#rawToSavedObject', () => {
).toEqual(raw);
});

test('it handles unprefixed ids', () => {
const actual = singleNamespaceSerializer.rawToSavedObject({
_id: 'universe',
_source: {
type: 'hello',
},
});

expect(actual).toHaveProperty('id', 'universe');
test('fails for documents which do not have a type prefix in their _id', () => {
expect(() =>
singleNamespaceSerializer.rawToSavedObject({
_id: 'universe',
_source: {
type: 'hello',
},
})
).toThrow(`Raw document 'universe' does not start with expected prefix 'hello:'`);
});

describe('namespace-agnostic type with a namespace', () => {
const raw = createSampleDoc({ _source: { namespace: 'baz' } });
const raw = createSampleDoc({ _source: { namespace: 'baz' } }); // namespace field should be ignored
const actual = namespaceAgnosticSerializer.rawToSavedObject(raw);

test(`removes type prefix from _id`, () => {
expect(actual).toHaveProperty('id', 'bar');
});

test(`copies _id to id if prefixed by namespace and type`, () => {
test(`fails for documents which have a namespace prefix in their _id`, () => {
const _id = `${raw._source.namespace}:${raw._id}`;
const _actual = namespaceAgnosticSerializer.rawToSavedObject({ ...raw, _id });
expect(_actual).toHaveProperty('id', _id);
expect(() => namespaceAgnosticSerializer.rawToSavedObject({ ...raw, _id })).toThrow(
`Raw document 'baz:foo:bar' does not start with expected prefix 'foo:'`
);
});

test(`doesn't copy _source.namespace to namespace`, () => {
Expand All @@ -372,10 +369,11 @@ describe('#rawToSavedObject', () => {
expect(actual).toHaveProperty('id', 'bar');
});

test(`copies _id to id if prefixed by random prefix and type`, () => {
test(`fails for documents which have any extra prefix in their _id`, () => {
const _id = `random:${raw._id}`;
const _actual = singleNamespaceSerializer.rawToSavedObject({ ...raw, _id });
expect(_actual).toHaveProperty('id', _id);
expect(() => singleNamespaceSerializer.rawToSavedObject({ ...raw, _id })).toThrow(
`Raw document 'random:foo:bar' does not start with expected prefix 'foo:'`
);
});

test(`doesn't specify namespace`, () => {
Expand All @@ -385,23 +383,28 @@ describe('#rawToSavedObject', () => {

describe('single-namespace type with a namespace', () => {
const namespace = 'baz';
const raw = createSampleDoc({ _source: { namespace } });
const raw = createSampleDoc({
_id: `${namespace}:${sampleTemplate._id}`,
_source: { namespace },
});
const actual = singleNamespaceSerializer.rawToSavedObject(raw);

test(`removes type and namespace prefix from _id`, () => {
const _id = `${namespace}:${raw._id}`;
const _actual = singleNamespaceSerializer.rawToSavedObject({ ...raw, _id });
expect(_actual).toHaveProperty('id', 'bar');
expect(actual).toHaveProperty('id', 'bar');
});

test(`copies _id to id if prefixed only by type`, () => {
expect(actual).toHaveProperty('id', raw._id);
test(`fails for documents which do not have a namespace prefix in their _id`, () => {
const _id = sampleTemplate._id;
expect(() => singleNamespaceSerializer.rawToSavedObject({ ...raw, _id })).toThrow(
`Raw document 'foo:bar' does not start with expected prefix 'baz:foo:'`
);
});

test(`copies _id to id if prefixed by random prefix and type`, () => {
test(`fails for documents which have any extra prefix in their _id`, () => {
const _id = `random:${raw._id}`;
const _actual = singleNamespaceSerializer.rawToSavedObject({ ...raw, _id });
expect(_actual).toHaveProperty('id', _id);
expect(() => singleNamespaceSerializer.rawToSavedObject({ ...raw, _id })).toThrow(
`Raw document 'random:baz:foo:bar' does not start with expected prefix 'baz:foo:'`
);
});

test(`copies _source.namespace to namespace`, () => {
Expand All @@ -419,17 +422,25 @@ describe('#rawToSavedObject', () => {
});

describe('multi-namespace type with a namespace', () => {
const raw = createSampleDoc({ _source: { namespace: 'baz' } });
const raw = createSampleDoc({ _source: { namespace: 'baz' } }); // namespace should be ignored
const actual = multiNamespaceSerializer.rawToSavedObject(raw);

test(`removes type prefix from _id`, () => {
expect(actual).toHaveProperty('id', 'bar');
});

test(`copies _id to id if prefixed by namespace and type`, () => {
test(`fails for documents which have a namespace prefix in their _id`, () => {
const _id = `${raw._source.namespace}:${raw._id}`;
const _actual = multiNamespaceSerializer.rawToSavedObject({ ...raw, _id });
expect(_actual).toHaveProperty('id', _id);
expect(() => multiNamespaceSerializer.rawToSavedObject({ ...raw, _id })).toThrow(
`Raw document 'baz:foo:bar' does not start with expected prefix 'foo:'`
);
});

test(`fails for documents which have any extra prefix in their _id`, () => {
const _id = `random:${raw._id}`;
expect(() => multiNamespaceSerializer.rawToSavedObject({ ...raw, _id })).toThrow(
`Raw document 'random:foo:bar' does not start with expected prefix 'foo:'`
);
});

test(`doesn't copy _source.namespace to namespace`, () => {
Expand Down Expand Up @@ -785,7 +796,7 @@ describe('#isRawSavedObject', () => {
).toBeFalsy();
});

test('is false if there is no [type] attribute', () => {
test('is true if there is no [type] attribute', () => {
expect(
singleNamespaceSerializer.isRawSavedObject({
_id: 'hello:world',
Expand All @@ -794,7 +805,7 @@ describe('#isRawSavedObject', () => {
jam: {},
},
})
).toBeFalsy();
).toBeTruthy();
});
});

Expand Down Expand Up @@ -1014,7 +1025,7 @@ describe('#isRawSavedObject', () => {
).toBeFalsy();
});

test('is false if there is no [type] attribute', () => {
test('is true if there is no [type] attribute', () => {
expect(
multiNamespaceSerializer.isRawSavedObject({
_id: 'hello:world',
Expand All @@ -1024,7 +1035,7 @@ describe('#isRawSavedObject', () => {
namespace: 'foo',
},
})
).toBeFalsy();
).toBeTruthy();
});
});

Expand Down Expand Up @@ -1107,7 +1118,7 @@ describe('#isRawSavedObject', () => {
).toBeFalsy();
});

test('is false if there is no [type] attribute', () => {
test('is true if there is no [type] attribute', () => {
expect(
namespaceAgnosticSerializer.isRawSavedObject({
_id: 'hello:world',
Expand All @@ -1117,7 +1128,7 @@ describe('#isRawSavedObject', () => {
namespace: 'foo',
},
})
).toBeFalsy();
).toBeTruthy();
});
});
});
Expand Down
29 changes: 26 additions & 3 deletions src/core/server/saved_objects/serialization/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,35 @@ export class SavedObjectsSerializer {
* @param {SavedObjectsRawDocParseOptions} options - Options for parsing the raw document.
*/
public isRawSavedObject(doc: SavedObjectsRawDoc, options: SavedObjectsRawDocParseOptions = {}) {
try {
this.checkIsRawSavedObject(doc, options);
return true;
} catch (error) {
// do nothing
}
return false;
}

private checkIsRawSavedObject(
doc: SavedObjectsRawDoc,
options: SavedObjectsRawDocParseOptions = {}
) {
const { namespaceTreatment = 'strict' } = options;
const { _id, _source } = doc;
const { type, namespace } = _source;
if (!type) {
return false;
throw new Error(`Raw document '${_id}' is missing _source.type field`);
}
const { idMatchesPrefix } = this.parseIdPrefix(namespace, type, _id, namespaceTreatment);
return idMatchesPrefix && _source.hasOwnProperty(type);
const { idMatchesPrefix, prefix } = this.parseIdPrefix(
namespace,
type,
_id,
namespaceTreatment
);
if (!idMatchesPrefix) {
throw new Error(`Raw document '${_id}' does not start with expected prefix '${prefix}'`);
}
return idMatchesPrefix;
}

/**
Expand All @@ -59,6 +80,8 @@ export class SavedObjectsSerializer {
doc: SavedObjectsRawDoc,
options: SavedObjectsRawDocParseOptions = {}
): SavedObjectSanitizedDoc {
this.checkIsRawSavedObject(doc, options); // throws a descriptive error if the document is not a saved object

const { namespaceTreatment = 'strict' } = options;
const { _id, _source, _seq_no, _primary_term } = doc;
const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ describe('registerCloudProviderUsageCollector', () => {
expect(collector.isReady()).toBe(true);
});

test('isReady() => true when cloud details have been retrieved but none have been found', () => {
cloudDetailsMock.mockReturnValueOnce(null);
expect(collector.isReady()).toBe(true);
});

test('initiates CloudDetector.detectCloudDetails when called', () => {
expect(detectCloudServiceMock).toHaveBeenCalledTimes(1);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function registerCloudProviderUsageCollector(usageCollection: UsageCollec

const collector = usageCollection.makeUsageCollector<Usage | undefined>({
type: 'cloud_provider',
isReady: () => Boolean(cloudDetector.getCloudDetails()),
isReady: () => typeof cloudDetector.getCloudDetails() !== 'undefined',
async fetch() {
const details = cloudDetector.getCloudDetails();
if (!details) {
Expand Down

0 comments on commit 0a63444

Please sign in to comment.