kibana/test/api_integration/apis/esql/errors.ts
Gerard Soldevila 313f973aec
Sustainable Kibana Architecture: Move modules owned by @elastic/kibana-esql (#202722)
## Summary

This PR aims at relocating some of the Kibana modules (plugins and
packages) into a new folder structure, according to the _Sustainable
Kibana Architecture_ initiative.

> [!IMPORTANT]
> * We kindly ask you to:
> * Manually fix the errors in the error section below (if there are
any).
> * Search for the `packages[\/\\]` and `plugins[\/\\]` patterns in the
source code (Babel and Eslint config files), and update them
appropriately.
> * Manually review
`.buildkite/scripts/pipelines/pull_request/pipeline.ts` to ensure that
any CI pipeline customizations continue to be correctly applied after
the changed path names
> * Review all of the updated files, specially the `.ts` and `.js` files
listed in the sections below, as some of them contain relative paths
that have been updated.
> * Think of potential impact of the move, including tooling and
configuration files that can be pointing to the relocated modules. E.g.:
>     * customised eslint rules
>     * docs pointing to source code

> [!NOTE]
> This PR has been auto-generated.
> Do not attempt to push any changes unless you know what you are doing.
> Please use
[#sustainable_kibana_architecture](https://elastic.slack.com/archives/C07TCKTA22E)
Slack channel for feedback.




#### 2 plugin(s) are going to be relocated:

| Id | Target folder |
| -- | ------------- |
| `@kbn/esql` | `src/platform/plugins/shared/esql` |
| `@kbn/esql-datagrid` | `src/platform/plugins/shared/esql_datagrid` |


#### 5 package(s) are going to be relocated:

  | Id | Target folder |
  | -- | ------------- |
  | `@kbn/esql-ast` | `src/platform/packages/shared/kbn-esql-ast` |
| `@kbn/esql-editor` | `src/platform/packages/private/kbn-esql-editor` |
| `@kbn/esql-utils` | `src/platform/packages/shared/kbn-esql-utils` |
| `@kbn/esql-validation-autocomplete` |
`src/platform/packages/shared/kbn-esql-validation-autocomplete` |
| `@kbn/language-documentation` |
`src/platform/packages/private/kbn-language-documentation` |


<details>
<summary>Updated references</summary>

```
./.buildkite/scripts/steps/esql_generate_function_metadata.sh
./.buildkite/scripts/steps/esql_grammar_sync.sh
./.eslintignore
./.eslintrc.js
./.i18nrc.json
./docs/developer/plugin-list.asciidoc
./examples/esql_ast_inspector/public/plugin.ts
./examples/esql_validation_example/public/plugin.ts
./package.json
./packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts
./packages/kbn-monaco/BUILD.bazel
./packages/kbn-repo-packages/package-map.json
./packages/kbn-ts-projects/config-paths.json
./packages/kbn-ui-shared-deps-src/BUILD.bazel
./src/dev/storybook/aliases.ts
./src/platform/packages/private/kbn-esql-editor/jest.config.js
./src/platform/packages/private/kbn-language-documentation/jest.config.js
./src/platform/packages/private/kbn-language-documentation/package.json
./src/platform/packages/shared/kbn-esql-ast/jest.config.js
./src/platform/packages/shared/kbn-esql-utils/jest.config.js
./src/platform/packages/shared/kbn-esql-validation-autocomplete/README.md
./src/platform/packages/shared/kbn-esql-validation-autocomplete/jest.config.js
./src/platform/packages/shared/kbn-esql-validation-autocomplete/jest.integration.config.js
./src/platform/packages/shared/kbn-esql-validation-autocomplete/package.json
./src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts
./src/platform/plugins/shared/esql/jest.config.js
./src/platform/plugins/shared/esql_datagrid/jest.config.js
./tsconfig.base.json
./yarn.lock
```
</details>
<details>
<summary>Updated relative paths</summary>

```
src/platform/packages/private/kbn-esql-editor/jest.config.js:12
src/platform/packages/private/kbn-esql-editor/tsconfig.json:2
src/platform/packages/private/kbn-language-documentation/jest.config.js:12
src/platform/packages/private/kbn-language-documentation/package.json:12
src/platform/packages/private/kbn-language-documentation/tsconfig.json:2
src/platform/packages/shared/kbn-esql-ast/jest.config.js:12
src/platform/packages/shared/kbn-esql-ast/tsconfig.json:2
src/platform/packages/shared/kbn-esql-utils/jest.config.js:12
src/platform/packages/shared/kbn-esql-utils/tsconfig.json:2
src/platform/packages/shared/kbn-esql-validation-autocomplete/jest.config.js:12
src/platform/packages/shared/kbn-esql-validation-autocomplete/jest.integration.config.js:12
src/platform/packages/shared/kbn-esql-validation-autocomplete/package.json:10
src/platform/packages/shared/kbn-esql-validation-autocomplete/package.json:11
src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts:389
src/platform/packages/shared/kbn-esql-validation-autocomplete/tsconfig.json:2
src/platform/plugins/shared/esql/jest.config.js:12
src/platform/plugins/shared/esql/tsconfig.json:2
src/platform/plugins/shared/esql/tsconfig.json:7
src/platform/plugins/shared/esql_datagrid/jest.config.js:12
src/platform/plugins/shared/esql_datagrid/tsconfig.json:2
src/platform/plugins/shared/esql_datagrid/tsconfig.json:7
```
</details>
<details>
<summary>Script errors</summary>

```

```
</details>

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Rudolf Meijering <skaapgif@gmail.com>
2024-12-09 11:33:55 +01:00

275 lines
9.2 KiB
TypeScript

/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import Fs from 'fs';
import Path from 'path';
import expect from '@kbn/expect';
import { MappingProperty } from '@elastic/elasticsearch/lib/api/types';
import { REPO_ROOT } from '@kbn/repo-info';
import uniqBy from 'lodash/uniqBy';
import { groupBy, mapValues } from 'lodash';
import { FtrProviderContext } from '../../ftr_provider_context';
function getConfigPath() {
return Path.resolve(
REPO_ROOT,
'src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation'
);
}
function getSetupPath() {
return Path.resolve(getConfigPath(), 'esql_validation_meta_tests.json');
}
function getMissmatchedPath() {
return Path.resolve(getConfigPath(), 'esql_validation_missmatches.json');
}
function readSetupFromESQLPackage() {
const esqlPackagePath = getSetupPath();
const json = Fs.readFileSync(esqlPackagePath, 'utf8');
const esqlPackage = JSON.parse(json);
return esqlPackage;
}
function createIndexRequest(
index: string,
fields: Array<{ name: string; type: string }>,
stringType: 'text' | 'keyword',
numberType: 'integer' | 'double' | 'long' | 'unsigned_long'
) {
return {
index,
mappings: {
properties: fields.reduce(
(memo: Record<string, MappingProperty>, { name, type }: { name: string; type: string }) => {
let esType = type;
if (type === 'string') {
esType = stringType;
}
if (type === 'number') {
esType = numberType;
}
if (type === 'cartesian_point') {
esType = 'point';
}
if (type === 'cartesian_shape') {
esType = 'shape';
}
if (type === 'unsupported') {
esType = 'integer_range';
}
memo[name] = { type: esType } as MappingProperty;
return memo;
},
{}
),
},
};
}
interface JSONConfig {
testCases: Array<{ query: string; error: string[] }>;
indexes: string[];
policies: Array<{
name: string;
sourceIndices: string[];
matchField: string;
enrichFields: string[];
}>;
unsupported_field: Array<{ name: string; type: string }>;
fields: Array<{ name: string; type: string }>;
enrichFields: Array<{ name: string; type: string }>;
}
export interface EsqlResultColumn {
name: string;
type: string;
}
export type EsqlResultRow = Array<string | null>;
export interface EsqlTable {
columns: EsqlResultColumn[];
values: EsqlResultRow[];
}
function parseConfig(config: JSONConfig) {
return {
queryToErrors: config.testCases,
indexes: config.indexes,
policies: config.policies.map(({ name }: { name: string }) => name),
};
}
export default function ({ getService }: FtrProviderContext) {
const es = getService('es');
const log = getService('log');
// Send raw ES|QL query directly to ES endpoint bypassing Kibana
// as we do not need more overhead here
async function sendESQLQuery(query: string): Promise<{
resp: EsqlTable | undefined;
error: { message: string } | undefined;
}> {
try {
const resp = await es.transport.request<EsqlTable>({
method: 'POST',
path: '/_query',
body: {
query,
},
});
return { resp, error: undefined };
} catch (e) {
return { resp: undefined, error: { message: e.meta.body.error.root_cause[0].reason } };
}
}
describe('error messages', () => {
const config = readSetupFromESQLPackage();
const { queryToErrors, indexes, policies } = parseConfig(config);
const missmatches: Array<{ query: string; error: string }> = [];
// Swap these for DEBUG/further investigation on ES bugs
const stringVariants = ['text', 'keyword'] as const;
const numberVariants = ['integer', 'long', 'double', 'long'] as const;
async function cleanup() {
// clean it up all indexes and policies
log.info(`cleaning up all indexes: ${indexes.join(', ')}`);
await es.indices.delete({ index: indexes, ignore_unavailable: true }, { ignore: [404] });
await es.indices.delete(
{ index: config.policies[0].sourceIndices[0], ignore_unavailable: true },
{ ignore: [404] }
);
for (const policy of policies) {
log.info(`deleting policy "${policy}"...`);
// TODO: Maybe `policy` -> `policy.name`?
await es.enrich.deletePolicy({ name: policy }, { ignore: [404] });
}
}
after(async () => {
if (missmatches.length) {
const distinctMissmatches = uniqBy(
missmatches,
(missmatch) => missmatch.query + missmatch.error
);
const missmatchesGrouped = mapValues(
groupBy(distinctMissmatches, (missmatch) => missmatch.error),
(list) => list.map(({ query }) => query)
);
log.info(`writing ${Object.keys(missmatchesGrouped).length} missmatches to file...`);
Fs.writeFileSync(getMissmatchedPath(), JSON.stringify(missmatchesGrouped, null, 2));
}
});
for (const stringFieldType of stringVariants) {
for (const numberFieldType of numberVariants) {
describe(`Using string field type: ${stringFieldType} and number field type: ${numberFieldType}`, () => {
before(async () => {
await cleanup();
log.info(`creating ${indexes.length} indexes...`);
for (const index of indexes) {
// setup all indexes, mappings and policies here
log.info(
`creating a index "${index}" with mapping...\n${JSON.stringify(config.fields)}`
);
const fieldsExcludingCounterType = config.fields.filter(
// ES|QL supports counter_integer, counter_long, counter_double, date_period, etc.
// but they are not types suitable for Elasticsearch indices
(c: { type: string }) =>
!c.type.startsWith('counter_') &&
c.type !== 'date_period' &&
c.type !== 'time_duration' &&
c.type !== 'null' &&
c.type !== 'time_literal'
);
await es.indices.create(
createIndexRequest(
index,
/unsupported/.test(index) ? config.unsupported_field : fieldsExcludingCounterType,
stringFieldType,
numberFieldType
),
{ ignore: [409] }
);
}
for (const { sourceIndices, matchField } of config.policies.slice(0, 1)) {
const enrichFields = [{ name: matchField, type: 'string' }].concat(
config.enrichFields
);
log.info(`creating a index "${sourceIndices[0]}" for policy with mapping...`);
await es.indices.create(
createIndexRequest(
sourceIndices[0],
enrichFields,
stringFieldType,
numberFieldType
),
{
ignore: [409],
}
);
}
log.info(`creating ${policies.length} policies...`);
for (const { name, sourceIndices, matchField, enrichFields } of config.policies) {
log.info(`creating a policy "${name}"...`);
await es.enrich.putPolicy(
{
name,
body: {
match: {
indices: sourceIndices,
match_field: matchField,
enrich_fields: enrichFields,
},
},
},
{ ignore: [409] }
);
log.info(`executing policy "${name}"...`);
await es.enrich.executePolicy({ name });
}
});
after(async () => {
await cleanup();
});
it(`Checking error messages`, async () => {
for (const { query, error } of queryToErrors) {
const jsonBody = await sendESQLQuery(query);
const clientSideHasError = Boolean(error.length);
const serverSideHasError = Boolean(jsonBody.error);
if (clientSideHasError !== serverSideHasError) {
if (clientSideHasError) {
// in this case it's a problem, so fail the test
expect().fail(`Client side errored but ES server did not: ${query}`);
}
if (serverSideHasError) {
// in this case client side validator can improve, but it's not hard failure
// rather log it as it can be a useful to investigate a bug on the ES implementation side for some type combination
missmatches.push({ query, error: jsonBody.error!.message });
}
}
}
});
});
}
}
});
}