Skip to content

Commit

Permalink
Test config settings that are exposed to the browser (#129438)
Browse files Browse the repository at this point in the history
(cherry picked from commit 27ff7d3)

# Conflicts:
#	.github/CODEOWNERS
#	packages/kbn-config-schema/src/index.ts
  • Loading branch information
jportner authored and Joe Portner committed Apr 9, 2022
1 parent 95dadca commit ef3aa64
Show file tree
Hide file tree
Showing 16 changed files with 520 additions and 127 deletions.
3 changes: 2 additions & 1 deletion packages/kbn-config-schema/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
NullableProps,
RecordOfOptions,
RecordOfType,
SchemaStructureEntry,
StringOptions,
StringType,
Type,
Expand All @@ -49,7 +50,7 @@ import {
StreamType,
} from './types';

export type { TypeOf, Props, NullableProps };
export type { TypeOf, Props, SchemaStructureEntry, NullableProps };
export { ObjectType, Type };
export { ByteSizeValue } from './byte_size_value';
export { SchemaTypeError, ValidationError } from './errors';
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-config-schema/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

export type { TypeOptions } from './type';
export type { SchemaStructureEntry } from './type';
export { Type } from './type';
export { AnyType } from './any_type';
export type { ArrayOptions } from './array_type';
Expand Down
73 changes: 73 additions & 0 deletions packages/kbn-config-schema/src/types/object_type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,3 +490,76 @@ describe('#extends', () => {
expect(extended.validate(undefined)).toEqual({ initial: 'bar', added: 42 });
});
});

test('returns schema structure', () => {
// This test covers different schema types that may or may not be nested
const objSchema = schema.object({
any: schema.any(),
array: schema.arrayOf(schema.string()),
boolean: schema.boolean(),
buffer: schema.buffer(),
byteSize: schema.byteSize(),
conditional: schema.conditional(
schema.contextRef('context_value_1'),
schema.contextRef('context_value_2'),
schema.string(),
schema.string()
),
duration: schema.duration(),
ip: schema.ip(),
literal: schema.literal('foo'),
map: schema.mapOf(schema.string(), schema.string()),
maybe: schema.maybe(schema.string()),
never: schema.never(),
nullable: schema.nullable(schema.string()),
number: schema.number(),
record: schema.recordOf(schema.string(), schema.string()),
stream: schema.stream(),
string: schema.string(),
union: schema.oneOf([schema.string()]),
uri: schema.uri(),
});
const type = objSchema.extends({
nested: objSchema,
});
expect(type.getSchemaStructure()).toEqual([
{ path: ['any'], type: 'any' },
{ path: ['array'], type: 'array' },
{ path: ['boolean'], type: 'boolean' },
{ path: ['buffer'], type: 'binary' },
{ path: ['byteSize'], type: 'bytes' },
{ path: ['conditional'], type: 'any' },
{ path: ['duration'], type: 'duration' },
{ path: ['ip'], type: 'string' },
{ path: ['literal'], type: 'any' },
{ path: ['map'], type: 'map' },
{ path: ['maybe'], type: 'string' },
{ path: ['never'], type: 'any' },
{ path: ['nullable'], type: 'alternatives' },
{ path: ['number'], type: 'number' },
{ path: ['record'], type: 'record' },
{ path: ['stream'], type: 'stream' },
{ path: ['string'], type: 'string' },
{ path: ['union'], type: 'alternatives' },
{ path: ['uri'], type: 'string' },
{ path: ['nested', 'any'], type: 'any' },
{ path: ['nested', 'array'], type: 'array' },
{ path: ['nested', 'boolean'], type: 'boolean' },
{ path: ['nested', 'buffer'], type: 'binary' },
{ path: ['nested', 'byteSize'], type: 'bytes' },
{ path: ['nested', 'conditional'], type: 'any' },
{ path: ['nested', 'duration'], type: 'duration' },
{ path: ['nested', 'ip'], type: 'string' },
{ path: ['nested', 'literal'], type: 'any' },
{ path: ['nested', 'map'], type: 'map' },
{ path: ['nested', 'maybe'], type: 'string' },
{ path: ['nested', 'never'], type: 'any' },
{ path: ['nested', 'nullable'], type: 'alternatives' },
{ path: ['nested', 'number'], type: 'number' },
{ path: ['nested', 'record'], type: 'record' },
{ path: ['nested', 'stream'], type: 'stream' },
{ path: ['nested', 'string'], type: 'string' },
{ path: ['nested', 'union'], type: 'alternatives' },
{ path: ['nested', 'uri'], type: 'string' },
]);
});
1 change: 1 addition & 0 deletions packages/kbn-config-schema/src/types/string_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export class StringType extends Type<string> {
);
}

schema.type = 'string';
super(schema, options);
}

Expand Down
23 changes: 23 additions & 0 deletions packages/kbn-config-schema/src/types/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ export interface TypeOptions<T> {
validate?: (value: T) => string | void;
}

export interface SchemaStructureEntry {
path: string[];
type: string;
}

export const convertValidationFunction = <T = unknown>(
validate: (value: T) => string | void
): CustomValidator<T> => {
Expand Down Expand Up @@ -98,6 +103,10 @@ export abstract class Type<V> {
return this.internalSchema;
}

public getSchemaStructure() {
return recursiveGetSchemaStructure(this.internalSchema);
}

protected handleError(
type: string,
context: Record<string, any>,
Expand Down Expand Up @@ -141,3 +150,17 @@ export abstract class Type<V> {
return new SchemaTypeError(message || code, convertedPath);
}
}

function recursiveGetSchemaStructure(internalSchema: AnySchema, path: string[] = []) {
const array: SchemaStructureEntry[] = [];
// Note: we are relying on Joi internals to obtain the schema structure (recursive keys).
// This is not ideal, but it works for now and we only need it for some integration test assertions.
// If it breaks in the future, we'll need to update our tests.
for (const [key, val] of (internalSchema as any)._ids._byKey.entries()) {
array.push(...recursiveGetSchemaStructure(val.schema, [...path, key]));
}
if (!array.length) {
array.push({ path, type: internalSchema.type ?? 'unknown' });
}
return array;
}
2 changes: 2 additions & 0 deletions src/core/server/http_resources/http_resources_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export class HttpResourcesService implements CoreService<InternalHttpResourcesSe
vars: {
apmConfig,
},
includeExposedConfigKeys: options.includeExposedConfigKeys,
});

return response.ok({
Expand All @@ -112,6 +113,7 @@ export class HttpResourcesService implements CoreService<InternalHttpResourcesSe
vars: {
apmConfig,
},
includeExposedConfigKeys: options.includeExposedConfigKeys,
});

return response.ok({
Expand Down
5 changes: 5 additions & 0 deletions src/core/server/http_resources/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export interface HttpResourcesRenderOptions {
* All HTML pages are already pre-configured with `content-security-policy` header that cannot be overridden.
* */
headers?: ResponseHeaders;
/**
* @internal
* This is only used for integration tests that allow us to verify which config keys are exposed to the browser.
*/
includeExposedConfigKeys?: boolean;
}

/**
Expand Down
Loading

0 comments on commit ef3aa64

Please sign in to comment.