Skip to content

Commit

Permalink
[Discover] Add support for contextual awareness functional tests (ela…
Browse files Browse the repository at this point in the history
…stic#185905)

## Summary

This PR adds functional test support for the Discover contextual
awareness framework, and adds tests for the initial `getCellRenderers`
extension point using example profiles.

To support this, this PR introduces a new YAML setting called
`discover.experimental.enabledProfiles` which can be used to selectively
enable profiles both for functional testing and demoing WIP profiles
that aren't yet ready for GA.

Example usage:
```yml
discover.experimental.enabledProfiles: ['example-root-profile', 'example-data-source-profile', 'example-document-profile']
```

Flaky test runs:
- Stateful x50:
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/6304
- Serverless Observability x50:
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/6305
- Serverless Search x50:
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/6306
- Serverless Security x50:
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/6307

Resolves elastic#184699.

### Checklist

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [ ] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [ ] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)

### For maintainers

- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
  • Loading branch information
davismcphee authored Jun 19, 2024
1 parent 06f7739 commit 57891ff
Show file tree
Hide file tree
Showing 35 changed files with 1,072 additions and 203 deletions.
4 changes: 4 additions & 0 deletions .buildkite/ftr_configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ enabled:
- test/functional/apps/discover/group6/config.ts
- test/functional/apps/discover/group7/config.ts
- test/functional/apps/discover/group8/config.ts
- test/functional/apps/discover/context_awareness/config.ts
- test/functional/apps/getting_started/config.ts
- test/functional/apps/home/config.ts
- test/functional/apps/kibana_overview/config.ts
Expand Down Expand Up @@ -426,6 +427,7 @@ enabled:
- x-pack/test_serverless/functional/test_suites/observability/config.ts
- x-pack/test_serverless/functional/test_suites/observability/config.examples.ts
- x-pack/test_serverless/functional/test_suites/observability/config.saved_objects_management.ts
- x-pack/test_serverless/functional/test_suites/observability/config.context_awareness.ts
- x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group1.ts
- x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group2.ts
- x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group3.ts
Expand All @@ -438,6 +440,7 @@ enabled:
- x-pack/test_serverless/functional/test_suites/search/config.examples.ts
- x-pack/test_serverless/functional/test_suites/search/config.screenshots.ts
- x-pack/test_serverless/functional/test_suites/search/config.saved_objects_management.ts
- x-pack/test_serverless/functional/test_suites/search/config.context_awareness.ts
- x-pack/test_serverless/functional/test_suites/search/common_configs/config.group1.ts
- x-pack/test_serverless/functional/test_suites/search/common_configs/config.group2.ts
- x-pack/test_serverless/functional/test_suites/search/common_configs/config.group3.ts
Expand All @@ -449,6 +452,7 @@ enabled:
- x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.basic.ts
- x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.essentials.ts
- x-pack/test_serverless/functional/test_suites/security/config.saved_objects_management.ts
- x-pack/test_serverless/functional/test_suites/security/config.context_awareness.ts
- x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts
- x-pack/test_serverless/functional/test_suites/security/common_configs/config.group2.ts
- x-pack/test_serverless/functional/test_suites/security/common_configs/config.group3.ts
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/discover/common/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ export const configSchema = schema.object({
experimental: schema.maybe(
schema.object({
ruleFormV2Enabled: schema.maybe(schema.boolean({ defaultValue: false })),
enabledProfiles: schema.maybe(schema.arrayOf(schema.string(), { defaultValue: [] })),
})
),
});

export type ConfigSchema = TypeOf<typeof configSchema>;
export type ExperimentalFeatures = ConfigSchema['experimental'];
export type ExperimentalFeatures = NonNullable<ConfigSchema['experimental']>;
21 changes: 13 additions & 8 deletions src/plugins/discover/public/context_awareness/__mocks__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ import {
RootProfileService,
SolutionType,
} from '../profiles';
import { createProfileProviderServices } from '../profiles/profile_provider_services';
import { createProfileProviderServices } from '../profile_providers/profile_provider_services';
import { ProfilesManager } from '../profiles_manager';

export const createContextAwarenessMocks = () => {
export const createContextAwarenessMocks = ({
shouldRegisterProviders = true,
}: { shouldRegisterProviders?: boolean } = {}) => {
const rootProfileProviderMock: RootProfileProvider = {
profileId: 'root-profile',
profile: {
Expand Down Expand Up @@ -92,15 +94,15 @@ export const createContextAwarenessMocks = () => {
const records = getDataTableRecords(dataViewWithTimefieldMock);
const contextRecordMock = records[0];
const contextRecordMock2 = records[1];

const rootProfileServiceMock = new RootProfileService();
rootProfileServiceMock.registerProvider(rootProfileProviderMock);

const dataSourceProfileServiceMock = new DataSourceProfileService();
dataSourceProfileServiceMock.registerProvider(dataSourceProfileProviderMock);

const documentProfileServiceMock = new DocumentProfileService();
documentProfileServiceMock.registerProvider(documentProfileProviderMock);

if (shouldRegisterProviders) {
rootProfileServiceMock.registerProvider(rootProfileProviderMock);
dataSourceProfileServiceMock.registerProvider(dataSourceProfileProviderMock);
documentProfileServiceMock.registerProvider(documentProfileProviderMock);
}

const profilesManagerMock = new ProfilesManager(
rootProfileServiceMock,
Expand All @@ -114,6 +116,9 @@ export const createContextAwarenessMocks = () => {
rootProfileProviderMock,
dataSourceProfileProviderMock,
documentProfileProviderMock,
rootProfileServiceMock,
dataSourceProfileServiceMock,
documentProfileServiceMock,
contextRecordMock,
contextRecordMock2,
profilesManagerMock,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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.
*/

export { exampleDataSourceProfileProvider } from './profile';
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* 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 { EuiBadge } from '@elastic/eui';
import type { DataTableRecord } from '@kbn/discover-utils';
import { isOfAggregateQueryType } from '@kbn/es-query';
import { getIndexPatternFromESQLQuery } from '@kbn/esql-utils';
import { euiThemeVars } from '@kbn/ui-theme';
import { capitalize } from 'lodash';
import React from 'react';
import { DataSourceType, isDataSourceType } from '../../../../common/data_sources';
import { DataSourceCategory, DataSourceProfileProvider } from '../../profiles';

export const exampleDataSourceProfileProvider: DataSourceProfileProvider = {
profileId: 'example-data-source-profile',
profile: {
getCellRenderers: (prev) => () => ({
...prev(),
'log.level': (props) => {
const level = getFieldValue(props.row, 'log.level');

if (!level) {
return (
<span
css={{ color: euiThemeVars.euiTextSubduedColor }}
data-test-subj="exampleDataSourceProfileLogLevelEmpty"
>
(None)
</span>
);
}

const levelMap: Record<string, string> = {
info: 'primary',
debug: 'default',
error: 'danger',
};

return (
<EuiBadge
color={levelMap[level]}
title={level}
data-test-subj="exampleDataSourceProfileLogLevel"
>
{capitalize(level)}
</EuiBadge>
);
},
}),
},
resolve: (params) => {
let indexPattern: string | undefined;

if (isDataSourceType(params.dataSource, DataSourceType.Esql)) {
if (!isOfAggregateQueryType(params.query)) {
return { isMatch: false };
}

indexPattern = getIndexPatternFromESQLQuery(params.query.esql);
} else if (isDataSourceType(params.dataSource, DataSourceType.DataView) && params.dataView) {
indexPattern = params.dataView.getIndexPattern();
}

if (indexPattern !== 'my-example-logs') {
return { isMatch: false };
}

return {
isMatch: true,
context: { category: DataSourceCategory.Logs },
};
},
};

const getFieldValue = (record: DataTableRecord, field: string) => {
const value = record.flattened[field];
return Array.isArray(value) ? value[0] : value;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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.
*/

export { exampleDocumentProfileProvider } from './profile';
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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 { DataTableRecord } from '@kbn/discover-utils';
import { DocumentProfileProvider, DocumentType } from '../../profiles';

export const exampleDocumentProfileProvider: DocumentProfileProvider = {
profileId: 'example-document-profile',
profile: {},
resolve: (params) => {
if (getFieldValue(params.record, 'data_stream.type') !== 'logs') {
return { isMatch: false };
}

return {
isMatch: true,
context: {
type: DocumentType.Log,
},
};
},
};

const getFieldValue = (record: DataTableRecord, field: string) => {
const value = record.flattened[field];
return Array.isArray(value) ? value[0] : value;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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.
*/

export { exampleRootProfileProvider } from './profile';
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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 { EuiBadge } from '@elastic/eui';
import type { DataTableRecord } from '@kbn/discover-utils';
import React from 'react';
import { RootProfileProvider, SolutionType } from '../../profiles';

export const exampleRootProfileProvider: RootProfileProvider = {
profileId: 'example-root-profile',
profile: {
getCellRenderers: (prev) => () => ({
...prev(),
'@timestamp': (props) => {
const timestamp = getFieldValue(props.row, '@timestamp');

return (
<EuiBadge color="hollow" title={timestamp} data-test-subj="exampleRootProfileTimestamp">
{timestamp}
</EuiBadge>
);
},
}),
},
resolve: (params) => {
if (params.solutionNavId != null) {
return { isMatch: false };
}

return { isMatch: true, context: { solutionType: SolutionType.Default } };
},
};

const getFieldValue = (record: DataTableRecord, field: string) => {
const value = record.flattened[field];
return Array.isArray(value) ? value[0] : value;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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.
*/

export { registerProfileProviders } from './register_profile_providers';
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import { DataTableRecord } from '@kbn/discover-utils';
import { DocumentProfileProvider, DocumentType } from '../../profiles';
import { ProfileProviderServices } from '../../profiles/profile_provider_services';
import { ProfileProviderServices } from '../profile_provider_services';

export const createLogDocumentProfileProvider = (
services: ProfileProviderServices
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
DataSourceProfileProvider,
DataSourceProfileProviderParams,
} from '../../profiles';
import { ProfileProviderServices } from '../../profiles/profile_provider_services';
import { ProfileProviderServices } from '../profile_provider_services';

export const createLogsDataSourceProfileProvider = (
services: ProfileProviderServices
Expand Down
Loading

0 comments on commit 57891ff

Please sign in to comment.