Functional tests for execution context propagation in alerting and task manager plugins (#111179) (#112066)
* move execution context tests to x-pack folder * add execution context tests for alerts and tasks * cleanup tests * remove obsolete test folder * use ToolingLog instead of console.log # Conflicts: # scripts/functional_tests.js # x-pack/scripts/functional_tests.js
This commit is contained in:
parent
e2d87731de
commit
6eb230d23c
|
@ -17,5 +17,4 @@ require('@kbn/test').runTestsCli([
|
|||
require.resolve('../test/new_visualize_flow/config.ts'),
|
||||
require.resolve('../test/security_functional/config.ts'),
|
||||
require.resolve('../test/functional/config.legacy.ts'),
|
||||
require.resolve('../test/functional_execution_context/config.ts'),
|
||||
]);
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { services as functionalServices } from '../functional/services';
|
||||
|
||||
export const services = functionalServices;
|
|
@ -1,374 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import type { Ecs, KibanaExecutionContext } from 'kibana/server';
|
||||
|
||||
import Fs from 'fs/promises';
|
||||
import Path from 'path';
|
||||
import { isEqual } from 'lodash';
|
||||
import type { FtrProviderContext } from '../ftr_provider_context';
|
||||
|
||||
const logFilePath = Path.resolve(__dirname, '../kibana.log');
|
||||
|
||||
// to avoid splitting log record containing \n symbol
|
||||
const endOfLine = /(?<=})\s*\n/;
|
||||
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const PageObjects = getPageObjects(['common', 'dashboard', 'header', 'home']);
|
||||
const retry = getService('retry');
|
||||
|
||||
async function assertLogContains(
|
||||
description: string,
|
||||
predicate: (record: Ecs) => boolean
|
||||
): Promise<void> {
|
||||
// logs are written to disk asynchronously. I sacrificed performance to reduce flakiness.
|
||||
await retry.waitFor(description, async () => {
|
||||
const logsStr = await Fs.readFile(logFilePath, 'utf-8');
|
||||
const normalizedRecords = logsStr
|
||||
.split(endOfLine)
|
||||
.filter(Boolean)
|
||||
.map((s) => JSON.parse(s));
|
||||
|
||||
return normalizedRecords.some(predicate);
|
||||
});
|
||||
}
|
||||
|
||||
function isExecutionContextLog(
|
||||
record: string | undefined,
|
||||
executionContext: KibanaExecutionContext
|
||||
) {
|
||||
if (!record) return false;
|
||||
try {
|
||||
const object = JSON.parse(record);
|
||||
return isEqual(object, executionContext);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
describe('Execution context service', () => {
|
||||
before(async () => {
|
||||
await PageObjects.common.navigateToUrl('home', '/tutorial_directory/sampleData', {
|
||||
useActualUrl: true,
|
||||
});
|
||||
await PageObjects.home.addSampleDataSet('flights');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await PageObjects.common.navigateToUrl('home', '/tutorial_directory/sampleData', {
|
||||
useActualUrl: true,
|
||||
});
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.home.removeSampleDataSet('flights');
|
||||
});
|
||||
|
||||
describe('discover app', () => {
|
||||
before(async () => {
|
||||
await PageObjects.common.navigateToApp('discover');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
|
||||
it('propagates context for Discover', async () => {
|
||||
await assertLogContains(
|
||||
'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
(record) => Boolean(record.http?.request?.id?.includes('kibana:application:discover'))
|
||||
);
|
||||
|
||||
await assertLogContains('execution context propagates to Kibana logs', (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
description: 'fetch documents',
|
||||
id: '',
|
||||
name: 'discover',
|
||||
type: 'application',
|
||||
// discovery doesn't have an URL since one of from the example dataset is not saved separately
|
||||
url: '/app/discover',
|
||||
})
|
||||
);
|
||||
|
||||
await assertLogContains('execution context propagates to Kibana logs', (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
description: 'fetch chart data and total hits',
|
||||
id: '',
|
||||
name: 'discover',
|
||||
type: 'application',
|
||||
url: '/app/discover',
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('dashboard app', () => {
|
||||
before(async () => {
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.loadSavedDashboard('[Flights] Global Flight Dashboard');
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
|
||||
describe('propagates context for Lens visualizations', () => {
|
||||
it('lnsXY', async () => {
|
||||
await assertLogContains(
|
||||
'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
(record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;lens:lnsXY:086ac2e9-dd16-4b45-92b8-1e43ff7e3f65'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
await assertLogContains('execution context propagates to Kibana logs', (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'lens',
|
||||
name: 'lnsXY',
|
||||
id: '086ac2e9-dd16-4b45-92b8-1e43ff7e3f65',
|
||||
description: '[Flights] Flight count',
|
||||
url: '/app/lens#/edit_by_value',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('lnsMetric', async () => {
|
||||
await assertLogContains(
|
||||
'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
(record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;lens:lnsMetric:b766e3b8-4544-46ed-99e6-9ecc4847e2a2'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
await assertLogContains('execution context propagates to Kibana logs', (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'lens',
|
||||
name: 'lnsMetric',
|
||||
id: '2e33ade5-96e5-40b4-b460-493e5d4fa834',
|
||||
description: '',
|
||||
url: '/app/lens#/edit_by_value',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('lnsDatatable', async () => {
|
||||
await assertLogContains(
|
||||
'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
(record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;lens:lnsDatatable:fb86b32f-fb7a-45cf-9511-f366fef51bbd'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
await assertLogContains('execution context propagates to Kibana logs', (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'lens',
|
||||
name: 'lnsDatatable',
|
||||
id: 'fb86b32f-fb7a-45cf-9511-f366fef51bbd',
|
||||
description: 'Cities by delay, cancellation',
|
||||
url: '/app/lens#/edit_by_value',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('lnsPie', async () => {
|
||||
await assertLogContains(
|
||||
'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
(record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;lens:lnsPie:5d53db36-2d5a-4adc-af7b-cec4c1a294e0'
|
||||
)
|
||||
)
|
||||
);
|
||||
await assertLogContains('execution context propagates to Kibana logs', (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'lens',
|
||||
name: 'lnsPie',
|
||||
id: '5d53db36-2d5a-4adc-af7b-cec4c1a294e0',
|
||||
description: '[Flights] Delay Type',
|
||||
url: '/app/lens#/edit_by_value',
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('propagates context for built-in Discover', async () => {
|
||||
await assertLogContains(
|
||||
'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
(record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;search:discover:571aaf70-4c88-11e8-b3d7-01146121b73d'
|
||||
)
|
||||
)
|
||||
);
|
||||
await assertLogContains('execution context propagates to Kibana logs', (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'search',
|
||||
name: 'discover',
|
||||
id: '571aaf70-4c88-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Flight Log',
|
||||
url: '/app/discover#/view/571aaf70-4c88-11e8-b3d7-01146121b73d',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('propagates context for TSVB visualizations', async () => {
|
||||
await assertLogContains(
|
||||
'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
(record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;visualization:TSVB:bcb63b50-4c89-11e8-b3d7-01146121b73d'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
await assertLogContains('execution context propagates to Kibana logs', (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'visualization',
|
||||
name: 'TSVB',
|
||||
id: 'bcb63b50-4c89-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Delays & Cancellations',
|
||||
url: '/app/visualize#/edit/bcb63b50-4c89-11e8-b3d7-01146121b73d',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('propagates context for Vega visualizations', async () => {
|
||||
await assertLogContains(
|
||||
'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
(record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;visualization:Vega:ed78a660-53a0-11e8-acbd-0be0ad9d822b'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
await assertLogContains('execution context propagates to Kibana logs', (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'visualization',
|
||||
name: 'Vega',
|
||||
id: 'ed78a660-53a0-11e8-acbd-0be0ad9d822b',
|
||||
description: '[Flights] Airport Connections (Hover Over Airport)',
|
||||
url: '/app/visualize#/edit/ed78a660-53a0-11e8-acbd-0be0ad9d822b',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('propagates context for Tag Cloud visualization', async () => {
|
||||
await assertLogContains(
|
||||
'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
(record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;visualization:Tag cloud:293b5a30-4c8f-11e8-b3d7-01146121b73d'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
await assertLogContains('execution context propagates to Kibana logs', (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'visualization',
|
||||
name: 'Tag cloud',
|
||||
id: '293b5a30-4c8f-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Destination Weather',
|
||||
url: '/app/visualize#/edit/293b5a30-4c8f-11e8-b3d7-01146121b73d',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('propagates context for Vertical bar visualization', async () => {
|
||||
await assertLogContains(
|
||||
'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
(record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;visualization:Vertical bar:9886b410-4c8b-11e8-b3d7-01146121b73d'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
await assertLogContains('execution context propagates to Kibana logs', (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'visualization',
|
||||
name: 'Vertical bar',
|
||||
id: '9886b410-4c8b-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Delay Buckets',
|
||||
url: '/app/visualize#/edit/9886b410-4c8b-11e8-b3d7-01146121b73d',
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -92,4 +92,5 @@ require('@kbn/test').runTestsCli([
|
|||
require.resolve('../test/fleet_functional/config.ts'),
|
||||
require.resolve('../test/examples/config.ts'),
|
||||
require.resolve('../test/performance/config.ts'),
|
||||
require.resolve('../test/functional_execution_context/config.ts'),
|
||||
]);
|
||||
|
|
|
@ -1,16 +1,26 @@
|
|||
/*
|
||||
* 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.
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
import Path from 'path';
|
||||
import { CA_CERT_PATH } from '@kbn/dev-utils';
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
import { logFilePath } from './test_utils';
|
||||
|
||||
const alertTestPlugin = Path.resolve(__dirname, './fixtures/plugins/alerts');
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const functionalConfig = await readConfigFile(require.resolve('../functional/config'));
|
||||
const functionalConfig = await readConfigFile(require.resolve('../../test/functional/config'));
|
||||
|
||||
const servers = {
|
||||
...functionalConfig.get('servers'),
|
||||
elasticsearch: {
|
||||
...functionalConfig.get('servers.elasticsearch'),
|
||||
protocol: 'https',
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
...functionalConfig.getAll(),
|
||||
|
@ -19,24 +29,31 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
junit: {
|
||||
reportName: 'Execution Context Functional Tests',
|
||||
},
|
||||
servers,
|
||||
esTestCluster: {
|
||||
...functionalConfig.get('esTestCluster'),
|
||||
ssl: true,
|
||||
},
|
||||
kbnTestServer: {
|
||||
...functionalConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...functionalConfig.get('kbnTestServer.serverArgs'),
|
||||
`--plugin-path=${alertTestPlugin}`,
|
||||
`--elasticsearch.hosts=${servers.elasticsearch.protocol}://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`,
|
||||
`--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`,
|
||||
|
||||
'--execution_context.enabled=true',
|
||||
'--logging.appenders.file.type=file',
|
||||
`--logging.appenders.file.fileName=${Path.resolve(__dirname, './kibana.log')}`,
|
||||
`--logging.appenders.file.fileName=${logFilePath}`,
|
||||
'--logging.appenders.file.layout.type=json',
|
||||
|
||||
'--logging.loggers[0].name=elasticsearch.query',
|
||||
'--logging.loggers[0].level=all',
|
||||
// eslint-disable-next-line prettier/prettier
|
||||
'--logging.loggers[0].appenders=[\"file\"]',
|
||||
`--logging.loggers[0].appenders=${JSON.stringify(['file'])}`,
|
||||
|
||||
'--logging.loggers[1].name=execution_context',
|
||||
'--logging.loggers[1].level=debug',
|
||||
// eslint-disable-next-line prettier/prettier
|
||||
'--logging.loggers[1].appenders=[\"file\"]',
|
||||
`--logging.loggers[1].appenders=${JSON.stringify(['file'])}`,
|
||||
],
|
||||
},
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"id": "alertsFixtures",
|
||||
"owner": {
|
||||
"name": "Core team",
|
||||
"githubTeam": "kibana-core"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"kibanaVersion": "kibana",
|
||||
"configPath": ["xpack"],
|
||||
"requiredPlugins": ["features", "alerting"],
|
||||
"server": true,
|
||||
"ui": false
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "alerts-fixtures",
|
||||
"version": "1.0.0",
|
||||
"kibana": {
|
||||
"version": "kibana",
|
||||
"templateVersion": "1.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"kbn": "node ../../../../../../scripts/kbn.js",
|
||||
"build": "rm -rf './target' && ../../../../../../node_modules/.bin/tsc"
|
||||
},
|
||||
"license": "Elastic License 2.0"
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FixturePlugin } from './plugin';
|
||||
|
||||
export const plugin = () => new FixturePlugin();
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { Plugin, CoreSetup } from 'kibana/server';
|
||||
import { PluginSetupContract as AlertingPluginSetup } from '../../../../../../plugins/alerting/server/plugin';
|
||||
import { EncryptedSavedObjectsPluginStart } from '../../../../../../plugins/encrypted_saved_objects/server';
|
||||
import { PluginSetupContract as FeaturesPluginSetup } from '../../../../../../plugins/features/server';
|
||||
import { SpacesPluginStart } from '../../../../../../plugins/spaces/server';
|
||||
import { SecurityPluginStart } from '../../../../../../plugins/security/server';
|
||||
|
||||
export interface FixtureSetupDeps {
|
||||
features: FeaturesPluginSetup;
|
||||
alerting: AlertingPluginSetup;
|
||||
}
|
||||
|
||||
export interface FixtureStartDeps {
|
||||
encryptedSavedObjects: EncryptedSavedObjectsPluginStart;
|
||||
security?: SecurityPluginStart;
|
||||
spaces?: SpacesPluginStart;
|
||||
}
|
||||
|
||||
export class FixturePlugin implements Plugin<void, void, FixtureSetupDeps, FixtureStartDeps> {
|
||||
constructor() {}
|
||||
|
||||
public setup(core: CoreSetup<FixtureStartDeps>, { features, alerting }: FixtureSetupDeps) {
|
||||
features.registerKibanaFeature({
|
||||
id: 'alertsFixture',
|
||||
name: 'Alerts',
|
||||
app: ['alerts', 'kibana'],
|
||||
category: { id: 'foo', label: 'foo' },
|
||||
alerting: ['test.executionContext'],
|
||||
privileges: {
|
||||
all: {
|
||||
app: ['alerts', 'kibana'],
|
||||
savedObject: {
|
||||
all: ['alert'],
|
||||
read: [],
|
||||
},
|
||||
alerting: {
|
||||
rule: {
|
||||
all: ['test.executionContext'],
|
||||
},
|
||||
},
|
||||
ui: [],
|
||||
},
|
||||
read: {
|
||||
app: ['alerts', 'kibana'],
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: ['alert'],
|
||||
},
|
||||
alerting: {
|
||||
rule: {
|
||||
read: ['test.executionContext'],
|
||||
},
|
||||
},
|
||||
ui: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
alerting.registerType({
|
||||
id: 'test.executionContext',
|
||||
name: 'Test: Query Elasticsearch server',
|
||||
actionGroups: [
|
||||
{
|
||||
id: 'default',
|
||||
name: 'Default',
|
||||
},
|
||||
],
|
||||
producer: 'alertsFixture',
|
||||
defaultActionGroupId: 'default',
|
||||
minimumLicenseRequired: 'basic',
|
||||
isExportable: true,
|
||||
async executor() {
|
||||
const [coreStart] = await core.getStartServices();
|
||||
await coreStart.elasticsearch.client.asInternalUser.ping();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public start() {}
|
||||
public stop() {}
|
||||
}
|
|
@ -1,13 +1,12 @@
|
|||
/*
|
||||
* 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.
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { GenericFtrProviderContext } from '@kbn/test';
|
||||
import { pageObjects } from '../functional/page_objects';
|
||||
import { pageObjects } from '../../test/functional/page_objects';
|
||||
import { services } from './services';
|
||||
|
||||
export type FtrProviderContext = GenericFtrProviderContext<typeof services, typeof pageObjects>;
|
10
x-pack/test/functional_execution_context/services.ts
Normal file
10
x-pack/test/functional_execution_context/services.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { services as functionalServices } from '../../test/functional/services';
|
||||
|
||||
export const services = functionalServices;
|
52
x-pack/test/functional_execution_context/test_utils.ts
Normal file
52
x-pack/test/functional_execution_context/test_utils.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import Fs from 'fs/promises';
|
||||
import Path from 'path';
|
||||
import { isEqualWith } from 'lodash';
|
||||
import type { Ecs, KibanaExecutionContext } from 'kibana/server';
|
||||
import type { RetryService } from '../../../test/common/services/retry';
|
||||
|
||||
export const logFilePath = Path.resolve(__dirname, './kibana.log');
|
||||
export const ANY = Symbol('any');
|
||||
|
||||
export function isExecutionContextLog(
|
||||
record: string | undefined,
|
||||
executionContext: KibanaExecutionContext
|
||||
) {
|
||||
if (!record) return false;
|
||||
try {
|
||||
const object = JSON.parse(record);
|
||||
return isEqualWith(object, executionContext, function customizer(obj1: any, obj2: any) {
|
||||
if (obj2 === ANY) return true;
|
||||
});
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// to avoid splitting log record containing \n symbol
|
||||
const endOfLine = /(?<=})\s*\n/;
|
||||
export async function assertLogContains({
|
||||
description,
|
||||
predicate,
|
||||
retry,
|
||||
}: {
|
||||
description: string;
|
||||
predicate: (record: Ecs) => boolean;
|
||||
retry: RetryService;
|
||||
}): Promise<void> {
|
||||
// logs are written to disk asynchronously. I sacrificed performance to reduce flakiness.
|
||||
await retry.waitFor(description, async () => {
|
||||
const logsStr = await Fs.readFile(logFilePath, 'utf-8');
|
||||
const normalizedRecords = logsStr
|
||||
.split(endOfLine)
|
||||
.filter(Boolean)
|
||||
.map((s) => JSON.parse(s));
|
||||
|
||||
return normalizedRecords.some(predicate);
|
||||
});
|
||||
}
|
381
x-pack/test/functional_execution_context/tests/browser.ts
Normal file
381
x-pack/test/functional_execution_context/tests/browser.ts
Normal file
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FtrProviderContext } from '../ftr_provider_context';
|
||||
import { assertLogContains, isExecutionContextLog } from '../test_utils';
|
||||
|
||||
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const PageObjects = getPageObjects(['common', 'dashboard', 'header', 'home']);
|
||||
const retry = getService('retry');
|
||||
|
||||
describe('Browser apps', () => {
|
||||
before(async () => {
|
||||
await PageObjects.common.navigateToUrl('home', '/tutorial_directory/sampleData', {
|
||||
useActualUrl: true,
|
||||
});
|
||||
await PageObjects.home.addSampleDataSet('flights');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await PageObjects.common.navigateToUrl('home', '/tutorial_directory/sampleData', {
|
||||
useActualUrl: true,
|
||||
});
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.home.removeSampleDataSet('flights');
|
||||
});
|
||||
|
||||
describe('discover app', () => {
|
||||
before(async () => {
|
||||
await PageObjects.common.navigateToApp('discover');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
|
||||
it('propagates context for Discover', async () => {
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(record.http?.request?.id?.includes('kibana:application:discover')),
|
||||
retry,
|
||||
});
|
||||
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
description: 'fetch documents',
|
||||
id: '',
|
||||
name: 'discover',
|
||||
type: 'application',
|
||||
// discovery doesn't have an URL since one of from the example dataset is not saved separately
|
||||
url: '/app/discover',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
description: 'fetch chart data and total hits',
|
||||
id: '',
|
||||
name: 'discover',
|
||||
type: 'application',
|
||||
url: '/app/discover',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('dashboard app', () => {
|
||||
before(async () => {
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.loadSavedDashboard('[Flights] Global Flight Dashboard');
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
|
||||
describe('propagates context for Lens visualizations', () => {
|
||||
it('lnsXY', async () => {
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;lens:lnsXY:086ac2e9-dd16-4b45-92b8-1e43ff7e3f65'
|
||||
)
|
||||
),
|
||||
retry,
|
||||
});
|
||||
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'lens',
|
||||
name: 'lnsXY',
|
||||
id: '086ac2e9-dd16-4b45-92b8-1e43ff7e3f65',
|
||||
description: '[Flights] Flight count',
|
||||
url: '/app/lens#/edit_by_value',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
});
|
||||
|
||||
it('lnsMetric', async () => {
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;lens:lnsMetric:b766e3b8-4544-46ed-99e6-9ecc4847e2a2'
|
||||
)
|
||||
),
|
||||
retry,
|
||||
});
|
||||
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'lens',
|
||||
name: 'lnsMetric',
|
||||
id: '2e33ade5-96e5-40b4-b460-493e5d4fa834',
|
||||
description: '',
|
||||
url: '/app/lens#/edit_by_value',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
});
|
||||
|
||||
it('lnsDatatable', async () => {
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;lens:lnsDatatable:fb86b32f-fb7a-45cf-9511-f366fef51bbd'
|
||||
)
|
||||
),
|
||||
retry,
|
||||
});
|
||||
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'lens',
|
||||
name: 'lnsDatatable',
|
||||
id: 'fb86b32f-fb7a-45cf-9511-f366fef51bbd',
|
||||
description: 'Cities by delay, cancellation',
|
||||
url: '/app/lens#/edit_by_value',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
});
|
||||
|
||||
it('lnsPie', async () => {
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;lens:lnsPie:5d53db36-2d5a-4adc-af7b-cec4c1a294e0'
|
||||
)
|
||||
),
|
||||
retry,
|
||||
});
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'lens',
|
||||
name: 'lnsPie',
|
||||
id: '5d53db36-2d5a-4adc-af7b-cec4c1a294e0',
|
||||
description: '[Flights] Delay Type',
|
||||
url: '/app/lens#/edit_by_value',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('propagates context for built-in Discover', async () => {
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;search:discover:571aaf70-4c88-11e8-b3d7-01146121b73d'
|
||||
)
|
||||
),
|
||||
retry,
|
||||
});
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'search',
|
||||
name: 'discover',
|
||||
id: '571aaf70-4c88-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Flight Log',
|
||||
url: '/app/discover#/view/571aaf70-4c88-11e8-b3d7-01146121b73d',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
});
|
||||
|
||||
it('propagates context for TSVB visualizations', async () => {
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;visualization:TSVB:bcb63b50-4c89-11e8-b3d7-01146121b73d'
|
||||
)
|
||||
),
|
||||
retry,
|
||||
});
|
||||
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'visualization',
|
||||
name: 'TSVB',
|
||||
id: 'bcb63b50-4c89-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Delays & Cancellations',
|
||||
url: '/app/visualize#/edit/bcb63b50-4c89-11e8-b3d7-01146121b73d',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
});
|
||||
|
||||
it('propagates context for Vega visualizations', async () => {
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;visualization:Vega:ed78a660-53a0-11e8-acbd-0be0ad9d822b'
|
||||
)
|
||||
),
|
||||
retry,
|
||||
});
|
||||
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'visualization',
|
||||
name: 'Vega',
|
||||
id: 'ed78a660-53a0-11e8-acbd-0be0ad9d822b',
|
||||
description: '[Flights] Airport Connections (Hover Over Airport)',
|
||||
url: '/app/visualize#/edit/ed78a660-53a0-11e8-acbd-0be0ad9d822b',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
});
|
||||
|
||||
it('propagates context for Tag Cloud visualization', async () => {
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;visualization:Tag cloud:293b5a30-4c8f-11e8-b3d7-01146121b73d'
|
||||
)
|
||||
),
|
||||
retry,
|
||||
});
|
||||
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'visualization',
|
||||
name: 'Tag cloud',
|
||||
id: '293b5a30-4c8f-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Destination Weather',
|
||||
url: '/app/visualize#/edit/293b5a30-4c8f-11e8-b3d7-01146121b73d',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
});
|
||||
|
||||
it('propagates context for Vertical bar visualization', async () => {
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(
|
||||
'kibana:application:dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d;visualization:Vertical bar:9886b410-4c8b-11e8-b3d7-01146121b73d'
|
||||
)
|
||||
),
|
||||
retry,
|
||||
});
|
||||
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'application',
|
||||
name: 'dashboard',
|
||||
id: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Global Flight Dashboard',
|
||||
url: '/view/7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
},
|
||||
type: 'visualization',
|
||||
name: 'Vertical bar',
|
||||
id: '9886b410-4c8b-11e8-b3d7-01146121b73d',
|
||||
description: '[Flights] Delay Buckets',
|
||||
url: '/app/visualize#/edit/9886b410-4c8b-11e8-b3d7-01146121b73d',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../ftr_provider_context';
|
||||
|
@ -11,6 +10,7 @@ import { FtrProviderContext } from '../ftr_provider_context';
|
|||
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||
describe('Execution context', function () {
|
||||
this.tags('ciGroup1');
|
||||
loadTestFile(require.resolve('./execution_context'));
|
||||
loadTestFile(require.resolve('./browser'));
|
||||
loadTestFile(require.resolve('./server'));
|
||||
});
|
||||
}
|
112
x-pack/test/functional_execution_context/tests/server.ts
Normal file
112
x-pack/test/functional_execution_context/tests/server.ts
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import type { FtrProviderContext } from '../ftr_provider_context';
|
||||
import { assertLogContains, isExecutionContextLog, ANY } from '../test_utils';
|
||||
|
||||
function delay(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const retry = getService('retry');
|
||||
const supertest = getService('supertest');
|
||||
const log = getService('log');
|
||||
|
||||
async function waitForStatus(
|
||||
id: string,
|
||||
statuses: Set<string>,
|
||||
waitMillis: number = 10000
|
||||
): Promise<Record<string, any>> {
|
||||
if (waitMillis < 0) {
|
||||
expect().fail(`waiting for alert ${id} statuses ${Array.from(statuses)} timed out`);
|
||||
}
|
||||
|
||||
const response = await supertest.get(`/api/alerting/rule/${id}`);
|
||||
expect(response.status).to.eql(200);
|
||||
const { status } = response.body.execution_status;
|
||||
if (statuses.has(status)) return response.body.execution_status;
|
||||
|
||||
log.debug(
|
||||
`waitForStatus(${Array.from(statuses)} for id:${id}): got ${JSON.stringify(
|
||||
response.body.execution_status
|
||||
)}, retrying`
|
||||
);
|
||||
|
||||
const WaitForStatusIncrement = 500;
|
||||
await delay(WaitForStatusIncrement);
|
||||
return await waitForStatus(id, statuses, waitMillis - WaitForStatusIncrement);
|
||||
}
|
||||
|
||||
describe('Server-side apps', () => {
|
||||
it('propagates context for Task and Alerts', async () => {
|
||||
const { body: createdAlert } = await supertest
|
||||
.post('/api/alerting/rule')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
enabled: true,
|
||||
name: 'abc',
|
||||
tags: ['foo'],
|
||||
rule_type_id: 'test.executionContext',
|
||||
consumer: 'alertsFixture',
|
||||
schedule: { interval: '3s' },
|
||||
throttle: '20s',
|
||||
actions: [],
|
||||
params: {},
|
||||
notify_when: 'onThrottleInterval',
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
const alertId = createdAlert.id;
|
||||
|
||||
await waitForStatus(alertId, new Set(['ok']), 90_000);
|
||||
|
||||
await assertLogContains({
|
||||
description:
|
||||
'task manager execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(
|
||||
// exclude part with taskId
|
||||
record.http?.request?.id?.includes(
|
||||
`kibana:task manager:run alerting:test.executionContext:`
|
||||
)
|
||||
),
|
||||
retry,
|
||||
});
|
||||
|
||||
await assertLogContains({
|
||||
description:
|
||||
'alerting execution context propagates to Elasticsearch via "x-opaque-id" header',
|
||||
predicate: (record) =>
|
||||
Boolean(
|
||||
record.http?.request?.id?.includes(`alert:execute test.executionContext:${alertId}`)
|
||||
),
|
||||
retry,
|
||||
});
|
||||
|
||||
await assertLogContains({
|
||||
description: 'execution context propagates to Kibana logs',
|
||||
predicate: (record) =>
|
||||
isExecutionContextLog(record?.message, {
|
||||
parent: {
|
||||
type: 'task manager',
|
||||
name: 'run alerting:test.executionContext',
|
||||
// @ts-expect-error. it accepts strings only
|
||||
id: ANY,
|
||||
description: 'run task',
|
||||
},
|
||||
type: 'alert',
|
||||
name: 'execute test.executionContext',
|
||||
id: alertId,
|
||||
description: 'execute [test.executionContext] with name [abc] in [default] namespace',
|
||||
}),
|
||||
retry,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue