[EBT] Better FTR helper APIs (#135298)

This commit is contained in:
Alejandro Fernández Haro 2022-06-29 14:11:13 +02:00 committed by GitHub
parent a6f17d5dd2
commit a2b0927e65
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 461 additions and 118 deletions

View file

@ -25,7 +25,7 @@ export function getPluginSearchPaths({ rootDir, oss, examples, testPlugins }: Se
resolve(rootDir, '..', 'kibana-extra'),
...(testPlugins
? [
resolve(rootDir, 'test/analytics/__fixtures__/plugins'),
resolve(rootDir, 'test/analytics/fixtures/plugins'),
resolve(rootDir, 'test/plugin_functional/plugins'),
resolve(rootDir, 'test/interpreter_functional/plugins'),
resolve(rootDir, 'test/common/fixtures/plugins'),

View file

@ -2168,7 +2168,7 @@ function getPluginSearchPaths({
examples,
testPlugins
}) {
return [(0, _path.resolve)(rootDir, 'src', 'plugins'), ...(oss ? [] : [(0, _path.resolve)(rootDir, 'x-pack', 'plugins')]), (0, _path.resolve)(rootDir, 'plugins'), ...(examples ? [(0, _path.resolve)(rootDir, 'examples')] : []), ...(examples && !oss ? [(0, _path.resolve)(rootDir, 'x-pack', 'examples')] : []), (0, _path.resolve)(rootDir, '..', 'kibana-extra'), ...(testPlugins ? [(0, _path.resolve)(rootDir, 'test/analytics/__fixtures__/plugins'), (0, _path.resolve)(rootDir, 'test/plugin_functional/plugins'), (0, _path.resolve)(rootDir, 'test/interpreter_functional/plugins'), (0, _path.resolve)(rootDir, 'test/common/fixtures/plugins')] : []), ...(testPlugins && !oss ? [(0, _path.resolve)(rootDir, 'x-pack/test/plugin_functional/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/functional_with_es_ssl/fixtures/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/alerting_api_integration/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/plugin_api_integration/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/plugin_api_perf/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/licensing_plugin/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/usage_collection/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/security_functional/fixtures/common')] : [])];
return [(0, _path.resolve)(rootDir, 'src', 'plugins'), ...(oss ? [] : [(0, _path.resolve)(rootDir, 'x-pack', 'plugins')]), (0, _path.resolve)(rootDir, 'plugins'), ...(examples ? [(0, _path.resolve)(rootDir, 'examples')] : []), ...(examples && !oss ? [(0, _path.resolve)(rootDir, 'x-pack', 'examples')] : []), (0, _path.resolve)(rootDir, '..', 'kibana-extra'), ...(testPlugins ? [(0, _path.resolve)(rootDir, 'test/analytics/fixtures/plugins'), (0, _path.resolve)(rootDir, 'test/plugin_functional/plugins'), (0, _path.resolve)(rootDir, 'test/interpreter_functional/plugins'), (0, _path.resolve)(rootDir, 'test/common/fixtures/plugins')] : []), ...(testPlugins && !oss ? [(0, _path.resolve)(rootDir, 'x-pack/test/plugin_functional/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/functional_with_es_ssl/fixtures/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/alerting_api_integration/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/plugin_api_integration/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/plugin_api_perf/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/licensing_plugin/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/usage_collection/plugins'), (0, _path.resolve)(rootDir, 'x-pack/test/security_functional/fixtures/common')] : [])];
}
/***/ }),

View file

@ -89,6 +89,7 @@ export const PROJECTS = [
'x-pack/plugins/*/tsconfig.json',
'examples/*/tsconfig.json',
'x-pack/examples/*/tsconfig.json',
'test/analytics/fixtures/plugins/*/tsconfig.json',
'test/plugin_functional/plugins/*/tsconfig.json',
'test/interpreter_functional/plugins/*/tsconfig.json',
'test/server_integration/__fixtures__/plugins/*/tsconfig.json',

View file

@ -14,8 +14,10 @@ There are 2 FTR helpers to allow you to retrieve the generated events:
The API is the same for both of them:
```typescript
// To retrieve 2 events of type "my-event-type"
const events = await getService('kibana_ebt_ui').getEvents(2, ['my-event-type']);
const events = await getService('kibana_ebt_ui').getEvents(2, { eventTypes: ['my-event-type'] });
expect(events).to...
```
If you are reusing these helpers in another suite, please remember to make sure to optIn via `await getService('kibana_ebt_ui').setOptIn(true);`
If you are reusing these helpers in another suite, please remember to make sure to optIn via `await getService('kibana_ebt_ui').setOptIn(true);`
Refer to [`EBTHelpersContract`](./fixtures/plugins/analytics_ftr_helpers/common/types.ts#:~:text=EBTHelpersContract) for more details about the existing APIs and all the options they accept.

View file

@ -35,8 +35,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
serverArgs: [
...functionalConfig.get('kbnTestServer.serverArgs'),
'--telemetry.optIn=true',
`--plugin-path=${path.resolve(__dirname, './__fixtures__/plugins/analytics_plugin_a')}`,
`--plugin-path=${path.resolve(__dirname, './__fixtures__/plugins/analytics_ftr_helpers')}`,
`--plugin-path=${path.resolve(__dirname, './fixtures/plugins/analytics_plugin_a')}`,
`--plugin-path=${path.resolve(__dirname, './fixtures/plugins/analytics_ftr_helpers')}`,
],
},
};

View file

@ -0,0 +1,57 @@
/*
* 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 {
filter,
firstValueFrom,
map,
NEVER,
type Observable,
take,
takeUntil,
timer,
toArray,
} from 'rxjs';
import type { Event } from '@kbn/analytics-client';
import type { GetEventsOptions } from './types';
export async function fetchEvents(
events$: Observable<Event>,
takeNumberOfEvents: number,
options: GetEventsOptions = {}
): Promise<Event[]> {
const { eventTypes = [], withTimeoutMs, fromTimestamp } = options;
const filteredEvents$ = events$.pipe(
filter((event) => {
if (eventTypes.length > 0) {
return eventTypes.includes(event.event_type);
}
return true;
}),
filter((event) => {
if (fromTimestamp) {
return new Date(event.timestamp).getTime() - new Date(fromTimestamp).getTime() >= 0;
}
return true;
})
);
return firstValueFrom(
filteredEvents$.pipe(
take(takeNumberOfEvents),
// If timeout is specified, close the subscriber when the timeout occurs
takeUntil(withTimeoutMs ? timer(withTimeoutMs) : NEVER),
toArray(),
// Sorting the events by timestamp... on CI it's happening an event may occur while the client is still forwarding the early ones...
map((_events) =>
_events.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime())
)
)
);
}

View file

@ -0,0 +1,49 @@
/*
* 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 { Event, EventType } from '@kbn/analytics-client';
export interface GetEventsOptions {
/**
* eventTypes (optional) array of event types to return
*/
eventTypes?: EventType[];
/**
* withTimeoutMs (optional) if specified, the method returns all the events received when the first occurs:
* - The number of received events match `takeNumberOfEvents`.
* - The number of ms in `withTimeoutMs` has elapsed.
*/
withTimeoutMs?: number;
/**
* fromTimestamp (optional) if specified, only the events that are greater or equal to the provided timestamp will be returned.
* @remarks Useful when we need to retrieve the events after a specific action, and we don't care about anything prior to that.
*/
fromTimestamp?: string;
}
export interface EBTHelpersContract {
/**
* Change the opt-in state of the Kibana EBT client.
* @param optIn `true` to opt-in, `false` to opt-out.
*/
setOptIn: (optIn: boolean) => void;
/**
* Returns the first N number of events of the specified types.
* @param takeNumberOfEvents - number of events to return
* @param options (optional) list of options to filter events or for advanced usage of the API {@link GetEventsOptions}.
*/
getEvents: (takeNumberOfEvents: number, options?: GetEventsOptions) => Promise<Event[]>;
/**
* Count the number of events that match the filters.
* @param options list of options to filter the events {@link GetEventsOptions}. `withTimeoutMs` is required in this API.
*/
getEventCount: (
options: Required<Pick<GetEventsOptions, 'withTimeoutMs'>> &
Omit<GetEventsOptions, 'withTimeoutMs'>
) => Promise<number>;
}

View file

@ -0,0 +1,19 @@
/*
* 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.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../../../..',
roots: ['<rootDir>/test/analytics/fixtures/plugins/analytics_ftr_helpers'],
coverageDirectory:
'<rootDir>/target/kibana-coverage/jest/test/analytics/fixtures/plugins/analytics_ftr_helpers',
coverageReporters: ['text', 'html'],
collectCoverageFrom: [
'<rootDir>/test/analytics/fixtures/plugins/analytics_ftr_helpers/{common,public,server}/**/*.{ts,tsx}',
],
};

View file

@ -1,7 +1,7 @@
{
"name": "analytics_ftr_helpers",
"version": "1.0.0",
"main": "target/test/analytics/__fixtures__/plugins/analytics_ftr_helpers",
"main": "target/test/analytics/fixtures/plugins/analytics_ftr_helpers",
"kibana": {
"version": "kibana",
"templateVersion": "1.0.0"

View file

@ -0,0 +1,133 @@
/*
* 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 { ReplaySubject } from 'rxjs';
import type { AnalyticsServiceSetup, Event } from '@kbn/core/public';
import { coreMock } from '@kbn/core/public/mocks';
// Importing types to have the window properties defined
import './types';
import { AnalyticsFTRHelpers } from './plugin';
import { withTimeout } from '@kbn/std';
describe('AnalyticsFTRHelpers', () => {
let plugin: AnalyticsFTRHelpers;
let events$: ReplaySubject<Event>;
let analyticsMock: jest.Mocked<AnalyticsServiceSetup>;
beforeEach(() => {
plugin = new AnalyticsFTRHelpers();
// eslint-disable-next-line dot-notation
events$ = plugin['events$'];
const coreSetup = coreMock.createSetup();
analyticsMock = coreSetup.analytics;
plugin.setup(coreSetup);
});
describe('setOptIn', () => {
test.each([true, false])('sets optIn value to %p', (optInValue) => {
window.__analytics_ftr_helpers__.setOptIn(optInValue);
expect(analyticsMock.optIn).toHaveBeenCalledWith({ global: { enabled: optInValue } });
});
});
describe('getEvents', () => {
const event: Event = {
timestamp: new Date().toISOString(),
event_type: 'test-event',
context: {},
properties: {},
};
test('should return any previously enqueued events as long as they match the required number of events', async () => {
// 3 enqueued events
const events = new Array(3).fill(event);
events.forEach((ev) => events$.next(ev));
await expect(window.__analytics_ftr_helpers__.getEvents(3)).resolves.toEqual(events);
});
test('should await until it matches the required number of events', async () => {
// 3 enqueued events
const events = new Array(3).fill(event);
events.forEach((ev) => events$.next(ev));
const getEventsPromise = window.__analytics_ftr_helpers__.getEvents(4);
await expect(withTimeout({ promise: getEventsPromise, timeoutMs: 1000 })).resolves.toEqual({
timedout: true,
});
// we are not filtering in the call by event type, so it should resolve as well
const anotherEvent = { ...event, event_type: 'another-test-event' };
events$.next(anotherEvent);
await expect(getEventsPromise).resolves.toEqual([...events, anotherEvent]);
});
test('should await until it times out', async () => {
// 3 enqueued events
const events = new Array(3).fill(event);
events.forEach((ev) => events$.next(ev));
// expecting 4 with timeout of 1.5s
const getEventsPromise = window.__analytics_ftr_helpers__.getEvents(4, {
withTimeoutMs: 1500,
});
// after 1 second it still doesn't emit
await expect(withTimeout({ promise: getEventsPromise, timeoutMs: 1000 })).resolves.toEqual({
timedout: true,
});
// it emits 3 events at some point
await expect(getEventsPromise).resolves.toEqual(events);
});
test('should filter by event-types when provided', async () => {
// 3 enqueued events
const events = [
{ ...event, event_type: 'one-test-event' },
{ ...event, event_type: 'another-test-event' },
{ ...event, event_type: 'skipped-test-event' },
{ ...event, event_type: 'another-test-event' },
];
events.forEach((ev) => events$.next(ev));
await expect(
window.__analytics_ftr_helpers__.getEvents(3, {
eventTypes: ['one-test-event', 'another-test-event'],
})
).resolves.toEqual([
{ ...event, event_type: 'one-test-event' },
{ ...event, event_type: 'another-test-event' },
{ ...event, event_type: 'another-test-event' },
]);
});
test('should filter by timestamp when provided', async () => {
// 3 enqueued events
const events = [
{ ...event, timestamp: '2022-01-10T00:00:00.000Z' },
{ ...event, timestamp: '2022-03-10T00:00:00.000Z' },
{ ...event, timestamp: '2022-06-10T00:00:00.000Z' },
];
events.forEach((ev) => events$.next(ev));
await expect(
window.__analytics_ftr_helpers__.getEvents(2, {
eventTypes: [event.event_type],
fromTimestamp: '2022-03-10T00:00:00.000Z',
})
).resolves.toEqual([
{ ...event, timestamp: '2022-03-10T00:00:00.000Z' },
{ ...event, timestamp: '2022-06-10T00:00:00.000Z' },
]);
});
});
});

View file

@ -6,10 +6,11 @@
* Side Public License, v 1.
*/
import { ReplaySubject, firstValueFrom, filter, take, toArray, map } from 'rxjs';
import { ReplaySubject } from 'rxjs';
import type { Plugin, CoreSetup, Event } from '@kbn/core/public';
import { CustomShipper } from './custom_shipper';
import './types';
import { fetchEvents } from '../common/fetch_events';
export class AnalyticsFTRHelpers implements Plugin {
private readonly events$ = new ReplaySubject<Event>();
@ -21,25 +22,10 @@ export class AnalyticsFTRHelpers implements Plugin {
setOptIn(optIn: boolean) {
analytics.optIn({ global: { enabled: optIn } });
},
getEvents: async (takeNumberOfEvents, eventTypes = []) =>
firstValueFrom(
this.events$.pipe(
filter((event) => {
if (eventTypes.length > 0) {
return eventTypes.includes(event.event_type);
}
return true;
}),
take(takeNumberOfEvents),
toArray(),
// Sorting the events by timestamp... on CI it's happening an event may occur while the client is still forwarding the early ones...
map((_events) =>
_events.sort(
(a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
)
)
)
),
getEvents: async (takeNumberOfEvents, options) =>
fetchEvents(this.events$, takeNumberOfEvents, options),
getEventCount: async (options) =>
(await fetchEvents(this.events$, Number.MAX_SAFE_INTEGER, options)).length,
};
}
public start() {}

View file

@ -6,13 +6,10 @@
* Side Public License, v 1.
*/
import type { Event, EventType } from '@kbn/core/public';
import { EBTHelpersContract } from '../common/types';
declare global {
interface Window {
__analytics_ftr_helpers__: {
setOptIn: (optIn: boolean) => void;
getEvents: (takeNumberOfEvents: number, eventTypes?: EventType[]) => Promise<Event[]>;
};
__analytics_ftr_helpers__: EBTHelpersContract;
}
}

View file

@ -6,9 +6,10 @@
* Side Public License, v 1.
*/
import { firstValueFrom, ReplaySubject, filter, take, toArray, map } from 'rxjs';
import { ReplaySubject } from 'rxjs';
import { schema } from '@kbn/config-schema';
import type { Plugin, CoreSetup, Event } from '@kbn/core/server';
import { fetchEvents } from '../common/fetch_events';
import { CustomShipper } from './custom_shipper';
export class AnalyticsFTRHelpers implements Plugin {
@ -45,34 +46,34 @@ export class AnalyticsFTRHelpers implements Plugin {
query: schema.object({
takeNumberOfEvents: schema.number({ min: 1 }),
eventTypes: schema.arrayOf(schema.string()),
withTimeoutMs: schema.maybe(schema.number()),
fromTimestamp: schema.maybe(schema.string()),
}),
},
},
async (context, req, res) => {
const { takeNumberOfEvents, eventTypes } = req.query;
const events = await firstValueFrom(
events$.pipe(
filter((event) => {
if (eventTypes.length > 0) {
return eventTypes.includes(event.event_type);
}
return true;
}),
take(takeNumberOfEvents),
toArray(),
// Sorting the events by timestamp... on CI it's happening an event may occur while the client is still forwarding the early ones...
map((_events) =>
_events.sort(
(a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
)
)
)
);
const { takeNumberOfEvents, ...options } = req.query;
const events = await fetchEvents(events$, takeNumberOfEvents, options);
return res.ok({ body: events });
}
);
router.get(
{
path: '/internal/analytics_ftr_helpers/count_events',
validate: {
query: schema.object({
eventTypes: schema.arrayOf(schema.string()),
withTimeoutMs: schema.number(),
fromTimestamp: schema.maybe(schema.string()),
}),
},
},
async (context, req, res) => {
const events = await fetchEvents(events$, Number.MAX_SAFE_INTEGER, req.query);
return res.ok({ body: { count: events.length } });
}
);
}
public start() {}

View file

@ -5,6 +5,7 @@
},
"include": [
"index.ts",
"common/**/*.ts",
"public/**/*.ts",
"server/**/*.ts",
"../../../../../typings/**/*",

View file

@ -1,7 +1,7 @@
{
"name": "analytics_plugin_a",
"version": "1.0.0",
"main": "target/test/analytics/__fixtures__/plugins/analytics_plugin_a",
"main": "target/test/analytics/fixtures/plugins/analytics_plugin_a",
"kibana": {
"version": "kibana",
"templateVersion": "1.0.0"

View file

@ -0,0 +1,13 @@
/*
* 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.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../..',
roots: ['<rootDir>/test/analytics'],
};

View file

@ -6,10 +6,11 @@
* Side Public License, v 1.
*/
import { FtrProviderContext } from '../../functional/ftr_provider_context';
import '@kbn/analytics-ftr-helpers-plugin/public/types';
import type { EBTHelpersContract } from '@kbn/analytics-ftr-helpers-plugin/common/types';
import type { FtrProviderContext } from '../../functional/ftr_provider_context';
export function KibanaEBTServerProvider({ getService }: FtrProviderContext) {
export function KibanaEBTServerProvider({ getService }: FtrProviderContext): EBTHelpersContract {
const supertest = getService('supertest');
const setOptIn = async (optIn: boolean) => {
@ -21,30 +22,42 @@ export function KibanaEBTServerProvider({ getService }: FtrProviderContext) {
};
return {
/**
* Change the opt-in state of the Kibana EBT client.
* @param optIn `true` to opt-in, `false` to opt-out.
*/
setOptIn,
/**
* Returns the last events of the specified types.
* @param takeNumberOfEvents - number of events to return
* @param eventTypes (Optional) array of event types to return
*/
getEvents: async (takeNumberOfEvents: number, eventTypes: string[] = []) => {
getEvents: async (
takeNumberOfEvents,
{ eventTypes = [], withTimeoutMs, fromTimestamp } = {}
) => {
await setOptIn(true);
const resp = await supertest
.get(`/internal/analytics_ftr_helpers/events`)
.query({ takeNumberOfEvents, eventTypes: JSON.stringify(eventTypes) })
.query({
takeNumberOfEvents,
eventTypes: JSON.stringify(eventTypes),
withTimeoutMs,
fromTimestamp,
})
.set('kbn-xsrf', 'xxx')
.expect(200);
return resp.body;
},
getEventCount: async ({ eventTypes = [], withTimeoutMs, fromTimestamp }) => {
await setOptIn(true);
const resp = await supertest
.get(`/internal/analytics_ftr_helpers/count_events`)
.query({ eventTypes: JSON.stringify(eventTypes), withTimeoutMs, fromTimestamp })
.set('kbn-xsrf', 'xxx')
.expect(200);
return resp.body.count;
},
};
}
export function KibanaEBTUIProvider({ getService, getPageObjects }: FtrProviderContext) {
export function KibanaEBTUIProvider({
getService,
getPageObjects,
}: FtrProviderContext): EBTHelpersContract {
const { common } = getPageObjects(['common']);
const browser = getService('browser');
@ -53,30 +66,24 @@ export function KibanaEBTUIProvider({ getService, getPageObjects }: FtrProviderC
};
return {
/**
* Change the opt-in state of the Kibana EBT client.
* @param optIn `true` to opt-in, `false` to opt-out.
*/
setOptIn: async (optIn: boolean) => {
setOptIn: async (optIn) => {
await common.navigateToApp('home');
await setOptIn(optIn);
},
/**
* Returns the last events of the specified types.
* @param numberOfEvents - number of events to return
* @param eventTypes (Optional) array of event types to return
*/
getEvents: async (numberOfEvents: number, eventTypes: string[] = []) => {
getEvents: async (numberOfEvents, options) => {
await setOptIn(true);
const events = await browser.execute(
({ eventTypes: _eventTypes, numberOfEvents: _numberOfEvents }) =>
window.__analytics_ftr_helpers__.getEvents(_numberOfEvents, _eventTypes),
{
eventTypes,
numberOfEvents,
}
return await browser.execute(
({ numberOfEvents: _numberOfEvents, options: _options }) =>
window.__analytics_ftr_helpers__.getEvents(_numberOfEvents, _options),
{ numberOfEvents, options }
);
},
getEventCount: async (options) => {
await setOptIn(true);
return await browser.execute(
({ options: _options }) => window.__analytics_ftr_helpers__.getEventCount(_options),
{ options }
);
return events;
},
};
}

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import type { Event, TelemetryCounter } from '@kbn/core/server';
import type { Action } from '@kbn/analytics-plugin-a-plugin/server/custom_shipper';
import type { Action } from '@kbn/analytics-plugin-a-plugin/public/custom_shipper';
import type { FtrProviderContext } from '../services';
import '@kbn/analytics-plugin-a-plugin/public/types';
@ -146,7 +146,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
expect(startEvent).to.be.greaterThan(setupEvent);
// This helps us to also test the helpers
const events = await ebtUIHelper.getEvents(2, ['test-plugin-lifecycle']);
const events = await ebtUIHelper.getEvents(2, { eventTypes: ['test-plugin-lifecycle'] });
expect(events).to.eql([
{
timestamp: reportTestPluginLifecycleEventsAction!.meta[setupEvent].timestamp,
@ -164,11 +164,45 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
it('it should extend the contexts with pid injected by "analytics_plugin_a"', async () => {
const [event] = await ebtUIHelper.getEvents(1, ['test-plugin-lifecycle']);
const [event] = await ebtUIHelper.getEvents(1, { eventTypes: ['test-plugin-lifecycle'] });
// Validating the remote user_agent because that's the only field that it's added by the FTR plugin.
expect(event.context).to.have.property('user_agent');
expect(event.context.user_agent).to.be.a('string');
});
describe('Test helpers capabilities', () => {
it('should return the count of the events', async () => {
const eventCount = await ebtUIHelper.getEventCount({
withTimeoutMs: 500,
eventTypes: ['test-plugin-lifecycle'],
});
expect(eventCount).to.be(2);
});
it('should return 0 events when filtering by timestamp', async () => {
const eventCount = await ebtUIHelper.getEventCount({
withTimeoutMs: 500,
eventTypes: ['test-plugin-lifecycle'],
fromTimestamp: new Date().toISOString(),
});
expect(eventCount).to.be(0);
});
it('should return 1 event when filtering by the latest timestamp', async () => {
const events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, {
eventTypes: ['test-plugin-lifecycle'],
withTimeoutMs: 500,
});
expect(events.length).to.be.greaterThan(0);
const lastEvent = events[events.length - 1];
const eventCount = await ebtUIHelper.getEventCount({
withTimeoutMs: 500,
eventTypes: ['test-plugin-lifecycle'],
fromTimestamp: lastEvent.timestamp,
});
expect(eventCount).to.be(1);
});
});
});
});
}

View file

@ -139,7 +139,9 @@ export default function ({ getService }: FtrProviderContext) {
expect(startEvent).to.be.greaterThan(setupEvent);
// This helps us to also test the helpers
const events = await ebtServerHelper.getEvents(2, ['test-plugin-lifecycle']);
const events = await ebtServerHelper.getEvents(2, {
eventTypes: ['test-plugin-lifecycle'],
});
expect(events).to.eql([
{
timestamp: reportTestPluginLifecycleEventsAction!.meta[setupEvent].timestamp,
@ -157,11 +159,46 @@ export default function ({ getService }: FtrProviderContext) {
});
it('it should extend the contexts with pid injected by "analytics_plugin_a"', async () => {
const [event] = await ebtServerHelper.getEvents(1, ['test-plugin-lifecycle']);
const [event] = await ebtServerHelper.getEvents(1, {
eventTypes: ['test-plugin-lifecycle'],
});
// Validating the remote PID because that's the only field that it's added by the FTR plugin.
expect(event.context).to.have.property('pid');
expect(event.context.pid).to.be.a('number');
});
describe('Test helpers capabilities', () => {
it('should return the count of the events', async () => {
const eventCount = await ebtServerHelper.getEventCount({
withTimeoutMs: 500,
eventTypes: ['test-plugin-lifecycle'],
});
expect(eventCount).to.be(2);
});
it('should return 0 events when filtering by timestamp', async () => {
const eventCount = await ebtServerHelper.getEventCount({
withTimeoutMs: 500,
eventTypes: ['test-plugin-lifecycle'],
fromTimestamp: new Date().toISOString(),
});
expect(eventCount).to.be(0);
});
it('should return 1 event when filtering by the latest timestamp', async () => {
const events = await ebtServerHelper.getEvents(Number.MAX_SAFE_INTEGER, {
withTimeoutMs: 500,
eventTypes: ['test-plugin-lifecycle'],
});
expect(events.length).to.be.greaterThan(0);
const lastEvent = events[events.length - 1];
const eventCount = await ebtServerHelper.getEventCount({
withTimeoutMs: 500,
eventTypes: ['test-plugin-lifecycle'],
fromTimestamp: lastEvent.timestamp,
});
expect(eventCount).to.be(1);
});
});
});
});
}

View file

@ -21,7 +21,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
it('should emit a "click" event', async () => {
const [event] = await ebtUIHelper.getEvents(1, ['click']);
const [event] = await ebtUIHelper.getEvents(1, { eventTypes: ['click'] });
expect(event.event_type).to.eql('click');
expect(event.properties.target).to.be.an('array');
const targets = event.properties.target as string[];

View file

@ -19,7 +19,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
let event: Event;
before(async () => {
await common.navigateToApp('home');
[event] = await ebtUIHelper.getEvents(1, ['Loaded Kibana']); // Get the loaded Kibana event
[event] = await ebtUIHelper.getEvents(1, { eventTypes: ['Loaded Kibana'] }); // Get the loaded Kibana event
});
it('should have the properties provided by the "cluster info" context provider', () => {
@ -74,7 +74,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
it('should have the properties provided by the "license info" context provider', async () => {
await common.clickAndValidate('kibanaChrome', 'kibanaChrome');
[event] = await ebtUIHelper.getEvents(1, ['click']); // Get a later event to ensure license has been obtained already.
[event] = await ebtUIHelper.getEvents(1, { eventTypes: ['click'] }); // Get a later event to ensure license has been obtained already.
expect(event.context).to.have.property('license_id');
expect(event.context.license_id).to.be.a('string');
expect(event.context).to.have.property('license_status');

View file

@ -20,7 +20,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
it('should emit the "Loaded Kibana" event', async () => {
const [event] = await ebtUIHelper.getEvents(1, ['Loaded Kibana']);
const [event] = await ebtUIHelper.getEvents(1, { eventTypes: ['Loaded Kibana'] });
expect(event.event_type).to.eql('Loaded Kibana');
expect(event.properties).to.have.property('kibana_version');
expect(event.properties.kibana_version).to.be.a('string');

View file

@ -20,7 +20,9 @@ export default function ({ getService }: FtrProviderContext) {
let i = 2;
do {
// Wait until we get a GREEN "status_changed" event. At that point all the context providers should be set up.
const events = await ebtServerHelper.getEvents(i, ['core-overall_status_changed']);
const events = await ebtServerHelper.getEvents(i, {
eventTypes: ['core-overall_status_changed'],
});
event = events[i - 1];
i++;
} while (event.properties.overall_status_level !== 'available');

View file

@ -18,9 +18,9 @@ export default function ({ getService }: FtrProviderContext) {
let secondEvent: Event;
before(async () => {
[initialEvent, secondEvent] = await ebtServerHelper.getEvents(2, [
'core-overall_status_changed',
]);
[initialEvent, secondEvent] = await ebtServerHelper.getEvents(2, {
eventTypes: ['core-overall_status_changed'],
});
});
it('should emit the initial "degraded" event with the context set to `initializing`', () => {

View file

@ -14,16 +14,20 @@ export default function ({ getService }: FtrProviderContext) {
describe('kibana_started', () => {
it('should emit the "kibana_started" event', async () => {
const [event] = await ebtServerHelper.getEvents(1, ['kibana_started']);
const [event] = await ebtServerHelper.getEvents(1, { eventTypes: ['kibana_started'] });
expect(event.event_type).to.eql('kibana_started');
expect(event.properties.uptime_per_step.constructor.start).to.be.a('number');
expect(event.properties.uptime_per_step.constructor.end).to.be.a('number');
expect(event.properties.uptime_per_step.preboot.start).to.be.a('number');
expect(event.properties.uptime_per_step.preboot.end).to.be.a('number');
expect(event.properties.uptime_per_step.setup.start).to.be.a('number');
expect(event.properties.uptime_per_step.setup.end).to.be.a('number');
expect(event.properties.uptime_per_step.start.start).to.be.a('number');
expect(event.properties.uptime_per_step.start.end).to.be.a('number');
const uptimePerStep = event.properties.uptime_per_step as Record<
'constructor' | 'preboot' | 'setup' | 'start',
Record<'start' | 'end', number>
>;
expect(uptimePerStep.constructor.start).to.be.a('number');
expect(uptimePerStep.constructor.end).to.be.a('number');
expect(uptimePerStep.preboot.start).to.be.a('number');
expect(uptimePerStep.preboot.end).to.be.a('number');
expect(uptimePerStep.setup.start).to.be.a('number');
expect(uptimePerStep.setup.end).to.be.a('number');
expect(uptimePerStep.start.start).to.be.a('number');
expect(uptimePerStep.start.end).to.be.a('number');
});
});
}

View file

@ -6,7 +6,7 @@
"declaration": true,
"declarationMap": true,
"types": [
"node",
"node",
"@emotion/react/types/css-prop",
"@kbn/ambient-ui-types",
]
@ -22,7 +22,7 @@
],
"exclude": [
"target/**/*",
"analytics/__fixtures__/plugins/**/*",
"analytics/fixtures/plugins/**/*",
"interpreter_functional/plugins/**/*",
"plugin_functional/plugins/**/*",
"server_integration/__fixtures__/plugins/**/*",
@ -59,8 +59,8 @@
{ "path": "../src/plugins/usage_collection/tsconfig.json" },
{ "path": "../src/plugins/data_view_management/tsconfig.json" },
{ "path": "../src/plugins/visualizations/tsconfig.json" },
{ "path": "analytics/__fixtures__/plugins/analytics_ftr_helpers/tsconfig.json"},
{ "path": "analytics/__fixtures__/plugins/analytics_plugin_a/tsconfig.json"},
{ "path": "analytics/fixtures/plugins/analytics_ftr_helpers/tsconfig.json"},
{ "path": "analytics/fixtures/plugins/analytics_plugin_a/tsconfig.json"},
{ "path": "interactive_setup_api_integration/fixtures/test_endpoints/tsconfig.json" },
{ "path": "plugin_functional/plugins/core_app_status/tsconfig.json" },
{ "path": "plugin_functional/plugins/core_provider_plugin/tsconfig.json" },

View file

@ -191,10 +191,10 @@
"@kbn/vis-type-xy-plugin/*": ["src/plugins/vis_types/xy/*"],
"@kbn/visualizations-plugin": ["src/plugins/visualizations"],
"@kbn/visualizations-plugin/*": ["src/plugins/visualizations/*"],
"@kbn/analytics-ftr-helpers-plugin": ["test/analytics/__fixtures__/plugins/analytics_ftr_helpers"],
"@kbn/analytics-ftr-helpers-plugin/*": ["test/analytics/__fixtures__/plugins/analytics_ftr_helpers/*"],
"@kbn/analytics-plugin-a-plugin": ["test/analytics/__fixtures__/plugins/analytics_plugin_a"],
"@kbn/analytics-plugin-a-plugin/*": ["test/analytics/__fixtures__/plugins/analytics_plugin_a/*"],
"@kbn/analytics-ftr-helpers-plugin": ["test/analytics/fixtures/plugins/analytics_ftr_helpers"],
"@kbn/analytics-ftr-helpers-plugin/*": ["test/analytics/fixtures/plugins/analytics_ftr_helpers/*"],
"@kbn/analytics-plugin-a-plugin": ["test/analytics/fixtures/plugins/analytics_plugin_a"],
"@kbn/analytics-plugin-a-plugin/*": ["test/analytics/fixtures/plugins/analytics_plugin_a/*"],
"@kbn/coverage-fixtures-plugin": ["test/common/fixtures/plugins/coverage"],
"@kbn/coverage-fixtures-plugin/*": ["test/common/fixtures/plugins/coverage/*"],
"@kbn/newsfeed-fixtures-plugin": ["test/common/fixtures/plugins/newsfeed"],