diff --git a/package.json b/package.json
index 03958f44c2fa9..26405562de226 100644
--- a/package.json
+++ b/package.json
@@ -427,6 +427,7 @@
"devDependencies": {
"@babel/cli": "^7.12.10",
"@babel/core": "^7.12.10",
+ "@babel/generator": "^7.12.11",
"@babel/parser": "^7.12.11",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-export-namespace-from": "^7.12.1",
@@ -651,6 +652,7 @@
"@types/yauzl": "^2.9.1",
"@types/zen-observable": "^0.8.0",
"@typescript-eslint/eslint-plugin": "^4.14.1",
+ "@typescript-eslint/typescript-estree": "^4.14.1",
"@typescript-eslint/parser": "^4.14.1",
"@yarnpkg/lockfile": "^1.1.0",
"abab": "^2.0.4",
@@ -720,6 +722,7 @@
"eslint-plugin-react": "^7.20.3",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-react-perf": "^3.2.3",
+ "eslint-traverse": "^1.0.0",
"expose-loader": "^0.7.5",
"faker": "^5.1.0",
"fancy-log": "^1.3.2",
diff --git a/packages/elastic-eslint-config-kibana/.eslintrc.js b/packages/elastic-eslint-config-kibana/.eslintrc.js
index 0e686d01e2b8b..4b5c3c372fa23 100644
--- a/packages/elastic-eslint-config-kibana/.eslintrc.js
+++ b/packages/elastic-eslint-config-kibana/.eslintrc.js
@@ -82,5 +82,7 @@ module.exports = {
}
],
],
+
+ '@kbn/eslint/no_async_promise_body': 'error',
},
};
diff --git a/packages/kbn-eslint-plugin-eslint/index.js b/packages/kbn-eslint-plugin-eslint/index.js
index e5a38e5f09529..a7a9c6b5bebdf 100644
--- a/packages/kbn-eslint-plugin-eslint/index.js
+++ b/packages/kbn-eslint-plugin-eslint/index.js
@@ -12,5 +12,6 @@ module.exports = {
'disallow-license-headers': require('./rules/disallow_license_headers'),
'no-restricted-paths': require('./rules/no_restricted_paths'),
module_migration: require('./rules/module_migration'),
+ no_async_promise_body: require('./rules/no_async_promise_body'),
},
};
diff --git a/packages/kbn-eslint-plugin-eslint/rules/no_async_promise_body.js b/packages/kbn-eslint-plugin-eslint/rules/no_async_promise_body.js
new file mode 100644
index 0000000000000..317758fd3629a
--- /dev/null
+++ b/packages/kbn-eslint-plugin-eslint/rules/no_async_promise_body.js
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+const { parseExpression } = require('@babel/parser');
+const { default: generate } = require('@babel/generator');
+const tsEstree = require('@typescript-eslint/typescript-estree');
+const traverse = require('eslint-traverse');
+const esTypes = tsEstree.AST_NODE_TYPES;
+const babelTypes = require('@babel/types');
+
+/** @typedef {import("eslint").Rule.RuleModule} Rule */
+/** @typedef {import("@typescript-eslint/parser").ParserServices} ParserServices */
+/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.Expression} Expression */
+/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.ArrowFunctionExpression} ArrowFunctionExpression */
+/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.FunctionExpression} FunctionExpression */
+/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.TryStatement} TryStatement */
+/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.NewExpression} NewExpression */
+/** @typedef {import("typescript").ExportDeclaration} ExportDeclaration */
+/** @typedef {import("eslint").Rule.RuleFixer} Fixer */
+
+const ERROR_MSG =
+ 'Passing an async function to the Promise constructor leads to a hidden promise being created and prevents handling rejections';
+
+/**
+ * @param {Expression} node
+ */
+const isPromise = (node) => node.type === esTypes.Identifier && node.name === 'Promise';
+
+/**
+ * @param {Expression} node
+ * @returns {node is ArrowFunctionExpression | FunctionExpression}
+ */
+const isFunc = (node) =>
+ node.type === esTypes.ArrowFunctionExpression || node.type === esTypes.FunctionExpression;
+
+/**
+ * @param {any} context
+ * @param {ArrowFunctionExpression | FunctionExpression} node
+ */
+const isFuncBodySafe = (context, node) => {
+ // if the body isn't wrapped in a blockStatement it can't have a try/catch at the root
+ if (node.body.type !== esTypes.BlockStatement) {
+ return false;
+ }
+
+ // when the entire body is wrapped in a try/catch it is the only node
+ if (node.body.body.length !== 1) {
+ return false;
+ }
+
+ const tryNode = node.body.body[0];
+ // ensure we have a try node with a handler
+ if (tryNode.type !== esTypes.TryStatement || !tryNode.handler) {
+ return false;
+ }
+
+ // ensure the handler doesn't throw
+ let hasThrow = false;
+ traverse(context, tryNode.handler, (path) => {
+ if (path.node.type === esTypes.ThrowStatement) {
+ hasThrow = true;
+ return traverse.STOP;
+ }
+ });
+ return !hasThrow;
+};
+
+/**
+ * @param {string} code
+ */
+const wrapFunctionInTryCatch = (code) => {
+ // parse the code with babel so we can mutate the AST
+ const ast = parseExpression(code, {
+ plugins: ['typescript', 'jsx'],
+ });
+
+ // validate that the code reperesents an arrow or function expression
+ if (!babelTypes.isArrowFunctionExpression(ast) && !babelTypes.isFunctionExpression(ast)) {
+ throw new Error('expected function to be an arrow or function expression');
+ }
+
+ // ensure that the function receives the second argument, and capture its name if already defined
+ let rejectName = 'reject';
+ if (ast.params.length === 0) {
+ ast.params.push(babelTypes.identifier('resolve'), babelTypes.identifier(rejectName));
+ } else if (ast.params.length === 1) {
+ ast.params.push(babelTypes.identifier(rejectName));
+ } else if (ast.params.length === 2) {
+ if (babelTypes.isIdentifier(ast.params[1])) {
+ rejectName = ast.params[1].name;
+ } else {
+ throw new Error('expected second param of promise definition function to be an identifier');
+ }
+ }
+
+ // ensure that the body of the function is a blockStatement
+ let block = ast.body;
+ if (!babelTypes.isBlockStatement(block)) {
+ block = babelTypes.blockStatement([babelTypes.returnStatement(block)]);
+ }
+
+ // redefine the body of the function as a new blockStatement containing a tryStatement
+ // which catches errors and forwards them to reject() when caught
+ ast.body = babelTypes.blockStatement([
+ // try {
+ babelTypes.tryStatement(
+ block,
+ // catch (error) {
+ babelTypes.catchClause(
+ babelTypes.identifier('error'),
+ babelTypes.blockStatement([
+ // reject(error)
+ babelTypes.expressionStatement(
+ babelTypes.callExpression(babelTypes.identifier(rejectName), [
+ babelTypes.identifier('error'),
+ ])
+ ),
+ ])
+ )
+ ),
+ ]);
+
+ return generate(ast).code;
+};
+
+/** @type {Rule} */
+module.exports = {
+ meta: {
+ fixable: 'code',
+ schema: [],
+ },
+ create: (context) => ({
+ NewExpression(_) {
+ const node = /** @type {NewExpression} */ (_);
+
+ // ensure we are newing up a promise with a single argument
+ if (!isPromise(node.callee) || node.arguments.length !== 1) {
+ return;
+ }
+
+ const func = node.arguments[0];
+ // ensure the argument is an arrow or function expression and is async
+ if (!isFunc(func) || !func.async) {
+ return;
+ }
+
+ // body must be a blockStatement, try/catch can't exist outside of a block
+ if (!isFuncBodySafe(context, func)) {
+ context.report({
+ message: ERROR_MSG,
+ loc: func.loc,
+ fix(fixer) {
+ const source = context.getSourceCode();
+ return fixer.replaceText(func, wrapFunctionInTryCatch(source.getText(func)));
+ },
+ });
+ }
+ },
+ }),
+};
diff --git a/packages/kbn-eslint-plugin-eslint/rules/no_async_promise_body.test.js b/packages/kbn-eslint-plugin-eslint/rules/no_async_promise_body.test.js
new file mode 100644
index 0000000000000..f5929b1b3966f
--- /dev/null
+++ b/packages/kbn-eslint-plugin-eslint/rules/no_async_promise_body.test.js
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ */
+
+const { RuleTester } = require('eslint');
+const rule = require('./no_async_promise_body');
+const dedent = require('dedent');
+
+const ruleTester = new RuleTester({
+ parser: require.resolve('@typescript-eslint/parser'),
+ parserOptions: {
+ sourceType: 'module',
+ ecmaVersion: 2018,
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+});
+
+ruleTester.run('@kbn/eslint/no_async_promise_body', rule, {
+ valid: [
+ // caught but no resolve
+ {
+ code: dedent`
+ new Promise(async function (resolve) {
+ try {
+ await asyncOperation();
+ } catch (error) {
+ // noop
+ }
+ })
+ `,
+ },
+ // arrow caught but no resolve
+ {
+ code: dedent`
+ new Promise(async (resolve) => {
+ try {
+ await asyncOperation();
+ } catch (error) {
+ // noop
+ }
+ })
+ `,
+ },
+ // caught with reject
+ {
+ code: dedent`
+ new Promise(async function (resolve, reject) {
+ try {
+ await asyncOperation();
+ } catch (error) {
+ reject(error)
+ }
+ })
+ `,
+ },
+ // arrow caught with reject
+ {
+ code: dedent`
+ new Promise(async (resolve, reject) => {
+ try {
+ await asyncOperation();
+ } catch (error) {
+ reject(error)
+ }
+ })
+ `,
+ },
+ // non async
+ {
+ code: dedent`
+ new Promise(function (resolve) {
+ setTimeout(resolve, 10);
+ })
+ `,
+ },
+ // arrow non async
+ {
+ code: dedent`
+ new Promise((resolve) => setTimeout(resolve, 10))
+ `,
+ },
+ ],
+
+ invalid: [
+ // no catch
+ {
+ code: dedent`
+ new Promise(async function (resolve) {
+ const result = await asyncOperation();
+ resolve(result);
+ })
+ `,
+ errors: [
+ {
+ line: 1,
+ message:
+ 'Passing an async function to the Promise constructor leads to a hidden promise being created and prevents handling rejections',
+ },
+ ],
+ output: dedent`
+ new Promise(async function (resolve, reject) {
+ try {
+ const result = await asyncOperation();
+ resolve(result);
+ } catch (error) {
+ reject(error);
+ }
+ })
+ `,
+ },
+ // arrow no catch
+ {
+ code: dedent`
+ new Promise(async (resolve) => {
+ const result = await asyncOperation();
+ resolve(result);
+ })
+ `,
+ errors: [
+ {
+ line: 1,
+ message:
+ 'Passing an async function to the Promise constructor leads to a hidden promise being created and prevents handling rejections',
+ },
+ ],
+ output: dedent`
+ new Promise(async (resolve, reject) => {
+ try {
+ const result = await asyncOperation();
+ resolve(result);
+ } catch (error) {
+ reject(error);
+ }
+ })
+ `,
+ },
+ // catch, but it throws
+ {
+ code: dedent`
+ new Promise(async function (resolve) {
+ try {
+ const result = await asyncOperation();
+ resolve(result);
+ } catch (error) {
+ if (error.code === 'foo') {
+ throw error;
+ }
+ }
+ })
+ `,
+ errors: [
+ {
+ line: 1,
+ message:
+ 'Passing an async function to the Promise constructor leads to a hidden promise being created and prevents handling rejections',
+ },
+ ],
+ output: dedent`
+ new Promise(async function (resolve, reject) {
+ try {
+ try {
+ const result = await asyncOperation();
+ resolve(result);
+ } catch (error) {
+ if (error.code === 'foo') {
+ throw error;
+ }
+ }
+ } catch (error) {
+ reject(error);
+ }
+ })
+ `,
+ },
+ // no catch without block
+ {
+ code: dedent`
+ new Promise(async (resolve) => resolve(await asyncOperation()));
+ `,
+ errors: [
+ {
+ line: 1,
+ message:
+ 'Passing an async function to the Promise constructor leads to a hidden promise being created and prevents handling rejections',
+ },
+ ],
+ output: dedent`
+ new Promise(async (resolve, reject) => {
+ try {
+ return resolve(await asyncOperation());
+ } catch (error) {
+ reject(error);
+ }
+ });
+ `,
+ },
+ // no catch with named reject
+ {
+ code: dedent`
+ new Promise(async (resolve, rej) => {
+ const result = await asyncOperation();
+ result ? resolve(true) : rej()
+ });
+ `,
+ errors: [
+ {
+ line: 1,
+ message:
+ 'Passing an async function to the Promise constructor leads to a hidden promise being created and prevents handling rejections',
+ },
+ ],
+ output: dedent`
+ new Promise(async (resolve, rej) => {
+ try {
+ const result = await asyncOperation();
+ result ? resolve(true) : rej();
+ } catch (error) {
+ rej(error);
+ }
+ });
+ `,
+ },
+ // no catch with no args
+ {
+ code: dedent`
+ new Promise(async () => {
+ await asyncOperation();
+ });
+ `,
+ errors: [
+ {
+ line: 1,
+ message:
+ 'Passing an async function to the Promise constructor leads to a hidden promise being created and prevents handling rejections',
+ },
+ ],
+ output: dedent`
+ new Promise(async (resolve, reject) => {
+ try {
+ await asyncOperation();
+ } catch (error) {
+ reject(error);
+ }
+ });
+ `,
+ },
+ ],
+});
diff --git a/src/core/public/application/integration_tests/utils.tsx b/src/core/public/application/integration_tests/utils.tsx
index dcf071719c11a..455d19956f7e8 100644
--- a/src/core/public/application/integration_tests/utils.tsx
+++ b/src/core/public/application/integration_tests/utils.tsx
@@ -21,13 +21,18 @@ export const createRenderer = (element: ReactElement | null): Renderer => {
const dom: Dom = element && mount({element});
return () =>
- new Promise(async (resolve) => {
- if (dom) {
- await act(async () => {
- dom.update();
- });
+ new Promise(async (resolve, reject) => {
+ try {
+ if (dom) {
+ await act(async () => {
+ dom.update();
+ });
+ }
+
+ setImmediate(() => resolve(dom)); // flushes any pending promises
+ } catch (error) {
+ reject(error);
}
- setImmediate(() => resolve(dom)); // flushes any pending promises
});
};
diff --git a/src/core/public/application/ui/app_container.test.tsx b/src/core/public/application/ui/app_container.test.tsx
index 86cb9198e0699..4c056e748f06e 100644
--- a/src/core/public/application/ui/app_container.test.tsx
+++ b/src/core/public/application/ui/app_container.test.tsx
@@ -27,8 +27,12 @@ describe('AppContainer', () => {
});
const flushPromises = async () => {
- await new Promise(async (resolve) => {
- setImmediate(() => resolve());
+ await new Promise(async (resolve, reject) => {
+ try {
+ setImmediate(() => resolve());
+ } catch (error) {
+ reject(error);
+ }
});
};
diff --git a/src/core/public/chrome/ui/header/header_action_menu.test.tsx b/src/core/public/chrome/ui/header/header_action_menu.test.tsx
index 386e48e745e80..201be8848bac8 100644
--- a/src/core/public/chrome/ui/header/header_action_menu.test.tsx
+++ b/src/core/public/chrome/ui/header/header_action_menu.test.tsx
@@ -26,13 +26,18 @@ describe('HeaderActionMenu', () => {
});
const refresh = () => {
- new Promise(async (resolve) => {
- if (component) {
- act(() => {
- component.update();
- });
+ new Promise(async (resolve, reject) => {
+ try {
+ if (component) {
+ act(() => {
+ component.update();
+ });
+ }
+
+ setImmediate(() => resolve(component)); // flushes any pending promises
+ } catch (error) {
+ reject(error);
}
- setImmediate(() => resolve(component)); // flushes any pending promises
});
};
diff --git a/src/plugins/kibana_react/public/util/mount_point_portal.test.tsx b/src/plugins/kibana_react/public/util/mount_point_portal.test.tsx
index 53503b197567e..39e345568a298 100644
--- a/src/plugins/kibana_react/public/util/mount_point_portal.test.tsx
+++ b/src/plugins/kibana_react/public/util/mount_point_portal.test.tsx
@@ -19,13 +19,18 @@ describe('MountPointPortal', () => {
let dom: ReactWrapper;
const refresh = () => {
- new Promise(async (resolve) => {
- if (dom) {
- act(() => {
- dom.update();
- });
+ new Promise(async (resolve, reject) => {
+ try {
+ if (dom) {
+ act(() => {
+ dom.update();
+ });
+ }
+
+ setImmediate(() => resolve(dom)); // flushes any pending promises
+ } catch (error) {
+ reject(error);
}
- setImmediate(() => resolve(dom)); // flushes any pending promises
});
};
diff --git a/src/plugins/maps_ems/public/lazy_load_bundle/get_service_settings.ts b/src/plugins/maps_ems/public/lazy_load_bundle/get_service_settings.ts
index 6e32ff5d4e41e..8eafada176e7a 100644
--- a/src/plugins/maps_ems/public/lazy_load_bundle/get_service_settings.ts
+++ b/src/plugins/maps_ems/public/lazy_load_bundle/get_service_settings.ts
@@ -16,10 +16,14 @@ export async function getServiceSettings(): Promise {
return loadPromise;
}
- loadPromise = new Promise(async (resolve) => {
- const { ServiceSettings } = await import('./lazy');
- const config = getMapsEmsConfig();
- resolve(new ServiceSettings(config, config.tilemap));
+ loadPromise = new Promise(async (resolve, reject) => {
+ try {
+ const { ServiceSettings } = await import('./lazy');
+ const config = getMapsEmsConfig();
+ resolve(new ServiceSettings(config, config.tilemap));
+ } catch (error) {
+ reject(error);
+ }
});
return loadPromise;
}
diff --git a/src/plugins/maps_legacy/public/lazy_load_bundle/index.ts b/src/plugins/maps_legacy/public/lazy_load_bundle/index.ts
index b1509c4effa7a..0017849408efb 100644
--- a/src/plugins/maps_legacy/public/lazy_load_bundle/index.ts
+++ b/src/plugins/maps_legacy/public/lazy_load_bundle/index.ts
@@ -18,13 +18,16 @@ export async function lazyLoadMapsLegacyModules(): Promise {
- const { KibanaMap, L } = await import('./lazy');
-
- resolve({
- KibanaMap,
- L,
- });
+ loadModulesPromise = new Promise(async (resolve, reject) => {
+ try {
+ const { KibanaMap, L } = await import('./lazy');
+ resolve({
+ KibanaMap,
+ L,
+ });
+ } catch (error) {
+ reject(error);
+ }
});
return loadModulesPromise;
}
diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx
index 558739a44dd41..45b9b4c7a885b 100644
--- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx
+++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx
@@ -109,13 +109,18 @@ describe('TopNavMenu', () => {
let dom: ReactWrapper;
const refresh = () => {
- new Promise(async (resolve) => {
- if (dom) {
- act(() => {
- dom.update();
- });
+ new Promise(async (resolve, reject) => {
+ try {
+ if (dom) {
+ act(() => {
+ dom.update();
+ });
+ }
+
+ setImmediate(() => resolve(dom)); // flushes any pending promises
+ } catch (error) {
+ reject(error);
}
- setImmediate(() => resolve(dom)); // flushes any pending promises
});
};
diff --git a/src/plugins/vis_type_table/public/legacy/vis_controller.ts b/src/plugins/vis_type_table/public/legacy/vis_controller.ts
index ee446c58c0013..e7b1940ec3e1f 100644
--- a/src/plugins/vis_type_table/public/legacy/vis_controller.ts
+++ b/src/plugins/vis_type_table/public/legacy/vis_controller.ts
@@ -70,35 +70,42 @@ export function getTableVisualizationControllerClass(
await this.initLocalAngular();
return new Promise(async (resolve, reject) => {
- if (!this.$rootScope) {
- const $injector = this.getInjector();
- this.$rootScope = $injector.get('$rootScope');
- this.$compile = $injector.get('$compile');
- }
- const updateScope = () => {
- if (!this.$scope) {
- return;
+ try {
+ if (!this.$rootScope) {
+ const $injector = this.getInjector();
+ this.$rootScope = $injector.get('$rootScope');
+ this.$compile = $injector.get('$compile');
}
- this.$scope.visState = { params: visParams, title: visParams.title };
- this.$scope.esResponse = esResponse;
-
- this.$scope.visParams = visParams;
- this.$scope.renderComplete = resolve;
- this.$scope.renderFailed = reject;
- this.$scope.resize = Date.now();
- this.$scope.$apply();
- };
-
- if (!this.$scope && this.$compile) {
- this.$scope = this.$rootScope.$new();
- this.$scope.uiState = handlers.uiState;
- this.$scope.filter = handlers.event;
- updateScope();
- this.el.find('div').append(this.$compile(tableVisTemplate)(this.$scope));
- this.$scope.$apply();
- } else {
- updateScope();
+ const updateScope = () => {
+ if (!this.$scope) {
+ return;
+ }
+
+ this.$scope.visState = {
+ params: visParams,
+ title: visParams.title,
+ };
+ this.$scope.esResponse = esResponse;
+ this.$scope.visParams = visParams;
+ this.$scope.renderComplete = resolve;
+ this.$scope.renderFailed = reject;
+ this.$scope.resize = Date.now();
+ this.$scope.$apply();
+ };
+
+ if (!this.$scope && this.$compile) {
+ this.$scope = this.$rootScope.$new();
+ this.$scope.uiState = handlers.uiState;
+ this.$scope.filter = handlers.event;
+ updateScope();
+ this.el.find('div').append(this.$compile(tableVisTemplate)(this.$scope));
+ this.$scope.$apply();
+ } else {
+ updateScope();
+ }
+ } catch (error) {
+ reject(error);
}
});
}
diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx
index 9ce5a5339c04f..2c26dfc3ae276 100644
--- a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx
+++ b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx
@@ -124,16 +124,25 @@ export class VisLegend extends PureComponent {
};
setFilterableLabels = (items: LegendItem[]): Promise =>
- new Promise(async (resolve) => {
- const filterableLabels = new Set();
- items.forEach(async (item) => {
- const canFilter = await this.canFilter(item);
- if (canFilter) {
- filterableLabels.add(item.label);
- }
- });
-
- this.setState({ filterableLabels }, resolve);
+ new Promise(async (resolve, reject) => {
+ try {
+ const filterableLabels = new Set();
+ items.forEach(async (item) => {
+ const canFilter = await this.canFilter(item);
+
+ if (canFilter) {
+ filterableLabels.add(item.label);
+ }
+ });
+ this.setState(
+ {
+ filterableLabels,
+ },
+ resolve
+ );
+ } catch (error) {
+ reject(error);
+ }
});
setLabels = (data: any, type: string) => {
diff --git a/x-pack/plugins/data_visualizer/public/lazy_load_bundle/index.ts b/x-pack/plugins/data_visualizer/public/lazy_load_bundle/index.ts
index 57f0872d62589..f04c611c2fae9 100644
--- a/x-pack/plugins/data_visualizer/public/lazy_load_bundle/index.ts
+++ b/x-pack/plugins/data_visualizer/public/lazy_load_bundle/index.ts
@@ -22,13 +22,13 @@ export async function lazyLoadModules(): Promise {
return loadModulesPromise;
}
- loadModulesPromise = new Promise(async (resolve) => {
- const lazyImports = await import('./lazy');
-
- resolve({
- ...lazyImports,
- getHttp: () => getCoreStart().http,
- });
+ loadModulesPromise = new Promise(async (resolve, reject) => {
+ try {
+ const lazyImports = await import('./lazy');
+ resolve({ ...lazyImports, getHttp: () => getCoreStart().http });
+ } catch (error) {
+ reject(error);
+ }
});
return loadModulesPromise;
}
diff --git a/x-pack/plugins/file_upload/public/lazy_load_bundle/index.ts b/x-pack/plugins/file_upload/public/lazy_load_bundle/index.ts
index 9c7c6ff1e5180..192a7ffb5e782 100644
--- a/x-pack/plugins/file_upload/public/lazy_load_bundle/index.ts
+++ b/x-pack/plugins/file_upload/public/lazy_load_bundle/index.ts
@@ -44,15 +44,18 @@ export async function lazyLoadModules(): Promise {
return loadModulesPromise;
}
- loadModulesPromise = new Promise(async (resolve) => {
- const { JsonUploadAndParse, importerFactory, IndexNameForm } = await import('./lazy');
-
- resolve({
- JsonUploadAndParse,
- importerFactory,
- getHttp,
- IndexNameForm,
- });
+ loadModulesPromise = new Promise(async (resolve, reject) => {
+ try {
+ const { JsonUploadAndParse, importerFactory, IndexNameForm } = await import('./lazy');
+ resolve({
+ JsonUploadAndParse,
+ importerFactory,
+ getHttp,
+ IndexNameForm,
+ });
+ } catch (error) {
+ reject(error);
+ }
});
return loadModulesPromise;
}
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/use_state_listener.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/use_state_listener.tsx
index 540da3e2b9fdc..cf1f9e1bc39e8 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/use_state_listener.tsx
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/use_state_listener.tsx
@@ -107,17 +107,25 @@ export const useMappingsStateListener = ({ onChange, value, mappingsType }: Args
validate: async () => {
const configurationFormValidator =
state.configuration.submitForm !== undefined
- ? new Promise(async (resolve) => {
- const { isValid } = await state.configuration.submitForm!();
- resolve(isValid);
+ ? new Promise(async (resolve, reject) => {
+ try {
+ const { isValid } = await state.configuration.submitForm!();
+ resolve(isValid);
+ } catch (error) {
+ reject(error);
+ }
})
: Promise.resolve(true);
const templatesFormValidator =
state.templates.submitForm !== undefined
- ? new Promise(async (resolve) => {
- const { isValid } = await state.templates.submitForm!();
- resolve(isValid);
+ ? new Promise(async (resolve, reject) => {
+ try {
+ const { isValid } = await state.templates.submitForm!();
+ resolve(isValid);
+ } catch (error) {
+ reject(error);
+ }
})
: Promise.resolve(true);
diff --git a/x-pack/plugins/maps/public/lazy_load_bundle/index.ts b/x-pack/plugins/maps/public/lazy_load_bundle/index.ts
index 3e5e2d54422d6..c1095e9a61c57 100644
--- a/x-pack/plugins/maps/public/lazy_load_bundle/index.ts
+++ b/x-pack/plugins/maps/public/lazy_load_bundle/index.ts
@@ -83,36 +83,39 @@ export async function lazyLoadMapModules(): Promise {
return loadModulesPromise;
}
- loadModulesPromise = new Promise(async (resolve) => {
- const {
- MapEmbeddable,
- getIndexPatternService,
- getMapsCapabilities,
- renderApp,
- createSecurityLayerDescriptors,
- registerLayerWizard,
- registerSource,
- createTileMapLayerDescriptor,
- createRegionMapLayerDescriptor,
- createBasemapLayerDescriptor,
- createESSearchSourceLayerDescriptor,
- suggestEMSTermJoinConfig,
- } = await import('./lazy');
-
- resolve({
- MapEmbeddable,
- getIndexPatternService,
- getMapsCapabilities,
- renderApp,
- createSecurityLayerDescriptors,
- registerLayerWizard,
- registerSource,
- createTileMapLayerDescriptor,
- createRegionMapLayerDescriptor,
- createBasemapLayerDescriptor,
- createESSearchSourceLayerDescriptor,
- suggestEMSTermJoinConfig,
- });
+ loadModulesPromise = new Promise(async (resolve, reject) => {
+ try {
+ const {
+ MapEmbeddable,
+ getIndexPatternService,
+ getMapsCapabilities,
+ renderApp,
+ createSecurityLayerDescriptors,
+ registerLayerWizard,
+ registerSource,
+ createTileMapLayerDescriptor,
+ createRegionMapLayerDescriptor,
+ createBasemapLayerDescriptor,
+ createESSearchSourceLayerDescriptor,
+ suggestEMSTermJoinConfig,
+ } = await import('./lazy');
+ resolve({
+ MapEmbeddable,
+ getIndexPatternService,
+ getMapsCapabilities,
+ renderApp,
+ createSecurityLayerDescriptors,
+ registerLayerWizard,
+ registerSource,
+ createTileMapLayerDescriptor,
+ createRegionMapLayerDescriptor,
+ createBasemapLayerDescriptor,
+ createESSearchSourceLayerDescriptor,
+ suggestEMSTermJoinConfig,
+ });
+ } catch (error) {
+ reject(error);
+ }
});
return loadModulesPromise;
}
diff --git a/x-pack/plugins/ml/public/application/services/new_job_capabilities/load_new_job_capabilities.ts b/x-pack/plugins/ml/public/application/services/new_job_capabilities/load_new_job_capabilities.ts
index a998343535249..d3b407c2bb65a 100644
--- a/x-pack/plugins/ml/public/application/services/new_job_capabilities/load_new_job_capabilities.ts
+++ b/x-pack/plugins/ml/public/application/services/new_job_capabilities/load_new_job_capabilities.ts
@@ -23,27 +23,34 @@ export function loadNewJobCapabilities(
jobType: JobType
) {
return new Promise(async (resolve, reject) => {
- const serviceToUse =
- jobType === ANOMALY_DETECTOR ? newJobCapsService : newJobCapsServiceAnalytics;
- if (indexPatternId !== undefined) {
- // index pattern is being used
- const indexPattern: IIndexPattern = await indexPatterns.get(indexPatternId);
- await serviceToUse.initializeFromIndexPattern(indexPattern);
- resolve(serviceToUse.newJobCaps);
- } else if (savedSearchId !== undefined) {
- // saved search is being used
- // load the index pattern from the saved search
- const { indexPattern } = await getIndexPatternAndSavedSearch(savedSearchId);
- if (indexPattern === null) {
- // eslint-disable-next-line no-console
- console.error('Cannot retrieve index pattern from saved search');
+ try {
+ const serviceToUse =
+ jobType === ANOMALY_DETECTOR ? newJobCapsService : newJobCapsServiceAnalytics;
+
+ if (indexPatternId !== undefined) {
+ // index pattern is being used
+ const indexPattern: IIndexPattern = await indexPatterns.get(indexPatternId);
+ await serviceToUse.initializeFromIndexPattern(indexPattern);
+ resolve(serviceToUse.newJobCaps);
+ } else if (savedSearchId !== undefined) {
+ // saved search is being used
+ // load the index pattern from the saved search
+ const { indexPattern } = await getIndexPatternAndSavedSearch(savedSearchId);
+
+ if (indexPattern === null) {
+ // eslint-disable-next-line no-console
+ console.error('Cannot retrieve index pattern from saved search');
+ reject();
+ return;
+ }
+
+ await serviceToUse.initializeFromIndexPattern(indexPattern);
+ resolve(serviceToUse.newJobCaps);
+ } else {
reject();
- return;
}
- await serviceToUse.initializeFromIndexPattern(indexPattern);
- resolve(serviceToUse.newJobCaps);
- } else {
- reject();
+ } catch (error) {
+ reject(error);
}
});
}
diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_setup_flyout.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_setup_flyout.tsx
index eb39ba4ab29aa..5090274ca7383 100644
--- a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_setup_flyout.tsx
+++ b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_setup_flyout.tsx
@@ -25,33 +25,34 @@ export async function resolveEmbeddableAnomalyChartsUserInput(
const anomalyDetectorService = new AnomalyDetectorService(new HttpService(http));
return new Promise(async (resolve, reject) => {
- const { jobIds } = await resolveJobSelection(coreStart, input?.jobIds);
-
- const title = input?.title ?? getDefaultExplorerChartsPanelTitle(jobIds);
- const jobs = await anomalyDetectorService.getJobs$(jobIds).toPromise();
- const influencers = anomalyDetectorService.extractInfluencers(jobs);
- influencers.push(VIEW_BY_JOB_LABEL);
-
- const modalSession = overlays.openModal(
- toMountPoint(
- {
- modalSession.close();
-
- resolve({
- jobIds,
- title: panelTitle,
- maxSeriesToPlot,
- });
- }}
- onCancel={() => {
- modalSession.close();
- reject();
- }}
- />
- )
- );
+ try {
+ const { jobIds } = await resolveJobSelection(coreStart, input?.jobIds);
+ const title = input?.title ?? getDefaultExplorerChartsPanelTitle(jobIds);
+ const jobs = await anomalyDetectorService.getJobs$(jobIds).toPromise();
+ const influencers = anomalyDetectorService.extractInfluencers(jobs);
+ influencers.push(VIEW_BY_JOB_LABEL);
+ const modalSession = overlays.openModal(
+ toMountPoint(
+ {
+ modalSession.close();
+ resolve({
+ jobIds,
+ title: panelTitle,
+ maxSeriesToPlot,
+ });
+ }}
+ onCancel={() => {
+ modalSession.close();
+ reject();
+ }}
+ />
+ )
+ );
+ } catch (error) {
+ reject(error);
+ }
});
}
diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_setup_flyout.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_setup_flyout.tsx
index e183907def57b..5027eb6783a64 100644
--- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_setup_flyout.tsx
+++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_setup_flyout.tsx
@@ -25,31 +25,36 @@ export async function resolveAnomalySwimlaneUserInput(
const anomalyDetectorService = new AnomalyDetectorService(new HttpService(http));
return new Promise(async (resolve, reject) => {
- const { jobIds } = await resolveJobSelection(coreStart, input?.jobIds);
-
- const title = input?.title ?? getDefaultSwimlanePanelTitle(jobIds);
-
- const jobs = await anomalyDetectorService.getJobs$(jobIds).toPromise();
-
- const influencers = anomalyDetectorService.extractInfluencers(jobs);
- influencers.push(VIEW_BY_JOB_LABEL);
-
- const modalSession = overlays.openModal(
- toMountPoint(
- {
- modalSession.close();
- resolve({ jobIds, title: panelTitle, swimlaneType, viewBy });
- }}
- onCancel={() => {
- modalSession.close();
- reject();
- }}
- />
- )
- );
+ try {
+ const { jobIds } = await resolveJobSelection(coreStart, input?.jobIds);
+ const title = input?.title ?? getDefaultSwimlanePanelTitle(jobIds);
+ const jobs = await anomalyDetectorService.getJobs$(jobIds).toPromise();
+ const influencers = anomalyDetectorService.extractInfluencers(jobs);
+ influencers.push(VIEW_BY_JOB_LABEL);
+ const modalSession = overlays.openModal(
+ toMountPoint(
+ {
+ modalSession.close();
+ resolve({
+ jobIds,
+ title: panelTitle,
+ swimlaneType,
+ viewBy,
+ });
+ }}
+ onCancel={() => {
+ modalSession.close();
+ reject();
+ }}
+ />
+ )
+ );
+ } catch (error) {
+ reject(error);
+ }
});
}
diff --git a/x-pack/plugins/ml/public/embeddables/common/resolve_job_selection.tsx b/x-pack/plugins/ml/public/embeddables/common/resolve_job_selection.tsx
index 1833883447859..fbceeb7f7cf79 100644
--- a/x-pack/plugins/ml/public/embeddables/common/resolve_job_selection.tsx
+++ b/x-pack/plugins/ml/public/embeddables/common/resolve_job_selection.tsx
@@ -38,56 +38,65 @@ export async function resolveJobSelection(
} = coreStart;
return new Promise(async (resolve, reject) => {
- const maps = {
- groupsMap: getInitialGroupsMap([]),
- jobsMap: {},
- };
+ try {
+ const maps = {
+ groupsMap: getInitialGroupsMap([]),
+ jobsMap: {},
+ };
+ const tzConfig = uiSettings.get('dateFormat:tz');
+ const dateFormatTz = tzConfig !== 'Browser' ? tzConfig : moment.tz.guess();
- const tzConfig = uiSettings.get('dateFormat:tz');
- const dateFormatTz = tzConfig !== 'Browser' ? tzConfig : moment.tz.guess();
+ const onFlyoutClose = () => {
+ flyoutSession.close();
+ reject();
+ };
- const onFlyoutClose = () => {
- flyoutSession.close();
- reject();
- };
+ const onSelectionConfirmed = async ({
+ jobIds,
+ groups,
+ }: {
+ jobIds: string[];
+ groups: Array<{
+ groupId: string;
+ jobIds: string[];
+ }>;
+ }) => {
+ await flyoutSession.close();
+ resolve({
+ jobIds,
+ groups,
+ });
+ };
- const onSelectionConfirmed = async ({
- jobIds,
- groups,
- }: {
- jobIds: string[];
- groups: Array<{ groupId: string; jobIds: string[] }>;
- }) => {
- await flyoutSession.close();
- resolve({ jobIds, groups });
- };
- const flyoutSession = coreStart.overlays.openFlyout(
- toMountPoint(
-
-
-
- ),
- {
- 'data-test-subj': 'mlFlyoutJobSelector',
- ownFocus: true,
- closeButtonAriaLabel: 'jobSelectorFlyout',
- }
- );
+ const flyoutSession = coreStart.overlays.openFlyout(
+ toMountPoint(
+
+
+
+ ),
+ {
+ 'data-test-subj': 'mlFlyoutJobSelector',
+ ownFocus: true,
+ closeButtonAriaLabel: 'jobSelectorFlyout',
+ }
+ ); // Close the flyout when user navigates out of the dashboard plugin
- // Close the flyout when user navigates out of the dashboard plugin
- currentAppId$.pipe(takeUntil(from(flyoutSession.onClose))).subscribe((appId) => {
- if (appId !== DashboardConstants.DASHBOARDS_ID) {
- flyoutSession.close();
- }
- });
+ currentAppId$.pipe(takeUntil(from(flyoutSession.onClose))).subscribe((appId) => {
+ if (appId !== DashboardConstants.DASHBOARDS_ID) {
+ flyoutSession.close();
+ }
+ });
+ } catch (error) {
+ reject(error);
+ }
});
}
diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js b/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js
index 32662ae0efa34..a4645edda73d0 100644
--- a/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js
+++ b/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js
@@ -98,27 +98,39 @@ async function getPaginatedThroughputData(pipelines, req, lsIndexPattern, throug
const metricSeriesData = Object.values(
await Promise.all(
pipelines.map((pipeline) => {
- return new Promise(async (resolve) => {
- const data = await getMetrics(
- req,
- lsIndexPattern,
- [throughputMetric],
- [
- {
- bool: {
- should: [
- { term: { type: 'logstash_stats' } },
- { term: { 'metricset.name': 'stats' } },
- ],
+ return new Promise(async (resolve, reject) => {
+ try {
+ const data = await getMetrics(
+ req,
+ lsIndexPattern,
+ [throughputMetric],
+ [
+ {
+ bool: {
+ should: [
+ {
+ term: {
+ type: 'logstash_stats',
+ },
+ },
+ {
+ term: {
+ 'metricset.name': 'stats',
+ },
+ },
+ ],
+ },
},
+ ],
+ {
+ pipeline,
},
- ],
- {
- pipeline,
- },
- 2
- );
- resolve(reduceData(pipeline, data));
+ 2
+ );
+ resolve(reduceData(pipeline, data));
+ } catch (error) {
+ reject(error);
+ }
});
})
)
@@ -184,27 +196,38 @@ async function getPipelines(req, lsIndexPattern, pipelines, throughputMetric, no
async function getThroughputPipelines(req, lsIndexPattern, pipelines, throughputMetric) {
const metricsResponse = await Promise.all(
pipelines.map((pipeline) => {
- return new Promise(async (resolve) => {
- const data = await getMetrics(
- req,
- lsIndexPattern,
- [throughputMetric],
- [
- {
- bool: {
- should: [
- { term: { type: 'logstash_stats' } },
- { term: { 'metricset.name': 'stats' } },
- ],
+ return new Promise(async (resolve, reject) => {
+ try {
+ const data = await getMetrics(
+ req,
+ lsIndexPattern,
+ [throughputMetric],
+ [
+ {
+ bool: {
+ should: [
+ {
+ term: {
+ type: 'logstash_stats',
+ },
+ },
+ {
+ term: {
+ 'metricset.name': 'stats',
+ },
+ },
+ ],
+ },
},
- },
- ],
- {
- pipeline,
- }
- );
-
- resolve(reduceData(pipeline, data));
+ ],
+ {
+ pipeline,
+ }
+ );
+ resolve(reduceData(pipeline, data));
+ } catch (error) {
+ reject(error);
+ }
});
})
);
diff --git a/x-pack/plugins/security/server/session_management/session_index.ts b/x-pack/plugins/security/server/session_management/session_index.ts
index 9093d5d2e0db2..f1a9296177d9c 100644
--- a/x-pack/plugins/security/server/session_management/session_index.ts
+++ b/x-pack/plugins/security/server/session_management/session_index.ts
@@ -317,69 +317,73 @@ export class SessionIndex {
const sessionIndexTemplateName = `${this.options.kibanaIndexName}_security_session_index_template_${SESSION_INDEX_TEMPLATE_VERSION}`;
return (this.indexInitialization = new Promise(async (resolve, reject) => {
- // Check if required index template exists.
- let indexTemplateExists = false;
try {
- indexTemplateExists = (
- await this.options.elasticsearchClient.indices.existsTemplate({
- name: sessionIndexTemplateName,
- })
- ).body;
- } catch (err) {
- this.options.logger.error(
- `Failed to check if session index template exists: ${err.message}`
- );
- return reject(err);
- }
-
- // Create index template if it doesn't exist.
- if (indexTemplateExists) {
- this.options.logger.debug('Session index template already exists.');
- } else {
+ // Check if required index template exists.
+ let indexTemplateExists = false;
try {
- await this.options.elasticsearchClient.indices.putTemplate({
- name: sessionIndexTemplateName,
- body: getSessionIndexTemplate(this.indexName),
- });
- this.options.logger.debug('Successfully created session index template.');
+ indexTemplateExists = (
+ await this.options.elasticsearchClient.indices.existsTemplate({
+ name: sessionIndexTemplateName,
+ })
+ ).body;
} catch (err) {
- this.options.logger.error(`Failed to create session index template: ${err.message}`);
+ this.options.logger.error(
+ `Failed to check if session index template exists: ${err.message}`
+ );
return reject(err);
}
- }
- // Check if required index exists. We cannot be sure that automatic creation of indices is
- // always enabled, so we create session index explicitly.
- let indexExists = false;
- try {
- indexExists = (
- await this.options.elasticsearchClient.indices.exists({ index: this.indexName })
- ).body;
- } catch (err) {
- this.options.logger.error(`Failed to check if session index exists: ${err.message}`);
- return reject(err);
- }
+ // Create index template if it doesn't exist.
+ if (indexTemplateExists) {
+ this.options.logger.debug('Session index template already exists.');
+ } else {
+ try {
+ await this.options.elasticsearchClient.indices.putTemplate({
+ name: sessionIndexTemplateName,
+ body: getSessionIndexTemplate(this.indexName),
+ });
+ this.options.logger.debug('Successfully created session index template.');
+ } catch (err) {
+ this.options.logger.error(`Failed to create session index template: ${err.message}`);
+ return reject(err);
+ }
+ }
- // Create index if it doesn't exist.
- if (indexExists) {
- this.options.logger.debug('Session index already exists.');
- } else {
+ // Check if required index exists. We cannot be sure that automatic creation of indices is
+ // always enabled, so we create session index explicitly.
+ let indexExists = false;
try {
- await this.options.elasticsearchClient.indices.create({ index: this.indexName });
- this.options.logger.debug('Successfully created session index.');
+ indexExists = (
+ await this.options.elasticsearchClient.indices.exists({ index: this.indexName })
+ ).body;
} catch (err) {
- // There can be a race condition if index is created by another Kibana instance.
- if (err?.body?.error?.type === 'resource_already_exists_exception') {
- this.options.logger.debug('Session index already exists.');
- } else {
- this.options.logger.error(`Failed to create session index: ${err.message}`);
- return reject(err);
+ this.options.logger.error(`Failed to check if session index exists: ${err.message}`);
+ return reject(err);
+ }
+
+ // Create index if it doesn't exist.
+ if (indexExists) {
+ this.options.logger.debug('Session index already exists.');
+ } else {
+ try {
+ await this.options.elasticsearchClient.indices.create({ index: this.indexName });
+ this.options.logger.debug('Successfully created session index.');
+ } catch (err) {
+ // There can be a race condition if index is created by another Kibana instance.
+ if (err?.body?.error?.type === 'resource_already_exists_exception') {
+ this.options.logger.debug('Session index already exists.');
+ } else {
+ this.options.logger.error(`Failed to create session index: ${err.message}`);
+ return reject(err);
+ }
}
}
- }
- // Notify any consumers that are awaiting on this promise and immediately reset it.
- resolve();
+ // Notify any consumers that are awaiting on this promise and immediately reset it.
+ resolve();
+ } catch (error) {
+ reject(error);
+ }
}).finally(() => {
this.indexInitialization = undefined;
}));
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts
index 8e322405280d3..7eb3220bc4387 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts
@@ -127,204 +127,221 @@ export const importRulesRoute = (
const batchParseObjects = chunkParseObjects.shift() ?? [];
const newImportRuleResponse = await Promise.all(
batchParseObjects.reduce>>((accum, parsedRule) => {
- const importsWorkerPromise = new Promise(async (resolve) => {
- if (parsedRule instanceof Error) {
- // If the JSON object had a validation or parse error then we return
- // early with the error and an (unknown) for the ruleId
- resolve(
- createBulkErrorObject({
- statusCode: 400,
- message: parsedRule.message,
- })
- );
- return null;
- }
- const {
- anomaly_threshold: anomalyThreshold,
- author,
- building_block_type: buildingBlockType,
- description,
- enabled,
- event_category_override: eventCategoryOverride,
- false_positives: falsePositives,
- from,
- immutable,
- query: queryOrUndefined,
- language: languageOrUndefined,
- license,
- machine_learning_job_id: machineLearningJobId,
- output_index: outputIndex,
- saved_id: savedId,
- meta,
- filters: filtersRest,
- rule_id: ruleId,
- index,
- interval,
- max_signals: maxSignals,
- risk_score: riskScore,
- risk_score_mapping: riskScoreMapping,
- rule_name_override: ruleNameOverride,
- name,
- severity,
- severity_mapping: severityMapping,
- tags,
- threat,
- threat_filters: threatFilters,
- threat_index: threatIndex,
- threat_query: threatQuery,
- threat_mapping: threatMapping,
- threat_language: threatLanguage,
- threat_indicator_path: threatIndicatorPath,
- concurrent_searches: concurrentSearches,
- items_per_search: itemsPerSearch,
- threshold,
- timestamp_override: timestampOverride,
- to,
- type,
- references,
- note,
- timeline_id: timelineId,
- timeline_title: timelineTitle,
- version,
- exceptions_list: exceptionsList,
- } = parsedRule;
-
- try {
- const query = !isMlRule(type) && queryOrUndefined == null ? '' : queryOrUndefined;
-
- const language =
- !isMlRule(type) && languageOrUndefined == null ? 'kuery' : languageOrUndefined;
-
- // TODO: Fix these either with an is conversion or by better typing them within io-ts
- const filters: PartialFilter[] | undefined = filtersRest as PartialFilter[];
+ const importsWorkerPromise = new Promise(
+ async (resolve, reject) => {
+ try {
+ if (parsedRule instanceof Error) {
+ // If the JSON object had a validation or parse error then we return
+ // early with the error and an (unknown) for the ruleId
+ resolve(
+ createBulkErrorObject({
+ statusCode: 400,
+ message: parsedRule.message,
+ })
+ );
+ return null;
+ }
- throwHttpError(await mlAuthz.validateRuleType(type));
-
- const rule = await readRules({ alertsClient, ruleId, id: undefined });
- if (rule == null) {
- await createRules({
- alertsClient,
- anomalyThreshold,
+ const {
+ anomaly_threshold: anomalyThreshold,
author,
- buildingBlockType,
+ building_block_type: buildingBlockType,
description,
enabled,
- eventCategoryOverride,
- falsePositives,
+ event_category_override: eventCategoryOverride,
+ false_positives: falsePositives,
from,
immutable,
- query,
- language,
+ query: queryOrUndefined,
+ language: languageOrUndefined,
license,
- machineLearningJobId,
- outputIndex: signalsIndex,
- savedId,
- timelineId,
- timelineTitle,
+ machine_learning_job_id: machineLearningJobId,
+ output_index: outputIndex,
+ saved_id: savedId,
meta,
- filters,
- ruleId,
+ filters: filtersRest,
+ rule_id: ruleId,
index,
interval,
- maxSignals,
+ max_signals: maxSignals,
+ risk_score: riskScore,
+ risk_score_mapping: riskScoreMapping,
+ rule_name_override: ruleNameOverride,
name,
- riskScore,
- riskScoreMapping,
- ruleNameOverride,
severity,
- severityMapping,
+ severity_mapping: severityMapping,
tags,
- to,
- type,
threat,
+ threat_filters: threatFilters,
+ threat_index: threatIndex,
+ threat_query: threatQuery,
+ threat_mapping: threatMapping,
+ threat_language: threatLanguage,
+ threat_indicator_path: threatIndicatorPath,
+ concurrent_searches: concurrentSearches,
+ items_per_search: itemsPerSearch,
threshold,
- threatFilters,
- threatIndex,
- threatIndicatorPath,
- threatQuery,
- threatMapping,
- threatLanguage,
- concurrentSearches,
- itemsPerSearch,
- timestampOverride,
- references,
- note,
- version,
- exceptionsList,
- actions: [], // Actions are not imported nor exported at this time
- });
- resolve({ rule_id: ruleId, status_code: 200 });
- } else if (rule != null && request.query.overwrite) {
- await patchRules({
- alertsClient,
- author,
- buildingBlockType,
- savedObjectsClient,
- description,
- enabled,
- eventCategoryOverride,
- falsePositives,
- from,
- query,
- language,
- license,
- outputIndex,
- savedId,
- timelineId,
- timelineTitle,
- meta,
- filters,
- rule,
- index,
- interval,
- maxSignals,
- riskScore,
- riskScoreMapping,
- ruleNameOverride,
- name,
- severity,
- severityMapping,
- tags,
- timestampOverride,
+ timestamp_override: timestampOverride,
to,
type,
- threat,
- threshold,
- threatFilters,
- threatIndex,
- threatQuery,
- threatMapping,
- threatLanguage,
- concurrentSearches,
- itemsPerSearch,
references,
note,
+ timeline_id: timelineId,
+ timeline_title: timelineTitle,
version,
- exceptionsList,
- anomalyThreshold,
- machineLearningJobId,
- actions: undefined,
- });
- resolve({ rule_id: ruleId, status_code: 200 });
- } else if (rule != null) {
- resolve(
- createBulkErrorObject({
+ exceptions_list: exceptionsList,
+ } = parsedRule;
+
+ try {
+ const query =
+ !isMlRule(type) && queryOrUndefined == null ? '' : queryOrUndefined;
+ const language =
+ !isMlRule(type) && languageOrUndefined == null
+ ? 'kuery'
+ : languageOrUndefined; // TODO: Fix these either with an is conversion or by better typing them within io-ts
+
+ const filters: PartialFilter[] | undefined = filtersRest as PartialFilter[];
+ throwHttpError(await mlAuthz.validateRuleType(type));
+ const rule = await readRules({
+ alertsClient,
ruleId,
- statusCode: 409,
- message: `rule_id: "${ruleId}" already exists`,
- })
- );
+ id: undefined,
+ });
+
+ if (rule == null) {
+ await createRules({
+ alertsClient,
+ anomalyThreshold,
+ author,
+ buildingBlockType,
+ description,
+ enabled,
+ eventCategoryOverride,
+ falsePositives,
+ from,
+ immutable,
+ query,
+ language,
+ license,
+ machineLearningJobId,
+ outputIndex: signalsIndex,
+ savedId,
+ timelineId,
+ timelineTitle,
+ meta,
+ filters,
+ ruleId,
+ index,
+ interval,
+ maxSignals,
+ name,
+ riskScore,
+ riskScoreMapping,
+ ruleNameOverride,
+ severity,
+ severityMapping,
+ tags,
+ to,
+ type,
+ threat,
+ threshold,
+ threatFilters,
+ threatIndex,
+ threatIndicatorPath,
+ threatQuery,
+ threatMapping,
+ threatLanguage,
+ concurrentSearches,
+ itemsPerSearch,
+ timestampOverride,
+ references,
+ note,
+ version,
+ exceptionsList,
+ actions: [], // Actions are not imported nor exported at this time
+ });
+ resolve({
+ rule_id: ruleId,
+ status_code: 200,
+ });
+ } else if (rule != null && request.query.overwrite) {
+ await patchRules({
+ alertsClient,
+ author,
+ buildingBlockType,
+ savedObjectsClient,
+ description,
+ enabled,
+ eventCategoryOverride,
+ falsePositives,
+ from,
+ query,
+ language,
+ license,
+ outputIndex,
+ savedId,
+ timelineId,
+ timelineTitle,
+ meta,
+ filters,
+ rule,
+ index,
+ interval,
+ maxSignals,
+ riskScore,
+ riskScoreMapping,
+ ruleNameOverride,
+ name,
+ severity,
+ severityMapping,
+ tags,
+ timestampOverride,
+ to,
+ type,
+ threat,
+ threshold,
+ threatFilters,
+ threatIndex,
+ threatQuery,
+ threatMapping,
+ threatLanguage,
+ concurrentSearches,
+ itemsPerSearch,
+ references,
+ note,
+ version,
+ exceptionsList,
+ anomalyThreshold,
+ machineLearningJobId,
+ actions: undefined,
+ });
+ resolve({
+ rule_id: ruleId,
+ status_code: 200,
+ });
+ } else if (rule != null) {
+ resolve(
+ createBulkErrorObject({
+ ruleId,
+ statusCode: 409,
+ message: `rule_id: "${ruleId}" already exists`,
+ })
+ );
+ }
+ } catch (err) {
+ resolve(
+ createBulkErrorObject({
+ ruleId,
+ statusCode: err.statusCode ?? 400,
+ message: err.message,
+ })
+ );
+ }
+ } catch (error) {
+ reject(error);
}
- } catch (err) {
- resolve(
- createBulkErrorObject({
- ruleId,
- statusCode: err.statusCode ?? 400,
- message: err.message,
- })
- );
}
- });
+ );
return [...accum, importsWorkerPromise];
}, [])
);
diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/helpers.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/helpers.ts
index 70d93d7552b1c..7e35c2163df70 100644
--- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/helpers.ts
+++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/helpers.ts
@@ -106,133 +106,132 @@ export const importTimelines = async (
batchParseObjects.reduce>>((accum, parsedTimeline) => {
const importsWorkerPromise = new Promise(
async (resolve, reject) => {
- if (parsedTimeline instanceof Error) {
- // If the JSON object had a validation or parse error then we return
- // early with the error and an (unknown) for the ruleId
- resolve(
- createBulkErrorObject({
- statusCode: 400,
- message: parsedTimeline.message,
- })
- );
-
- return null;
- }
-
- const {
- savedObjectId,
- pinnedEventIds,
- globalNotes,
- eventNotes,
- status,
- templateTimelineId,
- templateTimelineVersion,
- title,
- timelineType,
- version,
- } = parsedTimeline;
-
- const parsedTimelineObject = omit(timelineSavedObjectOmittedFields, parsedTimeline);
- let newTimeline = null;
try {
- const compareTimelinesStatus = new CompareTimelinesStatus({
+ if (parsedTimeline instanceof Error) {
+ // If the JSON object had a validation or parse error then we return
+ // early with the error and an (unknown) for the ruleId
+ resolve(
+ createBulkErrorObject({
+ statusCode: 400,
+ message: parsedTimeline.message,
+ })
+ );
+ return null;
+ }
+
+ const {
+ savedObjectId,
+ pinnedEventIds,
+ globalNotes,
+ eventNotes,
status,
- timelineType,
+ templateTimelineId,
+ templateTimelineVersion,
title,
- timelineInput: {
- id: savedObjectId,
- version,
- },
- templateTimelineInput: {
- id: templateTimelineId,
- version: templateTimelineVersion,
- },
- frameworkRequest,
- });
- await compareTimelinesStatus.init();
- const isTemplateTimeline = compareTimelinesStatus.isHandlingTemplateTimeline;
- if (compareTimelinesStatus.isCreatableViaImport) {
- // create timeline / timeline template
- newTimeline = await createTimelines({
- frameworkRequest,
- timeline: setTimeline(parsedTimelineObject, parsedTimeline, isTemplateTimeline),
- pinnedEventIds: isTemplateTimeline ? null : pinnedEventIds,
- notes: isTemplateTimeline ? globalNotes : [...globalNotes, ...eventNotes],
- isImmutable,
- overrideNotesOwner: false,
- });
+ timelineType,
+ version,
+ } = parsedTimeline;
+ const parsedTimelineObject = omit(timelineSavedObjectOmittedFields, parsedTimeline);
+ let newTimeline = null;
- resolve({
- timeline_id: newTimeline.timeline.savedObjectId,
- status_code: 200,
- action: TimelineStatusActions.createViaImport,
+ try {
+ const compareTimelinesStatus = new CompareTimelinesStatus({
+ status,
+ timelineType,
+ title,
+ timelineInput: {
+ id: savedObjectId,
+ version,
+ },
+ templateTimelineInput: {
+ id: templateTimelineId,
+ version: templateTimelineVersion,
+ },
+ frameworkRequest,
});
- }
+ await compareTimelinesStatus.init();
+ const isTemplateTimeline = compareTimelinesStatus.isHandlingTemplateTimeline;
- if (!compareTimelinesStatus.isHandlingTemplateTimeline) {
- const errorMessage = compareTimelinesStatus.checkIsFailureCases(
- TimelineStatusActions.createViaImport
- );
- const message = errorMessage?.body ?? DEFAULT_ERROR;
-
- resolve(
- createBulkErrorObject({
- id: savedObjectId ?? 'unknown',
- statusCode: 409,
- message,
- })
- );
- } else {
- if (compareTimelinesStatus.isUpdatableViaImport) {
- // update timeline template
+ if (compareTimelinesStatus.isCreatableViaImport) {
+ // create timeline / timeline template
newTimeline = await createTimelines({
frameworkRequest,
- timeline: parsedTimelineObject,
- timelineSavedObjectId: compareTimelinesStatus.timelineId,
- timelineVersion: compareTimelinesStatus.timelineVersion,
- notes: globalNotes,
- existingNoteIds: compareTimelinesStatus.timelineInput.data?.noteIds,
+ timeline: setTimeline(parsedTimelineObject, parsedTimeline, isTemplateTimeline),
+ pinnedEventIds: isTemplateTimeline ? null : pinnedEventIds,
+ notes: isTemplateTimeline ? globalNotes : [...globalNotes, ...eventNotes],
isImmutable,
overrideNotesOwner: false,
});
-
resolve({
timeline_id: newTimeline.timeline.savedObjectId,
status_code: 200,
- action: TimelineStatusActions.updateViaImport,
+ action: TimelineStatusActions.createViaImport,
});
- } else {
+ }
+
+ if (!compareTimelinesStatus.isHandlingTemplateTimeline) {
const errorMessage = compareTimelinesStatus.checkIsFailureCases(
- TimelineStatusActions.updateViaImport
+ TimelineStatusActions.createViaImport
);
-
const message = errorMessage?.body ?? DEFAULT_ERROR;
-
resolve(
createBulkErrorObject({
- id:
- savedObjectId ??
- (templateTimelineId
- ? `(template_timeline_id) ${templateTimelineId}`
- : 'unknown'),
+ id: savedObjectId ?? 'unknown',
statusCode: 409,
message,
})
);
+ } else {
+ if (compareTimelinesStatus.isUpdatableViaImport) {
+ // update timeline template
+ newTimeline = await createTimelines({
+ frameworkRequest,
+ timeline: parsedTimelineObject,
+ timelineSavedObjectId: compareTimelinesStatus.timelineId,
+ timelineVersion: compareTimelinesStatus.timelineVersion,
+ notes: globalNotes,
+ existingNoteIds: compareTimelinesStatus.timelineInput.data?.noteIds,
+ isImmutable,
+ overrideNotesOwner: false,
+ });
+ resolve({
+ timeline_id: newTimeline.timeline.savedObjectId,
+ status_code: 200,
+ action: TimelineStatusActions.updateViaImport,
+ });
+ } else {
+ const errorMessage = compareTimelinesStatus.checkIsFailureCases(
+ TimelineStatusActions.updateViaImport
+ );
+ const message = errorMessage?.body ?? DEFAULT_ERROR;
+ resolve(
+ createBulkErrorObject({
+ id:
+ savedObjectId ??
+ (templateTimelineId
+ ? `(template_timeline_id) ${templateTimelineId}`
+ : 'unknown'),
+ statusCode: 409,
+ message,
+ })
+ );
+ }
}
+ } catch (err) {
+ resolve(
+ createBulkErrorObject({
+ id:
+ savedObjectId ??
+ (templateTimelineId
+ ? `(template_timeline_id) ${templateTimelineId}`
+ : 'unknown'),
+ statusCode: 400,
+ message: err.message,
+ })
+ );
}
- } catch (err) {
- resolve(
- createBulkErrorObject({
- id:
- savedObjectId ??
- (templateTimelineId
- ? `(template_timeline_id) ${templateTimelineId}`
- : 'unknown'),
- statusCode: 400,
- message: err.message,
- })
- );
+ } catch (error) {
+ reject(error);
}
}
);
diff --git a/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts b/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts
index 6aa8bad5717ec..23a25628aa640 100644
--- a/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts
+++ b/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts
@@ -43,62 +43,62 @@ describe('Configuration Statistics Aggregator', () => {
};
return new Promise(async (resolve, reject) => {
- createConfigurationAggregator(configuration, managedConfig)
- .pipe(take(3), bufferCount(3))
- .subscribe(([initial, updatedWorkers, updatedInterval]) => {
- expect(initial.value).toEqual({
- max_workers: 10,
- poll_interval: 6000000,
- max_poll_inactivity_cycles: 10,
- request_capacity: 1000,
- monitored_aggregated_stats_refresh_rate: 5000,
- monitored_stats_running_average_window: 50,
- monitored_task_execution_thresholds: {
- default: {
- error_threshold: 90,
- warn_threshold: 80,
+ try {
+ createConfigurationAggregator(configuration, managedConfig)
+ .pipe(take(3), bufferCount(3))
+ .subscribe(([initial, updatedWorkers, updatedInterval]) => {
+ expect(initial.value).toEqual({
+ max_workers: 10,
+ poll_interval: 6000000,
+ max_poll_inactivity_cycles: 10,
+ request_capacity: 1000,
+ monitored_aggregated_stats_refresh_rate: 5000,
+ monitored_stats_running_average_window: 50,
+ monitored_task_execution_thresholds: {
+ default: {
+ error_threshold: 90,
+ warn_threshold: 80,
+ },
+ custom: {},
},
- custom: {},
- },
- });
-
- expect(updatedWorkers.value).toEqual({
- max_workers: 8,
- poll_interval: 6000000,
- max_poll_inactivity_cycles: 10,
- request_capacity: 1000,
- monitored_aggregated_stats_refresh_rate: 5000,
- monitored_stats_running_average_window: 50,
- monitored_task_execution_thresholds: {
- default: {
- error_threshold: 90,
- warn_threshold: 80,
+ });
+ expect(updatedWorkers.value).toEqual({
+ max_workers: 8,
+ poll_interval: 6000000,
+ max_poll_inactivity_cycles: 10,
+ request_capacity: 1000,
+ monitored_aggregated_stats_refresh_rate: 5000,
+ monitored_stats_running_average_window: 50,
+ monitored_task_execution_thresholds: {
+ default: {
+ error_threshold: 90,
+ warn_threshold: 80,
+ },
+ custom: {},
},
- custom: {},
- },
- });
-
- expect(updatedInterval.value).toEqual({
- max_workers: 8,
- poll_interval: 3000,
- max_poll_inactivity_cycles: 10,
- request_capacity: 1000,
- monitored_aggregated_stats_refresh_rate: 5000,
- monitored_stats_running_average_window: 50,
- monitored_task_execution_thresholds: {
- default: {
- error_threshold: 90,
- warn_threshold: 80,
+ });
+ expect(updatedInterval.value).toEqual({
+ max_workers: 8,
+ poll_interval: 3000,
+ max_poll_inactivity_cycles: 10,
+ request_capacity: 1000,
+ monitored_aggregated_stats_refresh_rate: 5000,
+ monitored_stats_running_average_window: 50,
+ monitored_task_execution_thresholds: {
+ default: {
+ error_threshold: 90,
+ warn_threshold: 80,
+ },
+ custom: {},
},
- custom: {},
- },
- });
- resolve();
- }, reject);
-
- managedConfig.maxWorkersConfiguration$.next(8);
-
- managedConfig.pollIntervalConfiguration$.next(3000);
+ });
+ resolve();
+ }, reject);
+ managedConfig.maxWorkersConfiguration$.next(8);
+ managedConfig.pollIntervalConfiguration$.next(3000);
+ } catch (error) {
+ reject(error);
+ }
});
});
});
diff --git a/x-pack/plugins/task_manager/server/monitoring/workload_statistics.test.ts b/x-pack/plugins/task_manager/server/monitoring/workload_statistics.test.ts
index 9125bca8f5b05..d24931646128a 100644
--- a/x-pack/plugins/task_manager/server/monitoring/workload_statistics.test.ts
+++ b/x-pack/plugins/task_manager/server/monitoring/workload_statistics.test.ts
@@ -328,27 +328,44 @@ describe('Workload Statistics Aggregator', () => {
loggingSystemMock.create().get()
);
- return new Promise(async (resolve) => {
- workloadAggregator.pipe(first()).subscribe((result) => {
- expect(result.key).toEqual('workload');
- expect(result.value).toMatchObject({
- count: 4,
- task_types: {
- actions_telemetry: { count: 2, status: { idle: 2 } },
- alerting_telemetry: { count: 1, status: { idle: 1 } },
- session_cleanup: { count: 1, status: { idle: 1 } },
- },
+ return new Promise(async (resolve, reject) => {
+ try {
+ workloadAggregator.pipe(first()).subscribe((result) => {
+ expect(result.key).toEqual('workload');
+ expect(result.value).toMatchObject({
+ count: 4,
+ task_types: {
+ actions_telemetry: {
+ count: 2,
+ status: {
+ idle: 2,
+ },
+ },
+ alerting_telemetry: {
+ count: 1,
+ status: {
+ idle: 1,
+ },
+ },
+ session_cleanup: {
+ count: 1,
+ status: {
+ idle: 1,
+ },
+ },
+ },
+ });
+ resolve();
});
- resolve();
- });
-
- availability$.next(false);
-
- await sleep(10);
- expect(taskStore.aggregate).not.toHaveBeenCalled();
- await sleep(10);
- expect(taskStore.aggregate).not.toHaveBeenCalled();
- availability$.next(true);
+ availability$.next(false);
+ await sleep(10);
+ expect(taskStore.aggregate).not.toHaveBeenCalled();
+ await sleep(10);
+ expect(taskStore.aggregate).not.toHaveBeenCalled();
+ availability$.next(true);
+ } catch (error) {
+ reject(error);
+ }
});
});
diff --git a/x-pack/plugins/task_manager/server/task_scheduling.ts b/x-pack/plugins/task_manager/server/task_scheduling.ts
index 153c16f5c4bf7..38773d011ac6f 100644
--- a/x-pack/plugins/task_manager/server/task_scheduling.ts
+++ b/x-pack/plugins/task_manager/server/task_scheduling.ts
@@ -100,8 +100,12 @@ export class TaskScheduling {
*/
public async runNow(taskId: string): Promise {
return new Promise(async (resolve, reject) => {
- this.awaitTaskRunResult(taskId).then(resolve).catch(reject);
- this.taskPollingLifecycle.attemptToRun(taskId);
+ try {
+ this.awaitTaskRunResult(taskId).then(resolve).catch(reject);
+ this.taskPollingLifecycle.attemptToRun(taskId);
+ } catch (error) {
+ reject(error);
+ }
});
}
diff --git a/x-pack/test/functional_enterprise_search/services/app_search_client.ts b/x-pack/test/functional_enterprise_search/services/app_search_client.ts
index 8e829b97e9dda..457523bccf8c3 100644
--- a/x-pack/test/functional_enterprise_search/services/app_search_client.ts
+++ b/x-pack/test/functional_enterprise_search/services/app_search_client.ts
@@ -105,14 +105,20 @@ const search = async (engineName: string): Promise => {
// Since the App Search API does not issue document receipts, the only way to tell whether or not documents
// are fully indexed is to poll the search endpoint.
export const waitForIndexedDocs = (engineName: string) => {
- return new Promise(async function (resolve) {
- let isReady = false;
- while (!isReady) {
- const response = await search(engineName);
- if (response.results && response.results.length > 0) {
- isReady = true;
- resolve();
+ return new Promise(async function (resolve, reject) {
+ try {
+ let isReady = false;
+
+ while (!isReady) {
+ const response = await search(engineName);
+
+ if (response.results && response.results.length > 0) {
+ isReady = true;
+ resolve();
+ }
}
+ } catch (error) {
+ reject(error);
}
});
};
diff --git a/x-pack/test/lists_api_integration/utils.ts b/x-pack/test/lists_api_integration/utils.ts
index 90103ec8b856c..bcb219ec9744d 100644
--- a/x-pack/test/lists_api_integration/utils.ts
+++ b/x-pack/test/lists_api_integration/utils.ts
@@ -117,21 +117,29 @@ export const waitFor = async (
timeoutWait: number = 10
) => {
await new Promise(async (resolve, reject) => {
- let found = false;
- let numberOfTries = 0;
- while (!found && numberOfTries < Math.floor(maxTimeout / timeoutWait)) {
- const itPasses = await functionToTest();
- if (itPasses) {
- found = true;
+ try {
+ let found = false;
+ let numberOfTries = 0;
+
+ while (!found && numberOfTries < Math.floor(maxTimeout / timeoutWait)) {
+ const itPasses = await functionToTest();
+
+ if (itPasses) {
+ found = true;
+ } else {
+ numberOfTries++;
+ }
+
+ await new Promise((resolveTimeout) => setTimeout(resolveTimeout, timeoutWait));
+ }
+
+ if (found) {
+ resolve();
} else {
- numberOfTries++;
+ reject(new Error(`timed out waiting for function ${functionName} condition to be true`));
}
- await new Promise((resolveTimeout) => setTimeout(resolveTimeout, timeoutWait));
- }
- if (found) {
- resolve();
- } else {
- reject(new Error(`timed out waiting for function ${functionName} condition to be true`));
+ } catch (error) {
+ reject(error);
}
});
};
diff --git a/yarn.lock b/yarn.lock
index f2b40bb08df1c..962b0ffbfd9f6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -110,6 +110,15 @@
jsesc "^2.5.1"
source-map "^0.5.0"
+"@babel/generator@^7.12.11":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.5.tgz#848d7b9f031caca9d0cd0af01b063f226f52d785"
+ integrity sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==
+ dependencies:
+ "@babel/types" "^7.14.5"
+ jsesc "^2.5.1"
+ source-map "^0.5.0"
+
"@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.10.4", "@babel/helper-annotate-as-pure@^7.12.10":
version "7.12.10"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz#54ab9b000e60a93644ce17b3f37d313aaf1d115d"
@@ -293,6 +302,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
+"@babel/helper-validator-identifier@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8"
+ integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==
+
"@babel/helper-validator-option@^7.12.1", "@babel/helper-validator-option@^7.12.11":
version "7.12.11"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz#d66cb8b7a3e7fe4c6962b32020a131ecf0847f4f"
@@ -1187,6 +1201,14 @@
lodash "^4.17.19"
to-fast-properties "^2.0.0"
+"@babel/types@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.5.tgz#3bb997ba829a2104cedb20689c4a5b8121d383ff"
+ integrity sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.14.5"
+ to-fast-properties "^2.0.0"
+
"@base2/pretty-print-object@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.0.tgz#860ce718b0b73f4009e153541faff2cb6b85d047"
@@ -6283,6 +6305,11 @@
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.14.1.tgz#b3d2eb91dafd0fd8b3fce7c61512ac66bd0364aa"
integrity sha512-SkhzHdI/AllAgQSxXM89XwS1Tkic7csPdndUuTKabEwRcEfR8uQ/iPA3Dgio1rqsV3jtqZhY0QQni8rLswJM2w==
+"@typescript-eslint/types@4.28.3":
+ version "4.28.3"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.3.tgz#8fffd436a3bada422c2c1da56060a0566a9506c7"
+ integrity sha512-kQFaEsQBQVtA9VGVyciyTbIg7S3WoKHNuOp/UF5RG40900KtGqfoiETWD/v0lzRXc+euVE9NXmfer9dLkUJrkA==
+
"@typescript-eslint/types@4.3.0":
version "4.3.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.3.0.tgz#1f0b2d5e140543e2614f06d48fb3ae95193c6ddf"
@@ -6316,6 +6343,19 @@
semver "^7.3.2"
tsutils "^3.17.1"
+"@typescript-eslint/typescript-estree@^4.14.1":
+ version "4.28.3"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.3.tgz#253d7088100b2a38aefe3c8dd7bd1f8232ec46fb"
+ integrity sha512-YAb1JED41kJsqCQt1NcnX5ZdTA93vKFCMP4lQYG6CFxd0VzDJcKttRlMrlG+1qiWAw8+zowmHU1H0OzjWJzR2w==
+ dependencies:
+ "@typescript-eslint/types" "4.28.3"
+ "@typescript-eslint/visitor-keys" "4.28.3"
+ debug "^4.3.1"
+ globby "^11.0.3"
+ is-glob "^4.0.1"
+ semver "^7.3.5"
+ tsutils "^3.21.0"
+
"@typescript-eslint/visitor-keys@4.14.1":
version "4.14.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.1.tgz#e93c2ff27f47ee477a929b970ca89d60a117da91"
@@ -6324,6 +6364,14 @@
"@typescript-eslint/types" "4.14.1"
eslint-visitor-keys "^2.0.0"
+"@typescript-eslint/visitor-keys@4.28.3":
+ version "4.28.3"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.3.tgz#26ac91e84b23529968361045829da80a4e5251c4"
+ integrity sha512-ri1OzcLnk1HH4gORmr1dllxDzzrN6goUIz/P4MHFV0YZJDCADPR3RvYNp0PW2SetKTThar6wlbFTL00hV2Q+fg==
+ dependencies:
+ "@typescript-eslint/types" "4.28.3"
+ eslint-visitor-keys "^2.0.0"
+
"@typescript-eslint/visitor-keys@4.3.0":
version "4.3.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.3.0.tgz#0e5ab0a09552903edeae205982e8521e17635ae0"
@@ -12962,6 +13010,11 @@ eslint-scope@^5.0.0:
esrecurse "^4.1.0"
estraverse "^4.1.1"
+eslint-traverse@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-traverse/-/eslint-traverse-1.0.0.tgz#108d360a171a6e6334e1af0cee905a93bd0dcc53"
+ integrity sha512-bSp37rQs93LF8rZ409EI369DGCI4tELbFVmFNxI6QbuveS7VRxYVyUhwDafKN/enMyUh88HQQ7ZoGUHtPuGdcw==
+
eslint-utils@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f"
@@ -24858,6 +24911,13 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+semver@^7.3.5:
+ version "7.3.5"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
+ integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
+ dependencies:
+ lru-cache "^6.0.0"
+
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
@@ -27215,6 +27275,13 @@ tsutils@^3.17.1:
dependencies:
tslib "^1.8.1"
+tsutils@^3.21.0:
+ version "3.21.0"
+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
+ integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
+ dependencies:
+ tslib "^1.8.1"
+
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"