diff --git a/src/platform/plugins/shared/data_views/test/scout/api/tests/data_views/runtime_fields_create_errors.spec.ts b/src/platform/plugins/shared/data_views/test/scout/api/tests/data_views/runtime_fields_create_errors.spec.ts new file mode 100644 index 0000000000000..8a96481825e53 --- /dev/null +++ b/src/platform/plugins/shared/data_views/test/scout/api/tests/data_views/runtime_fields_create_errors.spec.ts @@ -0,0 +1,56 @@ +/* + * 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 { apiTest, tags, type RoleApiCredentials } from '@kbn/scout'; +import { expect } from '@kbn/scout/api'; +import { COMMON_HEADERS, DATA_VIEW_PATH } from '../../fixtures/constants'; + +apiTest.describe( + 'POST api/data_views/data_view/{id}/runtime_field - create errors (data view api)', + { tag: tags.deploymentAgnostic }, + () => { + let adminApiCredentials: RoleApiCredentials; + let createdIds: string[] = []; + + apiTest.beforeAll(async ({ requestAuth }) => { + adminApiCredentials = await requestAuth.getApiKey('admin'); + }); + + apiTest.afterEach(async ({ apiServices }) => { + for (const id of createdIds) { + await apiServices.dataViews.delete(id); + } + createdIds = []; + }); + + apiTest( + 'returns an error when runtime field object is not provided', + async ({ apiClient, apiServices }) => { + const title = `foo-${Date.now()}-${Math.random()}*`; + const { data: dataView } = await apiServices.dataViews.create({ title }); + createdIds.push(dataView.id); + + const response = await apiClient.post(`${DATA_VIEW_PATH}/${dataView.id}/runtime_field`, { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: {}, + }); + + expect(response).toHaveStatusCode(400); + expect(response.body.statusCode).toBe(400); + expect(response.body.message).toBe( + '[request body.name]: expected value of type [string] but got [undefined]' + ); + } + ); + } +); diff --git a/src/platform/plugins/shared/data_views/test/scout/api/tests/data_views/runtime_fields_create_main.spec.ts b/src/platform/plugins/shared/data_views/test/scout/api/tests/data_views/runtime_fields_create_main.spec.ts new file mode 100644 index 0000000000000..cee2d298ff67a --- /dev/null +++ b/src/platform/plugins/shared/data_views/test/scout/api/tests/data_views/runtime_fields_create_main.spec.ts @@ -0,0 +1,234 @@ +/* + * 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 { apiTest, tags, type RoleApiCredentials } from '@kbn/scout'; +import { expect } from '@kbn/scout/api'; +import { COMMON_HEADERS, ES_ARCHIVE_BASIC_INDEX, DATA_VIEW_PATH } from '../../fixtures/constants'; + +apiTest.describe( + 'POST api/data_views/data_view/{id}/runtime_field - create main (data view api)', + { tag: tags.deploymentAgnostic }, + () => { + let adminApiCredentials: RoleApiCredentials; + let createdIds: string[] = []; + + apiTest.beforeAll(async ({ esArchiver, requestAuth }) => { + adminApiCredentials = await requestAuth.getApiKey('admin'); + await esArchiver.loadIfNeeded(ES_ARCHIVE_BASIC_INDEX); + }); + + apiTest.afterEach(async ({ apiServices }) => { + for (const id of createdIds) { + await apiServices.dataViews.delete(id); + } + createdIds = []; + }); + + apiTest('can create a new runtime field', async ({ apiClient, apiServices }) => { + const title = `basic_index-${Date.now()}-${Math.random()}*`; + const { data: dataView } = await apiServices.dataViews.create({ + title, + override: true, + }); + createdIds.push(dataView.id); + + const response = await apiClient.post(`${DATA_VIEW_PATH}/${dataView.id}/runtime_field`, { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeBar', + runtimeField: { + type: 'long', + script: { + source: "emit(doc['field_name'].value)", + }, + }, + }, + }); + + expect(response).toHaveStatusCode(200); + expect(response.body.data_view).toBeDefined(); + expect(response.body.fields).toBeDefined(); + expect(response.body.fields.length).toBeGreaterThan(0); + + const field = response.body.fields[0]; + expect(field.name).toBe('runtimeBar'); + expect(field.runtimeField.type).toBe('long'); + expect(field.runtimeField.script.source).toBe("emit(doc['field_name'].value)"); + expect(field.scripted).toBe(false); + }); + + apiTest( + 'newly created runtime field is available in the data view object', + async ({ apiClient, apiServices }) => { + const title = `basic_index-${Date.now()}-${Math.random()}`; + const { data: dataView } = await apiServices.dataViews.create({ + title, + override: true, + }); + createdIds.push(dataView.id); + + const rtResponse = await apiClient.post(`${DATA_VIEW_PATH}/${dataView.id}/runtime_field`, { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeBar', + runtimeField: { + type: 'long', + script: { + source: "emit(doc['field_name'].value)", + }, + }, + }, + }); + + expect(rtResponse).toHaveStatusCode(200); + + const { data: retrievedDataView } = await apiServices.dataViews.get(dataView.id); + expect(retrievedDataView).toBeDefined(); + + const fields = retrievedDataView.fields; + expect(fields).toBeDefined(); + + const field = fields!.runtimeBar; + expect(field.name).toBe('runtimeBar'); + expect(field.runtimeField.type).toBe('long'); + expect(field.runtimeField.script.source).toBe("emit(doc['field_name'].value)"); + expect(field.scripted).toBe(false); + + const duplicateResponse = await apiClient.post( + `${DATA_VIEW_PATH}/${dataView.id}/runtime_field`, + { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeBar', + runtimeField: { + type: 'long', + script: { + source: "emit(doc['field_name'].value)", + }, + }, + }, + } + ); + + expect(duplicateResponse).toHaveStatusCode(400); + } + ); + + apiTest('prevents field name collisions', async ({ apiClient, apiServices }) => { + const title = `basic-${Date.now()}-${Math.random()}*`; + const { data: dataView } = await apiServices.dataViews.create({ + title, + override: true, + }); + createdIds.push(dataView.id); + + const response1 = await apiClient.post(`${DATA_VIEW_PATH}/${dataView.id}/runtime_field`, { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeBar', + runtimeField: { + type: 'long', + script: { + source: "emit(doc['field_name'].value)", + }, + }, + }, + }); + + expect(response1).toHaveStatusCode(200); + + const response2 = await apiClient.post(`${DATA_VIEW_PATH}/${dataView.id}/runtime_field`, { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeBar', + runtimeField: { + type: 'long', + script: { + source: "emit(doc['field_name'].value)", + }, + }, + }, + }); + + expect(response2).toHaveStatusCode(400); + + const compositeResponse1 = await apiClient.post( + `${DATA_VIEW_PATH}/${dataView.id}/runtime_field`, + { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeComposite', + runtimeField: { + type: 'composite', + script: { + source: 'emit("a","a"); emit("b","b")', + }, + fields: { + a: { type: 'keyword' }, + b: { type: 'keyword' }, + }, + }, + }, + } + ); + + expect(compositeResponse1).toHaveStatusCode(200); + + const compositeResponse2 = await apiClient.post( + `${DATA_VIEW_PATH}/${dataView.id}/runtime_field`, + { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeComposite', + runtimeField: { + type: 'composite', + script: { + source: 'emit("a","a"); emit("b","b")', + }, + fields: { + a: { type: 'keyword' }, + b: { type: 'keyword' }, + }, + }, + }, + } + ); + + expect(compositeResponse2).toHaveStatusCode(400); + }); + } +); diff --git a/src/platform/plugins/shared/data_views/test/scout/api/tests/data_views/runtime_fields_get_errors.spec.ts b/src/platform/plugins/shared/data_views/test/scout/api/tests/data_views/runtime_fields_get_errors.spec.ts new file mode 100644 index 0000000000000..e55985b95afa8 --- /dev/null +++ b/src/platform/plugins/shared/data_views/test/scout/api/tests/data_views/runtime_fields_get_errors.spec.ts @@ -0,0 +1,85 @@ +/* + * 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 { apiTest, tags, type RoleApiCredentials } from '@kbn/scout'; +import { expect } from '@kbn/scout/api'; +import { + COMMON_HEADERS, + ES_ARCHIVE_BASIC_INDEX, + DATA_VIEW_PATH, + ID_OVER_MAX_LENGTH, +} from '../../fixtures/constants'; + +apiTest.describe( + 'GET api/data_views/data_view/{id}/runtime_field/{name} - get errors (data view api)', + { tag: tags.deploymentAgnostic }, + () => { + let viewerApiCredentials: RoleApiCredentials; + let dataViewId: string; + + apiTest.beforeAll(async ({ esArchiver, requestAuth, apiServices }) => { + viewerApiCredentials = await requestAuth.getApiKeyForViewer(); + await esArchiver.loadIfNeeded(ES_ARCHIVE_BASIC_INDEX); + + const { data: dataView } = await apiServices.dataViews.create({ + title: '*asic_index', + }); + dataViewId = dataView.id; + }); + + apiTest.afterAll(async ({ apiServices }) => { + if (dataViewId) { + await apiServices.dataViews.delete(dataViewId); + } + }); + + apiTest('returns 404 error on non-existing data view', async ({ apiClient }) => { + const id = `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-${Date.now()}`; + const response = await apiClient.get(`${DATA_VIEW_PATH}/${id}/runtime_field/foo`, { + headers: { + ...COMMON_HEADERS, + ...viewerApiCredentials.apiKeyHeader, + }, + responseType: 'json', + }); + + expect(response).toHaveStatusCode(404); + }); + + apiTest('returns 404 error on non-existing runtime field', async ({ apiClient }) => { + const response = await apiClient.get(`${DATA_VIEW_PATH}/${dataViewId}/runtime_field/sf`, { + headers: { + ...COMMON_HEADERS, + ...viewerApiCredentials.apiKeyHeader, + }, + responseType: 'json', + }); + + expect(response).toHaveStatusCode(404); + }); + + apiTest('returns error when ID is too long', async ({ apiClient }) => { + const response = await apiClient.get( + `${DATA_VIEW_PATH}/${ID_OVER_MAX_LENGTH}/runtime_field/foo`, + { + headers: { + ...COMMON_HEADERS, + ...viewerApiCredentials.apiKeyHeader, + }, + responseType: 'json', + } + ); + + expect(response).toHaveStatusCode(400); + expect(response.body.message).toBe( + '[request params.id]: value has length [1759] but it must have a maximum length of [1000].' + ); + }); + } +); diff --git a/src/platform/plugins/shared/data_views/test/scout/api/tests/index_patterns/runtime_fields_create_errors.spec.ts b/src/platform/plugins/shared/data_views/test/scout/api/tests/index_patterns/runtime_fields_create_errors.spec.ts new file mode 100644 index 0000000000000..2c4a171b7634c --- /dev/null +++ b/src/platform/plugins/shared/data_views/test/scout/api/tests/index_patterns/runtime_fields_create_errors.spec.ts @@ -0,0 +1,59 @@ +/* + * 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 { apiTest, tags, type RoleApiCredentials } from '@kbn/scout'; +import { expect } from '@kbn/scout/api'; +import { COMMON_HEADERS, DATA_VIEW_PATH_LEGACY } from '../../fixtures/constants'; + +apiTest.describe( + 'POST api/index_patterns/index_pattern/{id}/runtime_field - create errors (legacy index pattern api)', + { tag: tags.deploymentAgnostic }, + () => { + let adminApiCredentials: RoleApiCredentials; + let createdIds: string[] = []; + + apiTest.beforeAll(async ({ requestAuth }) => { + adminApiCredentials = await requestAuth.getApiKey('admin'); + }); + + apiTest.afterEach(async ({ apiServices }) => { + for (const id of createdIds) { + await apiServices.dataViews.delete(id); + } + createdIds = []; + }); + + apiTest( + 'returns an error when runtime field object is not provided', + async ({ apiClient, apiServices }) => { + const title = `foo-${Date.now()}-${Math.random()}*`; + const { data: dataView } = await apiServices.dataViews.create({ title }); + createdIds.push(dataView.id); + + const response = await apiClient.post( + `${DATA_VIEW_PATH_LEGACY}/${dataView.id}/runtime_field`, + { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: {}, + } + ); + + expect(response).toHaveStatusCode(400); + expect(response.body.statusCode).toBe(400); + expect(response.body.message).toBe( + '[request body.name]: expected value of type [string] but got [undefined]' + ); + } + ); + } +); diff --git a/src/platform/plugins/shared/data_views/test/scout/api/tests/index_patterns/runtime_fields_create_main.spec.ts b/src/platform/plugins/shared/data_views/test/scout/api/tests/index_patterns/runtime_fields_create_main.spec.ts new file mode 100644 index 0000000000000..4489f3fc99a60 --- /dev/null +++ b/src/platform/plugins/shared/data_views/test/scout/api/tests/index_patterns/runtime_fields_create_main.spec.ts @@ -0,0 +1,250 @@ +/* + * 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 { apiTest, tags, type RoleApiCredentials } from '@kbn/scout'; +import { expect } from '@kbn/scout/api'; +import { + COMMON_HEADERS, + ES_ARCHIVE_BASIC_INDEX, + DATA_VIEW_PATH_LEGACY, + SERVICE_KEY_LEGACY, +} from '../../fixtures/constants'; + +apiTest.describe( + 'POST api/index_patterns/index_pattern/{id}/runtime_field - create main (legacy index pattern api)', + { tag: tags.deploymentAgnostic }, + () => { + let adminApiCredentials: RoleApiCredentials; + let createdIds: string[] = []; + + apiTest.beforeAll(async ({ esArchiver, requestAuth }) => { + adminApiCredentials = await requestAuth.getApiKey('admin'); + await esArchiver.loadIfNeeded(ES_ARCHIVE_BASIC_INDEX); + }); + + apiTest.afterEach(async ({ apiServices }) => { + for (const id of createdIds) { + await apiServices.dataViews.delete(id); + } + createdIds = []; + }); + + apiTest('can create a new runtime field', async ({ apiClient, apiServices }) => { + const title = `basic_index-${Date.now()}-${Math.random()}*`; + const { data: dataView } = await apiServices.dataViews.create({ + title, + override: true, + }); + createdIds.push(dataView.id); + + const response = await apiClient.post( + `${DATA_VIEW_PATH_LEGACY}/${dataView.id}/runtime_field`, + { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeBar', + runtimeField: { + type: 'long', + script: { + source: "emit(doc['field_name'].value)", + }, + }, + }, + } + ); + + expect(response).toHaveStatusCode(200); + expect(response.body[SERVICE_KEY_LEGACY]).toBeDefined(); + expect(response.body.field).toBeDefined(); + + const field = response.body.field; + expect(field.name).toBe('runtimeBar'); + expect(field.runtimeField.type).toBe('long'); + expect(field.runtimeField.script.source).toBe("emit(doc['field_name'].value)"); + expect(field.scripted).toBe(false); + }); + + apiTest( + 'newly created runtime field is available in the index pattern object', + async ({ apiClient, apiServices }) => { + const title = `basic_index-${Date.now()}-${Math.random()}`; + const { data: dataView } = await apiServices.dataViews.create({ + title, + override: true, + }); + createdIds.push(dataView.id); + + const rtResponse = await apiClient.post( + `${DATA_VIEW_PATH_LEGACY}/${dataView.id}/runtime_field`, + { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeBar', + runtimeField: { + type: 'long', + script: { + source: "emit(doc['field_name'].value)", + }, + }, + }, + } + ); + + expect(rtResponse).toHaveStatusCode(200); + + const { data: retrievedDataView } = await apiServices.dataViews.get(dataView.id); + expect(retrievedDataView).toBeDefined(); + + const fields = retrievedDataView.fields; + expect(fields).toBeDefined(); + + const field = fields!.runtimeBar; + expect(field.name).toBe('runtimeBar'); + expect(field.runtimeField.type).toBe('long'); + expect(field.runtimeField.script.source).toBe("emit(doc['field_name'].value)"); + expect(field.scripted).toBe(false); + + const duplicateResponse = await apiClient.post( + `${DATA_VIEW_PATH_LEGACY}/${dataView.id}/runtime_field`, + { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeBar', + runtimeField: { + type: 'long', + script: { + source: "emit(doc['field_name'].value)", + }, + }, + }, + } + ); + + expect(duplicateResponse).toHaveStatusCode(400); + } + ); + + apiTest('prevents field name collisions', async ({ apiClient, apiServices }) => { + const title = `basic-${Date.now()}-${Math.random()}*`; + const { data: dataView } = await apiServices.dataViews.create({ + title, + override: true, + }); + createdIds.push(dataView.id); + + const response1 = await apiClient.post( + `${DATA_VIEW_PATH_LEGACY}/${dataView.id}/runtime_field`, + { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeBar', + runtimeField: { + type: 'long', + script: { + source: "emit(doc['field_name'].value)", + }, + }, + }, + } + ); + + expect(response1).toHaveStatusCode(200); + + const response2 = await apiClient.post( + `${DATA_VIEW_PATH_LEGACY}/${dataView.id}/runtime_field`, + { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeBar', + runtimeField: { + type: 'long', + script: { + source: "emit(doc['field_name'].value)", + }, + }, + }, + } + ); + + expect(response2).toHaveStatusCode(400); + + const compositeResponse1 = await apiClient.post( + `${DATA_VIEW_PATH_LEGACY}/${dataView.id}/runtime_field`, + { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeComposite', + runtimeField: { + type: 'composite', + script: { + source: 'emit("a","a"); emit("b","b")', + }, + fields: { + a: { type: 'keyword' }, + b: { type: 'keyword' }, + }, + }, + }, + } + ); + + expect(compositeResponse1).toHaveStatusCode(200); + + const compositeResponse2 = await apiClient.post( + `${DATA_VIEW_PATH_LEGACY}/${dataView.id}/runtime_field`, + { + headers: { + ...COMMON_HEADERS, + ...adminApiCredentials.apiKeyHeader, + }, + responseType: 'json', + body: { + name: 'runtimeComposite', + runtimeField: { + type: 'composite', + script: { + source: 'emit("a","a"); emit("b","b")', + }, + fields: { + a: { type: 'keyword' }, + b: { type: 'keyword' }, + }, + }, + }, + } + ); + + expect(compositeResponse2).toHaveStatusCode(400); + }); + } +); diff --git a/src/platform/plugins/shared/data_views/test/scout/api/tests/index_patterns/runtime_fields_get_errors.spec.ts b/src/platform/plugins/shared/data_views/test/scout/api/tests/index_patterns/runtime_fields_get_errors.spec.ts new file mode 100644 index 0000000000000..2492bada0eec0 --- /dev/null +++ b/src/platform/plugins/shared/data_views/test/scout/api/tests/index_patterns/runtime_fields_get_errors.spec.ts @@ -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", 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 { apiTest, tags, type RoleApiCredentials } from '@kbn/scout'; +import { expect } from '@kbn/scout/api'; +import { + COMMON_HEADERS, + ES_ARCHIVE_BASIC_INDEX, + DATA_VIEW_PATH_LEGACY, + ID_OVER_MAX_LENGTH, +} from '../../fixtures/constants'; + +apiTest.describe( + 'GET api/index_patterns/index_pattern/{id}/runtime_field/{name} - get errors (legacy index pattern api)', + { tag: tags.deploymentAgnostic }, + () => { + let viewerApiCredentials: RoleApiCredentials; + let indexPatternId: string; + + apiTest.beforeAll(async ({ esArchiver, requestAuth, apiServices }) => { + viewerApiCredentials = await requestAuth.getApiKeyForViewer(); + await esArchiver.loadIfNeeded(ES_ARCHIVE_BASIC_INDEX); + + const { data: dataView } = await apiServices.dataViews.create({ + title: '*asic_index', + }); + indexPatternId = dataView.id; + }); + + apiTest.afterAll(async ({ apiServices }) => { + if (indexPatternId) { + await apiServices.dataViews.delete(indexPatternId); + } + }); + + apiTest('returns 404 error on non-existing index pattern', async ({ apiClient }) => { + const id = `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-${Date.now()}`; + const response = await apiClient.get(`${DATA_VIEW_PATH_LEGACY}/${id}/runtime_field/foo`, { + headers: { + ...COMMON_HEADERS, + ...viewerApiCredentials.apiKeyHeader, + }, + responseType: 'json', + }); + + expect(response).toHaveStatusCode(404); + }); + + apiTest('returns 404 error on non-existing runtime field', async ({ apiClient }) => { + const response = await apiClient.get( + `${DATA_VIEW_PATH_LEGACY}/${indexPatternId}/runtime_field/sf`, + { + headers: { + ...COMMON_HEADERS, + ...viewerApiCredentials.apiKeyHeader, + }, + responseType: 'json', + } + ); + + expect(response).toHaveStatusCode(404); + }); + + apiTest('returns error when ID is too long', async ({ apiClient }) => { + const response = await apiClient.get( + `${DATA_VIEW_PATH_LEGACY}/${ID_OVER_MAX_LENGTH}/runtime_field/foo`, + { + headers: { + ...COMMON_HEADERS, + ...viewerApiCredentials.apiKeyHeader, + }, + responseType: 'json', + } + ); + + expect(response).toHaveStatusCode(400); + expect(response.body.message).toBe( + '[request params.id]: value has length [1759] but it must have a maximum length of [1000].' + ); + }); + } +); diff --git a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/create_runtime_field/errors.ts b/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/create_runtime_field/errors.ts deleted file mode 100644 index 645783d609754..0000000000000 --- a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/create_runtime_field/errors.ts +++ /dev/null @@ -1,39 +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", 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 expect from '@kbn/expect'; -import type { FtrProviderContext } from '../../../../ftr_provider_context'; -import { configArray } from '../../constants'; - -export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); - - describe('errors', () => { - configArray.forEach((config) => { - describe(config.name, () => { - it('returns an error field object is not provided', async () => { - const title = `foo-${Date.now()}-${Math.random()}*`; - const response1 = await supertest.post(config.path).send({ - [config.serviceKey]: { - title, - }, - }); - const id = response1.body[config.serviceKey].id; - const response2 = await supertest.post(`${config.path}/${id}/runtime_field`).send({}); - - expect(response2.status).to.be(400); - expect(response2.body.statusCode).to.be(400); - expect(response2.body.message).to.be( - '[request body.name]: expected value of type [string] but got [undefined]' - ); - }); - }); - }); - }); -} diff --git a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/create_runtime_field/index.ts b/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/create_runtime_field/index.ts deleted file mode 100644 index b2c6f532eac64..0000000000000 --- a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/create_runtime_field/index.ts +++ /dev/null @@ -1,17 +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", 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 type { FtrProviderContext } from '../../../../ftr_provider_context'; - -export default function ({ loadTestFile }: FtrProviderContext) { - describe('create_runtime_field', () => { - loadTestFile(require.resolve('./errors')); - loadTestFile(require.resolve('./main')); - }); -} diff --git a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/create_runtime_field/main.ts b/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/create_runtime_field/main.ts deleted file mode 100644 index e7097dcf2f163..0000000000000 --- a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/create_runtime_field/main.ts +++ /dev/null @@ -1,200 +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", 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 expect from '@kbn/expect'; -import type { FtrProviderContext } from '../../../../ftr_provider_context'; -import { configArray } from '../../constants'; - -export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('main', () => { - before(async () => { - await esArchiver.load( - 'src/platform/test/api_integration/fixtures/es_archiver/index_patterns/basic_index' - ); - }); - - after(async () => { - await esArchiver.unload( - 'src/platform/test/api_integration/fixtures/es_archiver/index_patterns/basic_index' - ); - }); - - configArray.forEach((config) => { - describe(config.name, () => { - it('can create a new runtime field', async () => { - const title = `basic_index*`; - const response1 = await supertest.post(config.path).send({ - override: true, - [config.serviceKey]: { - title, - }, - }); - const id = response1.body[config.serviceKey].id; - const response2 = await supertest.post(`${config.path}/${id}/runtime_field`).send({ - name: 'runtimeBar', - runtimeField: { - type: 'long', - script: { - source: "emit(doc['field_name'].value)", - }, - }, - }); - - expect(response2.status).to.be(200); - expect(response2.body[config.serviceKey]).to.not.be.empty(); - - const field = - config.serviceKey === 'index_pattern' ? response2.body.field : response2.body.fields[0]; - - expect(field.name).to.be('runtimeBar'); - expect(field.runtimeField.type).to.be('long'); - expect(field.runtimeField.script.source).to.be("emit(doc['field_name'].value)"); - expect(field.scripted).to.be(false); - }); - - it('newly created runtime field is available in the index_pattern object', async () => { - const title = `basic_index`; - const response1 = await supertest.post(config.path).send({ - override: true, - [config.serviceKey]: { - title, - }, - }); - - await supertest - .post(`${config.path}/${response1.body[config.serviceKey].id}/runtime_field`) - .send({ - name: 'runtimeBar', - runtimeField: { - type: 'long', - script: { - source: "emit(doc['field_name'].value)", - }, - }, - }); - - const response2 = await supertest.get( - `${config.path}/${response1.body[config.serviceKey].id}` - ); - - expect(response2.status).to.be(200); - expect(response2.body[config.serviceKey]).to.not.be.empty(); - - const field = response2.body[config.serviceKey].fields.runtimeBar; - - expect(field.name).to.be('runtimeBar'); - expect(field.runtimeField.type).to.be('long'); - expect(field.runtimeField.script.source).to.be("emit(doc['field_name'].value)"); - expect(field.scripted).to.be(false); - - const response3 = await supertest - .post(`${config.path}/${response1.body[config.serviceKey].id}/runtime_field`) - .send({ - name: 'runtimeBar', - runtimeField: { - type: 'long', - script: { - source: "emit(doc['field_name'].value)", - }, - }, - }); - - expect(response3.status).to.be(400); - - await supertest.delete(`${config.path}/${response1.body[config.serviceKey].id}`); - }); - - it('prevents field name collisions', async () => { - const title = `basic*`; - const response1 = await supertest.post(config.path).send({ - override: true, - [config.serviceKey]: { - title, - }, - }); - - const response2 = await supertest - .post(`${config.path}/${response1.body[config.serviceKey].id}/runtime_field`) - .send({ - name: 'runtimeBar', - runtimeField: { - type: 'long', - script: { - source: "emit(doc['field_name'].value)", - }, - }, - }); - - expect(response2.status).to.be(200); - - const response3 = await supertest - .post(`${config.path}/${response1.body[config.serviceKey].id}/runtime_field`) - .send({ - name: 'runtimeBar', - runtimeField: { - type: 'long', - script: { - source: "emit(doc['field_name'].value)", - }, - }, - }); - - expect(response3.status).to.be(400); - - const response4 = await supertest - .post(`${config.path}/${response1.body[config.serviceKey].id}/runtime_field`) - .send({ - name: 'runtimeComposite', - runtimeField: { - type: 'composite', - script: { - source: 'emit("a","a"); emit("b","b")', - }, - fields: { - a: { - type: 'keyword', - }, - b: { - type: 'keyword', - }, - }, - }, - }); - - expect(response4.status).to.be(200); - - const response5 = await supertest - .post(`${config.path}/${response1.body[config.serviceKey].id}/runtime_field`) - .send({ - name: 'runtimeComposite', - runtimeField: { - type: 'composite', - script: { - source: 'emit("a","a"); emit("b","b")', - }, - fields: { - a: { - type: 'keyword', - }, - b: { - type: 'keyword', - }, - }, - }, - }); - - expect(response5.status).to.be(400); - }); - }); - }); - }); -} diff --git a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/get_runtime_field/errors.ts b/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/get_runtime_field/errors.ts deleted file mode 100644 index f95f8363e74b9..0000000000000 --- a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/get_runtime_field/errors.ts +++ /dev/null @@ -1,75 +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", 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 expect from '@kbn/expect'; -import type { FtrProviderContext } from '../../../../ftr_provider_context'; -import { configArray } from '../../constants'; - -export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const supertest = getService('supertest'); - - describe('errors', () => { - const basicIndex = '*asic_index'; - let indexPattern: any; - - configArray.forEach((config) => { - describe(config.name, () => { - before(async () => { - await esArchiver.load( - 'src/platform/test/api_integration/fixtures/es_archiver/index_patterns/basic_index' - ); - - indexPattern = ( - await supertest.post(config.path).send({ - [config.serviceKey]: { - title: basicIndex, - }, - }) - ).body[config.serviceKey]; - }); - - after(async () => { - await esArchiver.unload( - 'src/platform/test/api_integration/fixtures/es_archiver/index_patterns/basic_index' - ); - - if (indexPattern) { - await supertest.delete(`${config.path}/${indexPattern.id}`); - } - }); - - it('returns 404 error on non-existing index_pattern', async () => { - const id = `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-${Date.now()}`; - const response = await supertest.get(`${config.path}/${id}/runtime_field/foo`); - - expect(response.status).to.be(404); - }); - - it('returns 404 error on non-existing runtime field', async () => { - const response1 = await supertest.get( - `${config.path}/${indexPattern.id}/runtime_field/sf` - ); - - expect(response1.status).to.be(404); - }); - - it('returns error when ID is too long', async () => { - const id = `xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx`; - const response = await supertest.get(`${config.path}/${id}/runtime_field/foo`); - - expect(response.status).to.be(400); - expect(response.body.message).to.be( - '[request params.id]: value has length [1759] but it must have a maximum length of [1000].' - ); - }); - }); - }); - }); -} diff --git a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/get_runtime_field/index.ts b/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/get_runtime_field/index.ts index e7e55a8e5d54d..e33ed16617a5f 100644 --- a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/get_runtime_field/index.ts +++ b/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/get_runtime_field/index.ts @@ -11,7 +11,6 @@ import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('get_runtime_field', () => { - loadTestFile(require.resolve('./errors')); loadTestFile(require.resolve('./main')); }); } diff --git a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/index.ts b/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/index.ts index c7fdb67ed2736..2375955ce7e30 100644 --- a/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/index.ts +++ b/src/platform/test/api_integration/apis/data_views/runtime_fields_crud/index.ts @@ -11,7 +11,6 @@ import type { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('runtime_fields_crud', () => { - loadTestFile(require.resolve('./create_runtime_field')); loadTestFile(require.resolve('./get_runtime_field')); loadTestFile(require.resolve('./delete_runtime_field')); loadTestFile(require.resolve('./put_runtime_field'));