[kbn-journeys] add optional beforeSteps hook (#151717)

## Summary

Related to #151613

There might be cases when we need to add extra wait for Kibana plugin to
be ready before starting loading test data with `esArchiver` /
`kbnArchiver`.

Currently journey lifecycle looks like this:

- `onSetup` wrapped with mocha `before` hook
  - in parallel 
    - `setupBrowserAndPage` (including EBT tracker setup)
    - load ES data / Kibana saved objects
  - `setupApm`
- steps execution (each step wrapped with mocha `it` function)
- `onTeardown` wrapped with mocha `after` hook
  - `tearDownBrowserAndPage` (including closing EBT tracker)
  - `teardownApm`
  - load ES data / Kibana saved objects

beforeSteps hook purpose is to make sure Kibana/ES state is ready for
journey execution and not load test data, since it won't be unloaded
during `after` hook:

- `onSetup` wrapped with mocha `before` hook
    - `setupBrowserAndPage` (including EBT tracker setup)
- run beforeSteps hook -> prepare Kibana/ES for data ingestion / steps
execution
    - load ES data / Kibana saved objects
    - `setupApm`

How to use:

```
export const journey = new Journey({
  beforeSteps: async ({ kibanaServer, retry }) => {
    retry.try(async () => {
      const response = await kibanaServer.request({
        path: '/internal/cloud_security_posture/status?check=init',
        method: 'GET',
      });
      return response.status === 200;
    });
  },
  esArchives: [...],
  kbnArchives: [...],
})
  .step({...})
  .step({...})
```
This commit is contained in:
Dzmitry Lemechko 2023-02-22 18:53:00 +01:00 committed by GitHub
parent 618f0d3b34
commit 6c33644b53
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 4 deletions

View file

@ -12,7 +12,12 @@ import { Page } from 'playwright';
import callsites from 'callsites';
import { ToolingLog } from '@kbn/tooling-log';
import { FtrConfigProvider } from '@kbn/test';
import { FtrProviderContext, KibanaServer } from '@kbn/ftr-common-functional-services';
import {
FtrProviderContext,
KibanaServer,
Es,
RetryService,
} from '@kbn/ftr-common-functional-services';
import { Auth } from '../services/auth';
import { InputDelays } from '../services/input_delays';
@ -28,6 +33,8 @@ export interface BaseStepCtx {
inputDelays: InputDelays;
kbnUrl: KibanaUrl;
kibanaServer: KibanaServer;
es: Es;
retry: RetryService;
}
export type AnyStep = Step<{}>;
@ -96,7 +103,16 @@ export class Journey<CtxExt extends object> {
/**
* Define a step of this Journey. Steps are only separated from each other
* to aid in reading/debuging the journey and reading it's logging output.
* to aid in reading/debugging the journey and reading it's logging output.
* These services might be helpful:
*
* page: methods to interact with a single tab in a browser
*
* kbnUrl: get the URL for a Kibana plugin
*
* kibanaServer: basic Kibana server client
*
* es: basic Elasticsearch client
*
* If a journey fails, a failure report will be created with a screenshot
* at the point of failure as well as a screenshot at the end of every
@ -119,6 +135,8 @@ export class Journey<CtxExt extends object> {
getService('config'),
getService('esArchiver'),
getService('kibanaServer'),
getService('es'),
getService('retry'),
new Auth(getService('config'), getService('log'), getService('kibanaServer')),
this.config
).initMochaSuite(this.#steps);

View file

@ -114,6 +114,11 @@ export interface JourneyConfigOptions<CtxExt> {
* be merged with the default context provided to each step function.
*/
extendContext?: (ctx: BaseStepCtx) => CtxExt;
/**
* Use this to define actions that will be executed after Kibana & ES were started,
* but before archives are loaded. APM traces are not collected for this hook.
*/
beforeSteps?: (ctx: BaseStepCtx & CtxExt) => Promise<void>;
}
export class JourneyConfig<CtxExt extends object> {
@ -179,4 +184,12 @@ export class JourneyConfig<CtxExt extends object> {
...ext(ctx),
};
}
async getBeforeStepsFn(ctx: BaseStepCtx & CtxExt) {
if (this.#opts.beforeSteps) {
await this.#opts.beforeSteps(ctx);
} else {
new Promise<void>((resolve) => resolve());
}
}
}

View file

@ -16,7 +16,7 @@ import playwright, { ChromiumBrowser, Page, BrowserContext, CDPSession, Request
import { asyncMap, asyncForEach } from '@kbn/std';
import { ToolingLog } from '@kbn/tooling-log';
import { Config } from '@kbn/test';
import { EsArchiver, KibanaServer } from '@kbn/ftr-common-functional-services';
import { EsArchiver, KibanaServer, Es, RetryService } from '@kbn/ftr-common-functional-services';
import { Auth } from '../services/auth';
import { getInputDelays } from '../services/input_delays';
@ -34,6 +34,8 @@ export class JourneyFtrHarness {
private readonly config: Config,
private readonly esArchiver: EsArchiver,
private readonly kibanaServer: KibanaServer,
private readonly es: Es,
private readonly retry: RetryService,
private readonly auth: Auth,
private readonly journeyConfig: JourneyConfig<any>
) {
@ -117,8 +119,12 @@ export class JourneyFtrHarness {
}
private async onSetup() {
// We start browser and init page in the first place
await this.setupBrowserAndPage();
// We allow opt-in beforeSteps hook to manage Kibana/ES state
await this.journeyConfig.getBeforeStepsFn(this.getCtx());
// Loading test data
await Promise.all([
this.setupBrowserAndPage(),
asyncForEach(this.journeyConfig.getEsArchives(), async (esArchive) => {
await this.esArchiver.load(esArchive);
}),
@ -365,6 +371,8 @@ export class JourneyFtrHarness {
)
),
kibanaServer: this.kibanaServer,
es: this.es,
retry: this.retry,
});
return this.#_ctx;