Skip to content

Commit 48846b2

Browse files
Merge branch 'master' into ml-job-mgmt
2 parents ae0d59c + 156066d commit 48846b2

File tree

371 files changed

+8579
-11285
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

371 files changed

+8579
-11285
lines changed

docs/development/core/server/kibana-plugin-core-server.routeconfig.validate.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ validate: RouteValidatorFullConfig<P, Q, B> | false;
1414

1515
## Remarks
1616

17-
You \*must\* specify a validation schema to be able to read: - url path segments - request query - request body To opt out of validating the request, specify `validate: false`<!-- -->. In this case request params, query, and body will be \*\*empty\*\* objects and have no access to raw values. In some cases you may want to use another validation library. To do this, you need to instruct the `@kbn/config-schema` library to output \*\*non-validated values\*\* with setting schema as `schema.object({}, { allowUnknowns: true })`<!-- -->;
17+
You \*must\* specify a validation schema to be able to read: - url path segments - request query - request body To opt out of validating the request, specify `validate: false`<!-- -->. In this case request params, query, and body will be \*\*empty\*\* objects and have no access to raw values. In some cases you may want to use another validation library. To do this, you need to instruct the `@kbn/config-schema` library to output \*\*non-validated values\*\* with setting schema as `schema.object({}, { unknowns: 'allow' })`<!-- -->;
1818

1919
## Example
2020

@@ -49,7 +49,7 @@ router.get({
4949
path: 'path/{id}',
5050
validate: {
5151
// handler has access to raw non-validated params in runtime
52-
params: schema.object({}, { allowUnknowns: true })
52+
params: schema.object({}, { unknowns: 'allow' })
5353
},
5454
},
5555
(context, req, res,) {

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@
314314
"@types/cheerio": "^0.22.10",
315315
"@types/chromedriver": "^2.38.0",
316316
"@types/classnames": "^2.2.9",
317+
"@types/color": "^3.0.0",
317318
"@types/d3": "^3.5.43",
318319
"@types/dedent": "^0.7.0",
319320
"@types/deep-freeze-strict": "^1.1.0",

packages/kbn-config-schema/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ __Output type:__ `{ [K in keyof TProps]: TypeOf<TProps[K]> } as TObject`
239239
__Options:__
240240
* `defaultValue: TObject | Reference<TObject> | (() => TObject)` - defines a default value, see [Default values](#default-values) section for more details.
241241
* `validate: (value: TObject) => string | void` - defines a custom validator function, see [Custom validation](#custom-validation) section for more details.
242-
* `allowUnknowns: boolean` - indicates whether unknown object properties should be allowed. It's `false` by default.
242+
* `unknowns: 'allow' | 'ignore' | 'forbid'` - indicates whether unknown object properties should be allowed, ignored, or forbidden. It's `forbid` by default.
243243

244244
__Usage:__
245245
```typescript
@@ -250,7 +250,7 @@ const valueSchema = schema.object({
250250
```
251251

252252
__Notes:__
253-
* Using `allowUnknowns` is discouraged and should only be used in exceptional circumstances. Consider using `schema.recordOf()` instead.
253+
* Using `unknowns: 'allow'` is discouraged and should only be used in exceptional circumstances. Consider using `schema.recordOf()` instead.
254254
* Currently `schema.object()` always has a default value of `{}`, but this may change in the near future. Try to not rely on this behaviour and specify default value explicitly or use `schema.maybe()` if the value is optional.
255255
* `schema.object()` also supports a json string as input if it can be safely parsed using `JSON.parse` and if the resulting value is a plain object.
256256

packages/kbn-config-schema/src/types/object_type.test.ts

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,10 +276,10 @@ test('individual keys can validated', () => {
276276
);
277277
});
278278

279-
test('allow unknown keys when allowUnknowns = true', () => {
279+
test('allow unknown keys when unknowns = `allow`', () => {
280280
const type = schema.object(
281281
{ foo: schema.string({ defaultValue: 'test' }) },
282-
{ allowUnknowns: true }
282+
{ unknowns: 'allow' }
283283
);
284284

285285
expect(
@@ -292,10 +292,10 @@ test('allow unknown keys when allowUnknowns = true', () => {
292292
});
293293
});
294294

295-
test('allowUnknowns = true affects only own keys', () => {
295+
test('unknowns = `allow` affects only own keys', () => {
296296
const type = schema.object(
297297
{ foo: schema.object({ bar: schema.string() }) },
298-
{ allowUnknowns: true }
298+
{ unknowns: 'allow' }
299299
);
300300

301301
expect(() =>
@@ -308,14 +308,45 @@ test('allowUnknowns = true affects only own keys', () => {
308308
).toThrowErrorMatchingInlineSnapshot(`"[foo.baz]: definition for this key is missing"`);
309309
});
310310

311-
test('does not allow unknown keys when allowUnknowns = false', () => {
311+
test('does not allow unknown keys when unknowns = `forbid`', () => {
312312
const type = schema.object(
313313
{ foo: schema.string({ defaultValue: 'test' }) },
314-
{ allowUnknowns: false }
314+
{ unknowns: 'forbid' }
315315
);
316316
expect(() =>
317317
type.validate({
318318
bar: 'baz',
319319
})
320320
).toThrowErrorMatchingInlineSnapshot(`"[bar]: definition for this key is missing"`);
321321
});
322+
323+
test('allow and remove unknown keys when unknowns = `ignore`', () => {
324+
const type = schema.object(
325+
{ foo: schema.string({ defaultValue: 'test' }) },
326+
{ unknowns: 'ignore' }
327+
);
328+
329+
expect(
330+
type.validate({
331+
bar: 'baz',
332+
})
333+
).toEqual({
334+
foo: 'test',
335+
});
336+
});
337+
338+
test('unknowns = `ignore` affects only own keys', () => {
339+
const type = schema.object(
340+
{ foo: schema.object({ bar: schema.string() }) },
341+
{ unknowns: 'ignore' }
342+
);
343+
344+
expect(() =>
345+
type.validate({
346+
foo: {
347+
bar: 'bar',
348+
baz: 'baz',
349+
},
350+
})
351+
).toThrowErrorMatchingInlineSnapshot(`"[foo.baz]: definition for this key is missing"`);
352+
});

packages/kbn-config-schema/src/types/object_type.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,25 @@ export type TypeOf<RT extends Type<any>> = RT['type'];
3030
// this might not have perfect _rendering_ output, but it will be typed.
3131
export type ObjectResultType<P extends Props> = Readonly<{ [K in keyof P]: TypeOf<P[K]> }>;
3232

33+
interface UnknownOptions {
34+
/**
35+
* Options for dealing with unknown keys:
36+
* - allow: unknown keys will be permitted
37+
* - ignore: unknown keys will not fail validation, but will be stripped out
38+
* - forbid (default): unknown keys will fail validation
39+
*/
40+
unknowns?: 'allow' | 'ignore' | 'forbid';
41+
}
42+
3343
export type ObjectTypeOptions<P extends Props = any> = TypeOptions<
3444
{ [K in keyof P]: TypeOf<P[K]> }
35-
> & {
36-
/** Should uknown keys not be defined in the schema be allowed. Defaults to `false` */
37-
allowUnknowns?: boolean;
38-
};
45+
> &
46+
UnknownOptions;
3947

4048
export class ObjectType<P extends Props = any> extends Type<ObjectResultType<P>> {
4149
private props: Record<string, AnySchema>;
4250

43-
constructor(props: P, { allowUnknowns = false, ...typeOptions }: ObjectTypeOptions<P> = {}) {
51+
constructor(props: P, { unknowns = 'forbid', ...typeOptions }: ObjectTypeOptions<P> = {}) {
4452
const schemaKeys = {} as Record<string, AnySchema>;
4553
for (const [key, value] of Object.entries(props)) {
4654
schemaKeys[key] = value.getSchema();
@@ -50,7 +58,8 @@ export class ObjectType<P extends Props = any> extends Type<ObjectResultType<P>>
5058
.keys(schemaKeys)
5159
.default()
5260
.optional()
53-
.unknown(Boolean(allowUnknowns));
61+
.unknown(unknowns === 'allow')
62+
.options({ stripUnknown: { objects: unknowns === 'ignore' } });
5463

5564
super(schema, typeOptions);
5665
this.props = schemaKeys;

packages/kbn-test/src/functional_test_runner/cli.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,15 @@ export function runFtrCli() {
4848
kbnTestServer: {
4949
installDir: parseInstallDir(flags),
5050
},
51+
suiteFiles: {
52+
include: toArray(flags.include as string | string[]).map(makeAbsolutePath),
53+
exclude: toArray(flags.exclude as string | string[]).map(makeAbsolutePath),
54+
},
5155
suiteTags: {
5256
include: toArray(flags['include-tag'] as string | string[]),
5357
exclude: toArray(flags['exclude-tag'] as string | string[]),
5458
},
5559
updateBaselines: flags.updateBaselines,
56-
excludeTestFiles: flags.exclude || undefined,
5760
}
5861
);
5962

@@ -104,7 +107,15 @@ export function runFtrCli() {
104107
},
105108
{
106109
flags: {
107-
string: ['config', 'grep', 'exclude', 'include-tag', 'exclude-tag', 'kibana-install-dir'],
110+
string: [
111+
'config',
112+
'grep',
113+
'include',
114+
'exclude',
115+
'include-tag',
116+
'exclude-tag',
117+
'kibana-install-dir',
118+
],
108119
boolean: ['bail', 'invert', 'test-stats', 'updateBaselines', 'throttle', 'headless'],
109120
default: {
110121
config: 'test/functional/config.js',
@@ -115,7 +126,8 @@ export function runFtrCli() {
115126
--bail stop tests after the first failure
116127
--grep <pattern> pattern used to select which tests to run
117128
--invert invert grep to exclude tests
118-
--exclude=file path to a test file that should not be loaded
129+
--include=file a test file to be included, pass multiple times for multiple files
130+
--exclude=file a test file to be excluded, pass multiple times for multiple files
119131
--include-tag=tag a tag to be included, pass multiple times for multiple tags
120132
--exclude-tag=tag a tag to be excluded, pass multiple times for multiple tags
121133
--test-stats print the number of tests (included and excluded) to STDERR

packages/kbn-test/src/functional_test_runner/lib/config/schema.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,16 @@ export const schema = Joi.object()
6464
testFiles: Joi.array().items(Joi.string()),
6565
testRunner: Joi.func(),
6666

67-
excludeTestFiles: Joi.array()
68-
.items(Joi.string())
69-
.default([]),
67+
suiteFiles: Joi.object()
68+
.keys({
69+
include: Joi.array()
70+
.items(Joi.string())
71+
.default([]),
72+
exclude: Joi.array()
73+
.items(Joi.string())
74+
.default([]),
75+
})
76+
.default(),
7077

7178
suiteTags: Joi.object()
7279
.keys({

packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
* specific language governing permissions and limitations
1717
* under the License.
1818
*/
19-
19+
import { relative } from 'path';
20+
import { REPO_ROOT } from '@kbn/dev-utils';
2021
import { createAssignmentProxy } from './assignment_proxy';
2122
import { wrapFunction } from './wrap_function';
2223
import { wrapRunnableArgs } from './wrap_runnable_args';
@@ -65,6 +66,10 @@ export function decorateMochaUi(lifecycle, context) {
6566
this._tags = [].concat(this._tags || [], tags);
6667
};
6768

69+
const relativeFilePath = relative(REPO_ROOT, this.file);
70+
this.tags(relativeFilePath);
71+
this.suiteTag = relativeFilePath; // The tag that uniquely targets this suite/file
72+
6873
provider.call(this);
6974

7075
after(async () => {

packages/kbn-test/src/functional_test_runner/lib/mocha/load_test_files.js

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,12 @@ import { decorateMochaUi } from './decorate_mocha_ui';
3131
* @param {String} path
3232
* @return {undefined} - mutates mocha, no return value
3333
*/
34-
export const loadTestFiles = ({
35-
mocha,
36-
log,
37-
lifecycle,
38-
providers,
39-
paths,
40-
excludePaths,
41-
updateBaselines,
42-
}) => {
43-
const pendingExcludes = new Set(excludePaths.slice(0));
44-
34+
export const loadTestFiles = ({ mocha, log, lifecycle, providers, paths, updateBaselines }) => {
4535
const innerLoadTestFile = path => {
4636
if (typeof path !== 'string' || !isAbsolute(path)) {
4737
throw new TypeError('loadTestFile() only accepts absolute paths');
4838
}
4939

50-
if (pendingExcludes.has(path)) {
51-
pendingExcludes.delete(path);
52-
log.warning('Skipping test file %s', path);
53-
return;
54-
}
55-
5640
loadTracer(path, `testFile[${path}]`, () => {
5741
log.verbose('Loading test file %s', path);
5842

@@ -94,13 +78,4 @@ export const loadTestFiles = ({
9478
};
9579

9680
paths.forEach(innerLoadTestFile);
97-
98-
if (pendingExcludes.size) {
99-
throw new Error(
100-
`After loading all test files some exclude paths were not consumed:${[
101-
'',
102-
...pendingExcludes,
103-
].join('\n -')}`
104-
);
105-
}
10681
};

packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919

2020
import Mocha from 'mocha';
21+
import { relative } from 'path';
22+
import { REPO_ROOT } from '@kbn/dev-utils';
2123

2224
import { loadTestFiles } from './load_test_files';
2325
import { filterSuitesByTags } from './filter_suites_by_tags';
@@ -50,10 +52,20 @@ export async function setupMocha(lifecycle, log, config, providers) {
5052
lifecycle,
5153
providers,
5254
paths: config.get('testFiles'),
53-
excludePaths: config.get('excludeTestFiles'),
5455
updateBaselines: config.get('updateBaselines'),
5556
});
5657

58+
// Each suite has a tag that is the path relative to the root of the repo
59+
// So we just need to take input paths, make them relative to the root, and use them as tags
60+
// Also, this is a separate filterSuitesByTags() call so that the test suites will be filtered first by
61+
// files, then by tags. This way, you can target tags (like smoke) in a specific file.
62+
filterSuitesByTags({
63+
log,
64+
mocha,
65+
include: config.get('suiteFiles.include').map(file => relative(REPO_ROOT, file)),
66+
exclude: config.get('suiteFiles.exclude').map(file => relative(REPO_ROOT, file)),
67+
});
68+
5769
filterSuitesByTags({
5870
log,
5971
mocha,

0 commit comments

Comments
 (0)