From 1c3c51a2d180661a81136c64f7413c6707ec8d4f Mon Sep 17 00:00:00 2001 From: iblancof Date: Mon, 18 Nov 2024 11:58:04 +0100 Subject: [PATCH 01/21] Create settings/anomaly_detection basic deployment agnostic api tests --- .../settings/anomaly_detection/basic.spec.ts | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.spec.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.spec.ts new file mode 100644 index 0000000000000..7c35a47776f55 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; +import { ApmApiError } from '../../../../../services/apm_api'; + +export default function apiTest({ getService }: DeploymentAgnosticFtrProviderContext) { + const apmApiClient = getService('apmApi'); + + type SupertestAsUser = typeof apmApiClient.readUser | typeof apmApiClient.writeUser; + + function getJobs(user: SupertestAsUser) { + return user({ endpoint: `GET /internal/apm/settings/anomaly-detection/jobs` }); + } + + function createJobs(user: SupertestAsUser, environments: string[]) { + return user({ + endpoint: 'POST /internal/apm/settings/anomaly-detection/jobs', + params: { + body: { environments }, + }, + }); + } + + async function expectForbidden(user: SupertestAsUser) { + try { + await getJobs(user); + } catch (e) { + const err = e as ApmApiError; + expect(err.res.status).to.be(403); + } + + try { + await createJobs(user, ['production', 'staging']); + } catch (e) { + const err = e as ApmApiError; + expect(err.res.status).to.be(403); + } + } + + describe('ML jobs return a 403 for', () => { + describe('basic', function () { + this.tags('skipFIPS'); + + it('read user', async () => { + await expectForbidden(apmApiClient.readUser); + }); + + it('write user', async () => { + await expectForbidden(apmApiClient.writeUser); + }); + }); + }); +} From 744db47dfc9a67bcfd81bbe5f38162b5cafa89fb Mon Sep 17 00:00:00 2001 From: iblancof Date: Mon, 18 Nov 2024 17:16:51 +0100 Subject: [PATCH 02/21] Create settings/anomaly_detection read user deployment agnostic api tests --- .../anomaly_detection/read_user.spec.ts | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/read_user.spec.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/read_user.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/read_user.spec.ts new file mode 100644 index 0000000000000..10932014000d9 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/read_user.spec.ts @@ -0,0 +1,52 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; +import { ApmApiError } from '../../../../../services/apm_api'; + +export default function apiTest({ getService }: DeploymentAgnosticFtrProviderContext) { + const apmApiClient = getService('apmApi'); + + function getJobs() { + return apmApiClient.readUser({ endpoint: `GET /internal/apm/settings/anomaly-detection/jobs` }); + } + + function createJobs(environments: string[]) { + return apmApiClient.readUser({ + endpoint: `POST /internal/apm/settings/anomaly-detection/jobs`, + params: { + body: { environments }, + }, + }); + } + + describe('ML jobs', () => { + describe(`when readUser has read access to ML`, () => { + describe('when calling the endpoint for listing jobs', () => { + it('returns a list of jobs', async () => { + const { body } = await getJobs(); + + expect(body.jobs).not.to.be(undefined); + expect(body.hasLegacyJobs).to.be(false); + }); + }); + + describe('when calling create endpoint', () => { + it('returns an error because the user does not have access', async () => { + try { + await createJobs(['production', 'staging']); + expect(true).to.be(false); + } catch (e) { + const err = e as ApmApiError; + expect(err.res.status).to.be(403); + } + }); + }); + }); + }); +} From eeb1971498973abc477a605d87397430d3275ef6 Mon Sep 17 00:00:00 2001 From: iblancof Date: Tue, 19 Nov 2024 13:13:11 +0100 Subject: [PATCH 03/21] Create settings/custom_link deployment agnostic api tests --- .../settings/custom_link/custom_link.spec.ts | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts new file mode 100644 index 0000000000000..da1c1edc47d46 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts @@ -0,0 +1,213 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { CustomLink } from '@kbn/apm-plugin/common/custom_link/custom_link_types'; +import { ApmApiError } from '../../../../../services/apm_api'; +import { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; +import { ARCHIVER_ROUTES } from '../../constants/archiver'; + +export default function customLinksTests({ getService }: DeploymentAgnosticFtrProviderContext) { + const esArchiver = getService('esArchiver'); + const apmApiClient = getService('apmApi'); + const log = getService('log'); + + const archiveName = '8.0.0'; + + describe('Custom links with data', () => { + before(async () => { + await esArchiver.load(ARCHIVER_ROUTES[archiveName]); + + const customLink = { + url: 'https://elastic.co', + label: 'with filters', + filters: [ + { key: 'service.name', value: 'baz' }, + { key: 'transaction.type', value: 'qux' }, + ], + } as CustomLink; + + await createCustomLink(customLink); + }); + + after(async () => { + await esArchiver.unload(ARCHIVER_ROUTES['8.0.0']); + }); + + it('should fail if the user does not have write access', async () => { + const customLink = { + url: 'https://elastic.co', + label: 'with filters', + filters: [ + { key: 'service.name', value: 'baz' }, + { key: 'transaction.type', value: 'qux' }, + ], + } as CustomLink; + + const err = await expectToReject(() => createCustomLinkAsReadUser(customLink)); + expect(err.res.status).to.be(403); + }); + + it('fetches a custom link', async () => { + const { status, body } = await searchCustomLinks({ + 'service.name': 'baz', + 'transaction.type': 'qux', + }); + const { label, url, filters } = body.customLinks[0]; + + expect(status).to.equal(200); + expect({ label, url, filters }).to.eql({ + label: 'with filters', + url: 'https://elastic.co', + filters: [ + { key: 'service.name', value: 'baz' }, + { key: 'transaction.type', value: 'qux' }, + ], + }); + }); + + it(`creates a custom link as write user`, async () => { + const customLink = { + url: 'https://elastic.co', + label: 'with filters', + filters: [ + { key: 'service.name', value: 'baz' }, + { key: 'transaction.type', value: 'qux' }, + ], + } as CustomLink; + + await createCustomLink(customLink); + }); + + it(`updates a custom link as write user`, async () => { + const { status, body } = await searchCustomLinks({ + 'service.name': 'baz', + 'transaction.type': 'qux', + }); + expect(status).to.equal(200); + + const id = body.customLinks[0].id!; + await updateCustomLink(id, { + label: 'foo', + url: 'https://elastic.co?service.name={{service.name}}', + filters: [ + { key: 'service.name', value: 'quz' }, + { key: 'transaction.name', value: 'bar' }, + ], + }); + + const { status: newStatus, body: newBody } = await searchCustomLinks({ + 'service.name': 'quz', + 'transaction.name': 'bar', + }); + + const { label, url, filters } = newBody.customLinks[0]; + expect(newStatus).to.equal(200); + expect({ label, url, filters }).to.eql({ + label: 'foo', + url: 'https://elastic.co?service.name={{service.name}}', + filters: [ + { key: 'service.name', value: 'quz' }, + { key: 'transaction.name', value: 'bar' }, + ], + }); + }); + + it(`deletes a custom link as write user`, async () => { + const { status, body } = await searchCustomLinks({ + 'service.name': 'quz', + 'transaction.name': 'bar', + }); + expect(status).to.equal(200); + expect(body.customLinks.length).to.be(1); + + const id = body.customLinks[0].id!; + await deleteCustomLink(id); + + const { status: newStatus, body: newBody } = await searchCustomLinks({ + 'service.name': 'quz', + 'transaction.name': 'bar', + }); + expect(newStatus).to.equal(200); + expect(newBody.customLinks.length).to.be(0); + }); + + it('fetches a transaction sample', async () => { + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/settings/custom_links/transaction', + params: { + query: { + 'service.name': 'opbeans-java', + }, + }, + }); + expect(response.status).to.be(200); + expect(response.body.service.name).to.eql('opbeans-java'); + }); + }); + + function searchCustomLinks(filters?: any) { + return apmApiClient.readUser({ + endpoint: 'GET /internal/apm/settings/custom_links', + params: { + query: filters, + }, + }); + } + + async function createCustomLink(customLink: CustomLink) { + log.debug('creating configuration', customLink); + + return apmApiClient.writeUser({ + endpoint: 'POST /internal/apm/settings/custom_links', + params: { + body: customLink, + }, + }); + } + + async function createCustomLinkAsReadUser(customLink: CustomLink) { + log.debug('creating configuration', customLink); + + return apmApiClient.readUser({ + endpoint: 'POST /internal/apm/settings/custom_links', + params: { + body: customLink, + }, + }); + } + + async function updateCustomLink(id: string, customLink: CustomLink) { + log.debug('updating configuration', id, customLink); + + return apmApiClient.writeUser({ + endpoint: 'PUT /internal/apm/settings/custom_links/{id}', + params: { + path: { id }, + body: customLink, + }, + }); + } + + async function deleteCustomLink(id: string) { + log.debug('deleting configuration', id); + + return apmApiClient.writeUser({ + endpoint: 'DELETE /internal/apm/settings/custom_links/{id}', + params: { path: { id } }, + }); + } +} + +async function expectToReject(fn: () => Promise): Promise { + try { + await fn(); + } catch (e) { + return e; + } + throw new Error(`Expected fn to throw`); +} From a825c95dc50a523355c7fc24c8b675d18354cbc8 Mon Sep 17 00:00:00 2001 From: iblancof Date: Tue, 19 Nov 2024 13:13:32 +0100 Subject: [PATCH 04/21] Create settings/apm_indices deployment agnostic api tests --- .../settings/apm_indices/apm_indices.spec.ts | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts new file mode 100644 index 0000000000000..f8008e9fa97e7 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts @@ -0,0 +1,74 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + APM_INDEX_SETTINGS_SAVED_OBJECT_ID, + APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, +} from '@kbn/apm-data-access-plugin/server/saved_objects/apm_indices'; +import expect from '@kbn/expect'; +import { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; + +export default function apmIndicesTests({ getService }: DeploymentAgnosticFtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const apmApiClient = getService('apmApi'); + + async function deleteSavedObject() { + try { + return await kibanaServer.savedObjects.delete({ + type: APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, + id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, + }); + } catch (e) { + if (e.response.status !== 404) { + throw e; + } + } + } + + describe('APM Indices', () => { + beforeEach(async () => { + await deleteSavedObject(); + }); + afterEach(async () => { + await deleteSavedObject(); + }); + + it('returns APM Indices', async () => { + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/settings/apm-indices', + }); + expect(response.status).to.be(200); + expect(response.body).to.eql({ + transaction: 'traces-apm*,apm-*,traces-*.otel-*', + span: 'traces-apm*,apm-*,traces-*.otel-*', + error: 'logs-apm*,apm-*,logs-*.otel-*', + metric: 'metrics-apm*,apm-*,metrics-*.otel-*', + onboarding: 'apm-*', + sourcemap: 'apm-*', + }); + }); + + it('updates apm indices', async () => { + const INDEX_VALUE = 'foo-*'; + + const writeResponse = await apmApiClient.writeUser({ + endpoint: 'POST /internal/apm/settings/apm-indices/save', + params: { + body: { transaction: INDEX_VALUE }, + }, + }); + expect(writeResponse.status).to.be(200); + + const readResponse = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/settings/apm-indices', + }); + + expect(readResponse.status).to.be(200); + expect(readResponse.body.transaction).to.eql(INDEX_VALUE); + }); + }); +} From 86c262fb9df7e9299736b059d8dc6c76aa940794 Mon Sep 17 00:00:00 2001 From: iblancof Date: Tue, 19 Nov 2024 16:19:55 +0100 Subject: [PATCH 05/21] Create settings/agent_keys deployment agnostic api tests --- .../settings/agent_keys/agent_keys.spec.ts | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts new file mode 100644 index 0000000000000..c6d0a917642ce --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts @@ -0,0 +1,86 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import expect from '@kbn/expect'; +import { PrivilegeType, ClusterPrivilegeType } from '@kbn/apm-plugin/common/privilege_type'; +import { RoleCredentials } from '../../../../../services'; +import { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; +import { expectToReject } from '../../../../../../../apm_api_integration/common/utils/expect_to_reject'; +import { ApmApiError } from '../../../../../services/apm_api'; + +export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { + const apmApiClient = getService('apmApi'); + const samlAuth = getService('samlAuth'); + + const agentKeyName = 'test'; + const allApplicationPrivileges = [PrivilegeType.AGENT_CONFIG, PrivilegeType.EVENT]; + const clusterPrivileges = [ClusterPrivilegeType.MANAGE_OWN_API_KEY]; + + async function createAgentKey( + apiClient: (typeof apmApiClient)[keyof typeof apmApiClient], + roleAuthc: RoleCredentials, + privileges = allApplicationPrivileges + ) { + return await apiClient({ + endpoint: 'POST /api/apm/agent_keys 2023-10-31', + params: { + body: { + name: agentKeyName, + privileges, + }, + }, + roleAuthc, + }); + } + + async function invalidateAgentKey(id: string) { + return await apmApiClient.writeUser({ + endpoint: 'POST /internal/apm/api_key/invalidate', + params: { + body: { id }, + }, + }); + } + + async function getAgentKeys() { + return await apmApiClient.writeUser({ endpoint: 'GET /internal/apm/agent_keys' }); + } + + describe('When the user does not have the required privileges', () => { + let roleAuthc: RoleCredentials; + + before(async () => { + roleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('editor'); + }); + + describe('When the user does not have the required cluster privileges', () => { + it('should return an error when creating an agent key', async () => { + const error = await expectToReject(() => + createAgentKey(apmApiClient.writeUser, roleAuthc) + ); + expect(error.res.status).to.be(403); + expect(error.res.body.message).contain('is missing the following requested privilege'); + expect(error.res.body.attributes).to.eql({ + _inspect: [], + data: { + missingPrivileges: allApplicationPrivileges, + missingClusterPrivileges: clusterPrivileges, + }, + }); + }); + + it('should return an error when invalidating an agent key', async () => { + const error = await expectToReject(() => invalidateAgentKey(agentKeyName)); + expect(error.res.status).to.be(500); + }); + + it('should return an error when getting a list of agent keys', async () => { + const error = await expectToReject(() => getAgentKeys()); + expect(error.res.status).to.be(500); + }); + }); + }); +} From 8c4f48a3a3fedad7ef8bd4a8efaea67a83bf3a1a Mon Sep 17 00:00:00 2001 From: iblancof Date: Tue, 19 Nov 2024 16:20:37 +0100 Subject: [PATCH 06/21] Create tests loader for settings deployment agnostic tests --- .../apis/observability/apm/index.ts | 1 + .../apis/observability/apm/settings/index.ts | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/index.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts index ff5a4618e33c3..ed0b523015459 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts @@ -27,5 +27,6 @@ export default function apmApiIntegrationTests({ loadTestFile(require.resolve('./latency')); loadTestFile(require.resolve('./infrastructure')); loadTestFile(require.resolve('./service_groups')); + loadTestFile(require.resolve('./settings')); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/index.ts new file mode 100644 index 0000000000000..5690ce79690c3 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/index.ts @@ -0,0 +1,18 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) { + describe('settings', () => { + loadTestFile(require.resolve('./agent_keys/agent_keys.spec.ts')); + loadTestFile(require.resolve('./anomaly_detection/basic.spec.ts')); + loadTestFile(require.resolve('./anomaly_detection/read_user.spec.ts')); + loadTestFile(require.resolve('./apm_indices/apm_indices.spec.ts')); + loadTestFile(require.resolve('./custom_link/custom_link.spec.ts')); + }); +} From ed0bc6b76915f22fc85011e816b9709282d13677 Mon Sep 17 00:00:00 2001 From: iblancof Date: Tue, 19 Nov 2024 16:32:41 +0100 Subject: [PATCH 07/21] Clean stateful tests --- .../settings/agent_keys/agent_keys.spec.ts | 31 -------- .../anomaly_detection/read_user.spec.ts | 50 ++++++------- .../anomaly_detection/write_user.spec.ts | 74 +++++++++---------- .../settings/apm_indices/apm_indices.spec.ts | 34 --------- 4 files changed, 60 insertions(+), 129 deletions(-) diff --git a/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts b/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts index 82c869dd09fe2..c46ea8c83b34d 100644 --- a/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts +++ b/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts @@ -50,37 +50,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { 'When the user does not have the required privileges', { config: 'basic', archives: [] }, () => { - describe('When the user does not have the required cluster privileges', () => { - it('should return an error when creating an agent key', async () => { - const error = await expectToReject(() => - createAgentKey(apmApiClient.writeUser) - ); - expect(error.res.status).to.be(403); - expect(error.res.body.message).contain('is missing the following requested privilege'); - expect(error.res.body.attributes).to.eql({ - _inspect: [], - data: { - missingPrivileges: allApplicationPrivileges, - missingClusterPrivileges: clusterPrivileges, - }, - }); - }); - - it('should return an error when invalidating an agent key', async () => { - const error = await expectToReject(() => - invalidateAgentKey(apmApiClient.writeUser, agentKeyName) - ); - expect(error.res.status).to.be(500); - }); - - it('should return an error when getting a list of agent keys', async () => { - const error = await expectToReject(() => - getAgentKeys(apmApiClient.writeUser) - ); - expect(error.res.status).to.be(500); - }); - }); - describe('When the user does not have the required application privileges', () => { allApplicationPrivileges.map((privilege) => { it(`should return an error when creating an agent key with ${privilege} privilege`, async () => { diff --git a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/read_user.spec.ts b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/read_user.spec.ts index cc56731fec07b..fa9bcb1d0700d 100644 --- a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/read_user.spec.ts +++ b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/read_user.spec.ts @@ -35,37 +35,35 @@ export default function apiTest({ getService }: FtrProviderContext) { } registry.when('ML jobs', { config: 'trial', archives: [] }, () => { - (['readUser', 'apmAllPrivilegesWithoutWriteSettingsUser'] as ApmApiClientKey[]).forEach( - (user) => { - describe(`when ${user} has read access to ML`, () => { - before(async () => { - const res = await getJobs({ user }); - const jobIds = res.body.jobs.map((job: any) => job.jobId); - await deleteJobs(jobIds); - }); + (['apmAllPrivilegesWithoutWriteSettingsUser'] as ApmApiClientKey[]).forEach((user) => { + describe(`when ${user} has read access to ML`, () => { + before(async () => { + const res = await getJobs({ user }); + const jobIds = res.body.jobs.map((job: any) => job.jobId); + await deleteJobs(jobIds); + }); - describe('when calling the endpoint for listing jobs', () => { - it('returns a list of jobs', async () => { - const { body } = await getJobs({ user }); + describe('when calling the endpoint for listing jobs', () => { + it('returns a list of jobs', async () => { + const { body } = await getJobs({ user }); - expect(body.jobs.length).to.be(0); - expect(body.hasLegacyJobs).to.be(false); - }); + expect(body.jobs.length).to.be(0); + expect(body.hasLegacyJobs).to.be(false); }); + }); - describe('when calling create endpoint', () => { - it('returns an error because the user does not have access', async () => { - try { - await createJobs(['production', 'staging'], { user }); - expect(true).to.be(false); - } catch (e) { - const err = e as ApmApiError; - expect(err.res.status).to.be(403); - } - }); + describe('when calling create endpoint', () => { + it('returns an error because the user does not have access', async () => { + try { + await createJobs(['production', 'staging'], { user }); + expect(true).to.be(false); + } catch (e) { + const err = e as ApmApiError; + expect(err.res.status).to.be(403); + } }); }); - } - ); + }); + }); }); } diff --git a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.spec.ts b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.spec.ts index 652da64384dd7..40e62b1ddc969 100644 --- a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.spec.ts +++ b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.spec.ts @@ -35,59 +35,57 @@ export default function apiTest({ getService }: FtrProviderContext) { } registry.when('ML jobs', { config: 'trial', archives: [] }, () => { - (['writeUser', 'apmReadPrivilegesWithWriteSettingsUser'] as ApmApiClientKey[]).forEach( - (user) => { - describe(`when ${user} has write access to ML`, () => { - before(async () => { - const res = await getJobs({ user }); - const jobIds = res.body.jobs.map((job: any) => job.jobId); - await deleteJobs(jobIds); - }); + (['apmReadPrivilegesWithWriteSettingsUser'] as ApmApiClientKey[]).forEach((user) => { + describe(`when ${user} has write access to ML`, () => { + before(async () => { + const res = await getJobs({ user }); + const jobIds = res.body.jobs.map((job: any) => job.jobId); + await deleteJobs(jobIds); + }); + + after(async () => { + const res = await getJobs({ user }); + const jobIds = res.body.jobs.map((job: any) => job.jobId); + await deleteJobs(jobIds); + }); - after(async () => { - const res = await getJobs({ user }); - const jobIds = res.body.jobs.map((job: any) => job.jobId); - await deleteJobs(jobIds); + describe('when calling the endpoint for listing jobs', () => { + it('returns a list of jobs', async () => { + const { body } = await getJobs({ user }); + expect(body.jobs.length).to.be(0); + expect(body.hasLegacyJobs).to.be(false); }); + }); - describe('when calling the endpoint for listing jobs', () => { - it('returns a list of jobs', async () => { - const { body } = await getJobs({ user }); - expect(body.jobs.length).to.be(0); - expect(body.hasLegacyJobs).to.be(false); + describe('when calling create endpoint', () => { + it('creates two jobs', async () => { + await createJobs(['production', 'staging'], { user }); + + const { body } = await getJobs({ user }); + expect(body.hasLegacyJobs).to.be(false); + expect(countBy(body.jobs, 'environment')).to.eql({ + production: 1, + staging: 1, }); }); - describe('when calling create endpoint', () => { - it('creates two jobs', async () => { + describe('with existing ML jobs', () => { + before(async () => { await createJobs(['production', 'staging'], { user }); + }); + it('skips duplicate job creation', async () => { + await createJobs(['production', 'test'], { user }); const { body } = await getJobs({ user }); - expect(body.hasLegacyJobs).to.be(false); expect(countBy(body.jobs, 'environment')).to.eql({ production: 1, staging: 1, - }); - }); - - describe('with existing ML jobs', () => { - before(async () => { - await createJobs(['production', 'staging'], { user }); - }); - it('skips duplicate job creation', async () => { - await createJobs(['production', 'test'], { user }); - - const { body } = await getJobs({ user }); - expect(countBy(body.jobs, 'environment')).to.eql({ - production: 1, - staging: 1, - test: 1, - }); + test: 1, }); }); }); }); - } - ); + }); + }); }); } diff --git a/x-pack/test/apm_api_integration/tests/settings/apm_indices/apm_indices.spec.ts b/x-pack/test/apm_api_integration/tests/settings/apm_indices/apm_indices.spec.ts index 41bc0448e063e..6fb5977626259 100644 --- a/x-pack/test/apm_api_integration/tests/settings/apm_indices/apm_indices.spec.ts +++ b/x-pack/test/apm_api_integration/tests/settings/apm_indices/apm_indices.spec.ts @@ -107,40 +107,6 @@ export default function apmIndicesTests({ getService }: FtrProviderContext) { await deleteSavedObject(); }); - it('[trial] returns APM Indices', async () => { - const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/settings/apm-indices', - }); - expect(response.status).to.be(200); - expect(response.body).to.eql({ - transaction: 'traces-apm*,apm-*,traces-*.otel-*', - span: 'traces-apm*,apm-*,traces-*.otel-*', - error: 'logs-apm*,apm-*,logs-*.otel-*', - metric: 'metrics-apm*,apm-*,metrics-*.otel-*', - onboarding: 'apm-*', - sourcemap: 'apm-*', - }); - }); - - it('[trial] updates apm indices', async () => { - const INDEX_VALUE = 'foo-*'; - - const writeResponse = await apmApiClient.writeUser({ - endpoint: 'POST /internal/apm/settings/apm-indices/save', - params: { - body: { transaction: INDEX_VALUE }, - }, - }); - expect(writeResponse.status).to.be(200); - - const readResponse = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/settings/apm-indices', - }); - - expect(readResponse.status).to.be(200); - expect(readResponse.body.transaction).to.eql(INDEX_VALUE); - }); - it('[trial] updates apm indices as read privileges with modify settings user', async () => { const INDEX_VALUE = 'foo-*'; From e74f5514701f3484972004e1a2c7e17c97054d98 Mon Sep 17 00:00:00 2001 From: iblancof Date: Tue, 19 Nov 2024 17:07:16 +0100 Subject: [PATCH 08/21] Refactor imports to use type-only imports in APM settings test files --- .../apm/settings/agent_keys/agent_keys.spec.ts | 6 +++--- .../apm/settings/anomaly_detection/basic.spec.ts | 4 ++-- .../apm/settings/anomaly_detection/read_user.spec.ts | 4 ++-- .../apm/settings/apm_indices/apm_indices.spec.ts | 2 +- .../apm/settings/custom_link/custom_link.spec.ts | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts index c6d0a917642ce..dc4439f391763 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts @@ -6,10 +6,10 @@ */ import expect from '@kbn/expect'; import { PrivilegeType, ClusterPrivilegeType } from '@kbn/apm-plugin/common/privilege_type'; -import { RoleCredentials } from '../../../../../services'; -import { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; +import type { RoleCredentials } from '../../../../../services'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; import { expectToReject } from '../../../../../../../apm_api_integration/common/utils/expect_to_reject'; -import { ApmApiError } from '../../../../../services/apm_api'; +import type { ApmApiError } from '../../../../../services/apm_api'; export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { const apmApiClient = getService('apmApi'); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.spec.ts index 7c35a47776f55..0aab44c6e27c3 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.spec.ts @@ -6,8 +6,8 @@ */ import expect from '@kbn/expect'; -import { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; -import { ApmApiError } from '../../../../../services/apm_api'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; +import type { ApmApiError } from '../../../../../services/apm_api'; export default function apiTest({ getService }: DeploymentAgnosticFtrProviderContext) { const apmApiClient = getService('apmApi'); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/read_user.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/read_user.spec.ts index 10932014000d9..0de23a4c27f2f 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/read_user.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/read_user.spec.ts @@ -6,8 +6,8 @@ */ import expect from '@kbn/expect'; -import { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; -import { ApmApiError } from '../../../../../services/apm_api'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; +import type { ApmApiError } from '../../../../../services/apm_api'; export default function apiTest({ getService }: DeploymentAgnosticFtrProviderContext) { const apmApiClient = getService('apmApi'); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts index f8008e9fa97e7..9c94afd69abf4 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts @@ -10,7 +10,7 @@ import { APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, } from '@kbn/apm-data-access-plugin/server/saved_objects/apm_indices'; import expect from '@kbn/expect'; -import { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; export default function apmIndicesTests({ getService }: DeploymentAgnosticFtrProviderContext) { const kibanaServer = getService('kibanaServer'); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts index da1c1edc47d46..3f4d99976e6ea 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts @@ -6,9 +6,9 @@ */ import expect from '@kbn/expect'; -import { CustomLink } from '@kbn/apm-plugin/common/custom_link/custom_link_types'; -import { ApmApiError } from '../../../../../services/apm_api'; -import { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; +import type { CustomLink } from '@kbn/apm-plugin/common/custom_link/custom_link_types'; +import type { ApmApiError } from '../../../../../services/apm_api'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; import { ARCHIVER_ROUTES } from '../../constants/archiver'; export default function customLinksTests({ getService }: DeploymentAgnosticFtrProviderContext) { From e183e466cfb8cb1dc63f6517f852cb530f2d53e6 Mon Sep 17 00:00:00 2001 From: iblancof Date: Tue, 19 Nov 2024 17:16:15 +0100 Subject: [PATCH 09/21] Invalidate samlAuth --- .../observability/apm/settings/agent_keys/agent_keys.spec.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts index dc4439f391763..db61ffeb15d8d 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts @@ -56,6 +56,10 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon roleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('editor'); }); + after(async () => { + await samlAuth.invalidateM2mApiKeyWithRoleScope(roleAuthc); + }); + describe('When the user does not have the required cluster privileges', () => { it('should return an error when creating an agent key', async () => { const error = await expectToReject(() => From 48a98c97f722e7d33eb2851218d4ba4d969d3afc Mon Sep 17 00:00:00 2001 From: iblancof Date: Tue, 19 Nov 2024 17:27:32 +0100 Subject: [PATCH 10/21] Remove unused constant --- .../tests/settings/agent_keys/agent_keys.spec.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts b/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts index c46ea8c83b34d..8d8808c282a8b 100644 --- a/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts +++ b/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; import { first } from 'lodash'; -import { PrivilegeType, ClusterPrivilegeType } from '@kbn/apm-plugin/common/privilege_type'; +import { PrivilegeType } from '@kbn/apm-plugin/common/privilege_type'; import { ApmUsername } from '@kbn/apm-plugin/server/test_helpers/create_apm_users/authentication'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import { ApmApiError, ApmApiSupertest } from '../../../common/apm_api_supertest'; @@ -19,7 +19,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { const agentKeyName = 'test'; const allApplicationPrivileges = [PrivilegeType.AGENT_CONFIG, PrivilegeType.EVENT]; - const clusterPrivileges = [ClusterPrivilegeType.MANAGE_OWN_API_KEY]; async function createAgentKey(apiClient: ApmApiSupertest, privileges = allApplicationPrivileges) { return await apiClient({ From 8c61a72fb3ae9a48a446b51e76c4ec1cd47f9f6a Mon Sep 17 00:00:00 2001 From: Irene Blanco Date: Wed, 20 Nov 2024 11:34:23 +0100 Subject: [PATCH 11/21] Update x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts Co-authored-by: Carlos Crespo --- .../observability/apm/settings/custom_link/custom_link.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts index 3f4d99976e6ea..bd46edc555ac4 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts @@ -35,7 +35,7 @@ export default function customLinksTests({ getService }: DeploymentAgnosticFtrPr }); after(async () => { - await esArchiver.unload(ARCHIVER_ROUTES['8.0.0']); + await esArchiver.unload(ARCHIVER_ROUTES[archiveName]); }); it('should fail if the user does not have write access', async () => { From 41e3a23fc54c682b7177ae0a0b76e4c6cca3051d Mon Sep 17 00:00:00 2001 From: Irene Blanco Date: Wed, 20 Nov 2024 11:35:57 +0100 Subject: [PATCH 12/21] Update x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts Co-authored-by: Carlos Crespo --- .../observability/apm/settings/apm_indices/apm_indices.spec.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts index 9c94afd69abf4..6bdcc8049e9f4 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts @@ -33,9 +33,6 @@ export default function apmIndicesTests({ getService }: DeploymentAgnosticFtrPro beforeEach(async () => { await deleteSavedObject(); }); - afterEach(async () => { - await deleteSavedObject(); - }); it('returns APM Indices', async () => { const response = await apmApiClient.readUser({ From 2cb8be0c99ba46a49602883cb8dcde369176bd5c Mon Sep 17 00:00:00 2001 From: iblancof Date: Wed, 20 Nov 2024 11:42:08 +0100 Subject: [PATCH 13/21] Remove migrated test --- .../settings/anomaly_detection/basic.spec.ts | 68 ------------------- 1 file changed, 68 deletions(-) delete mode 100644 x-pack/test/apm_api_integration/tests/settings/anomaly_detection/basic.spec.ts diff --git a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/basic.spec.ts b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/basic.spec.ts deleted file mode 100644 index 86290fc35f124..0000000000000 --- a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/basic.spec.ts +++ /dev/null @@ -1,68 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../common/ftr_provider_context'; -import { ApmApiError } from '../../../common/apm_api_supertest'; - -export default function apiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - - type SupertestAsUser = - | typeof apmApiClient.readUser - | typeof apmApiClient.writeUser - | typeof apmApiClient.noAccessUser; - - function getJobs(user: SupertestAsUser) { - return user({ endpoint: `GET /internal/apm/settings/anomaly-detection/jobs` }); - } - - function createJobs(user: SupertestAsUser, environments: string[]) { - return user({ - endpoint: 'POST /internal/apm/settings/anomaly-detection/jobs', - params: { - body: { environments }, - }, - }); - } - - async function expectForbidden(user: SupertestAsUser) { - try { - await getJobs(user); - expect(true).to.be(false); - } catch (e) { - const err = e as ApmApiError; - expect(err.res.status).to.be(403); - } - - try { - await createJobs(user, ['production', 'staging']); - expect(true).to.be(false); - } catch (e) { - const err = e as ApmApiError; - expect(err.res.status).to.be(403); - } - } - - registry.when('ML jobs return a 403 for', { config: 'basic', archives: [] }, () => { - describe('basic', function () { - this.tags('skipFIPS'); - it('user without access', async () => { - await expectForbidden(apmApiClient.noAccessUser); - }); - - it('read user', async () => { - await expectForbidden(apmApiClient.readUser); - }); - - it('write user', async () => { - await expectForbidden(apmApiClient.writeUser); - }); - }); - }); -} From f2d8c395ee25d653f5fcae6e9641adb4577dc7f9 Mon Sep 17 00:00:00 2001 From: iblancof Date: Wed, 20 Nov 2024 11:45:54 +0100 Subject: [PATCH 14/21] Remove FIPS skip --- .../observability/apm/settings/anomaly_detection/basic.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.spec.ts index 0aab44c6e27c3..195e4ff5e7bd2 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/anomaly_detection/basic.spec.ts @@ -45,8 +45,6 @@ export default function apiTest({ getService }: DeploymentAgnosticFtrProviderCon describe('ML jobs return a 403 for', () => { describe('basic', function () { - this.tags('skipFIPS'); - it('read user', async () => { await expectForbidden(apmApiClient.readUser); }); From de4cb585a7db9e51a045fdefa25f5e10feb8bd67 Mon Sep 17 00:00:00 2001 From: Carlos Crespo Date: Wed, 20 Nov 2024 12:06:27 +0100 Subject: [PATCH 15/21] Better support for public api calls --- .../apm/services/derived_annotations.spec.ts | 2 +- .../deployment_agnostic/services/apm_api.ts | 90 ++++++++++++------- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/derived_annotations.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/derived_annotations.spec.ts index 3af97dea84c72..272ddb876573f 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/derived_annotations.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/derived_annotations.spec.ts @@ -118,7 +118,7 @@ export default function annotationApiTests({ getService }: DeploymentAgnosticFtr }); response = ( - await apmApiClient.readUser({ + await apmApiClient.publicApi({ endpoint: 'GET /api/apm/services/{serviceName}/annotation/search 2023-10-31', params: { path: { diff --git a/x-pack/test/api_integration/deployment_agnostic/services/apm_api.ts b/x-pack/test/api_integration/deployment_agnostic/services/apm_api.ts index c3f43b57902e8..ed2c5ba7ccf1f 100644 --- a/x-pack/test/api_integration/deployment_agnostic/services/apm_api.ts +++ b/x-pack/test/api_integration/deployment_agnostic/services/apm_api.ts @@ -16,16 +16,7 @@ import { formatRequest } from '@kbn/server-route-repository'; import { RoleCredentials } from '@kbn/ftr-common-functional-services'; import type { DeploymentAgnosticFtrProviderContext } from '../ftr_provider_context'; -const INTERNAL_API_REGEX = /^\S+\s(\/)?internal\/[^\s]*$/; - -type InternalApi = `${string} /internal/${string}`; -interface ExternalEndpointParams { - roleAuthc: RoleCredentials; -} - -type Options = (TEndpoint extends InternalApi - ? {} - : ExternalEndpointParams) & { +type Options = { type?: 'form-data'; endpoint: TEndpoint; spaceId?: string; @@ -33,33 +24,28 @@ type Options = (TEndpoint extends InternalApi params?: { query?: { _inspect?: boolean } }; }; -function isPublicApi( - options: Options -): options is Options & ExternalEndpointParams { - return !INTERNAL_API_REGEX.test(options.endpoint); -} +type InternalEndpoint = T extends `${string} /internal/${string}` + ? T + : never; + +type PublicEndpoint = T extends `${string} /api/${string}` ? T : never; -function createApmApiClient({ getService }: DeploymentAgnosticFtrProviderContext, role: string) { +function createApmApiClient({ getService }: DeploymentAgnosticFtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); const samlAuth = getService('samlAuth'); const logger = getService('log'); - return async ( - options: Options - ): Promise> => { + async function makeApiRequest({ + options, + headers, + }: { + options: Options; + headers: Record; + }): Promise> { const { endpoint, type } = options; const params = 'params' in options ? (options.params as Record) : {}; - const credentials = isPublicApi(options) - ? options.roleAuthc.apiKeyHeader - : await samlAuth.getM2MApiCookieCredentialsWithRoleScope(role); - - const headers: Record = { - ...samlAuth.getInternalRequestHeader(), - ...credentials, - }; - const { method, pathname, version } = formatRequest(endpoint, params.path); const pathnameWithSpaceId = options.spaceId ? `/s/${options.spaceId}${pathname}` : pathname; const url = format({ pathname: pathnameWithSpaceId, query: params?.query }); @@ -71,6 +57,7 @@ function createApmApiClient({ getService }: DeploymentAgnosticFtrProviderContext } let res: request.Response; + if (type === 'form-data') { const fields: Array<[string, any]> = Object.entries(params.body); const formDataRequest = supertestWithoutAuth[method](url) @@ -94,6 +81,45 @@ function createApmApiClient({ getService }: DeploymentAgnosticFtrProviderContext } return res; + } + + function makeInternalApiRequest(role: string) { + return async >( + options: Options + ): Promise> => { + const headers: Record = { + ...samlAuth.getInternalRequestHeader(), + ...(await samlAuth.getM2MApiCookieCredentialsWithRoleScope(role)), + }; + + return makeApiRequest({ + options, + headers, + }); + }; + } + + function makePublicApiRequest() { + return async >( + options: Options & { + roleAuthc: RoleCredentials; + } + ): Promise> => { + const headers: Record = { + ...samlAuth.getInternalRequestHeader(), + ...options.roleAuthc.apiKeyHeader, + }; + + return makeApiRequest({ + options, + headers, + }); + }; + } + + return { + makeInternalApiRequest, + makePublicApiRequest, }; } @@ -129,10 +155,12 @@ export interface SupertestReturnType { } export function ApmApiProvider(context: DeploymentAgnosticFtrProviderContext) { + const apmClient = createApmApiClient(context); return { - readUser: createApmApiClient(context, 'viewer'), - adminUser: createApmApiClient(context, 'admin'), - writeUser: createApmApiClient(context, 'editor'), + readUser: apmClient.makeInternalApiRequest('viewer'), + adminUser: apmClient.makeInternalApiRequest('admin'), + writeUser: apmClient.makeInternalApiRequest('editor'), + publicApi: apmClient.makePublicApiRequest(), }; } From d50e6bfc6751500f04cb09e4421640112c2bd911 Mon Sep 17 00:00:00 2001 From: iblancof Date: Wed, 20 Nov 2024 14:49:49 +0100 Subject: [PATCH 16/21] Use publicApi --- .../apm/settings/agent_keys/agent_keys.spec.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts index db61ffeb15d8d..925820c0e7c13 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts @@ -19,17 +19,13 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon const allApplicationPrivileges = [PrivilegeType.AGENT_CONFIG, PrivilegeType.EVENT]; const clusterPrivileges = [ClusterPrivilegeType.MANAGE_OWN_API_KEY]; - async function createAgentKey( - apiClient: (typeof apmApiClient)[keyof typeof apmApiClient], - roleAuthc: RoleCredentials, - privileges = allApplicationPrivileges - ) { - return await apiClient({ + async function createAgentKey(roleAuthc: RoleCredentials) { + return await apmApiClient.publicApi({ endpoint: 'POST /api/apm/agent_keys 2023-10-31', params: { body: { name: agentKeyName, - privileges, + privileges: allApplicationPrivileges, }, }, roleAuthc, @@ -62,9 +58,7 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon describe('When the user does not have the required cluster privileges', () => { it('should return an error when creating an agent key', async () => { - const error = await expectToReject(() => - createAgentKey(apmApiClient.writeUser, roleAuthc) - ); + const error = await expectToReject(() => createAgentKey(roleAuthc)); expect(error.res.status).to.be(403); expect(error.res.body.message).contain('is missing the following requested privilege'); expect(error.res.body.attributes).to.eql({ From 294c068aff6250ea0a4d34f16068d97c758b9347 Mon Sep 17 00:00:00 2001 From: iblancof Date: Wed, 20 Nov 2024 14:53:49 +0100 Subject: [PATCH 17/21] Reorder apmApiIntegrationTests --- .../deployment_agnostic/apis/observability/apm/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts index 18200d3075eaa..5d94e39ea6547 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts @@ -33,12 +33,12 @@ export default function apmApiIntegrationTests({ loadTestFile(require.resolve('./service_groups')); loadTestFile(require.resolve('./service_maps')); loadTestFile(require.resolve('./service_nodes')); + loadTestFile(require.resolve('./service_overview')); loadTestFile(require.resolve('./services')); loadTestFile(require.resolve('./settings')); loadTestFile(require.resolve('./span_links')); loadTestFile(require.resolve('./suggestions')); loadTestFile(require.resolve('./throughput')); loadTestFile(require.resolve('./time_range_metadata')); - loadTestFile(require.resolve('./service_overview')); }); } From e2ed6f535948365f5741bebb2e26ffc47d0622e5 Mon Sep 17 00:00:00 2001 From: iblancof Date: Wed, 20 Nov 2024 17:28:42 +0100 Subject: [PATCH 18/21] Remove duplicated test file import --- .../deployment_agnostic/apis/observability/apm/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts index 17b1e6bd2b2cc..bc209186c869c 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts @@ -41,6 +41,5 @@ export default function apmApiIntegrationTests({ loadTestFile(require.resolve('./throughput')); loadTestFile(require.resolve('./time_range_metadata')); loadTestFile(require.resolve('./transactions')); - loadTestFile(require.resolve('./service_overview')); }); } From 4f8ad0cb7244e3bfaa1a749dae26f5ec24d62b69 Mon Sep 17 00:00:00 2001 From: iblancof Date: Thu, 21 Nov 2024 10:43:18 +0100 Subject: [PATCH 19/21] Remove test case that was not deployment agnostic --- .../apm/settings/custom_link/custom_link.spec.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts index bd46edc555ac4..9924814591110 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/custom_link/custom_link.spec.ts @@ -135,19 +135,6 @@ export default function customLinksTests({ getService }: DeploymentAgnosticFtrPr expect(newStatus).to.equal(200); expect(newBody.customLinks.length).to.be(0); }); - - it('fetches a transaction sample', async () => { - const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/settings/custom_links/transaction', - params: { - query: { - 'service.name': 'opbeans-java', - }, - }, - }); - expect(response.status).to.be(200); - expect(response.body.service.name).to.eql('opbeans-java'); - }); }); function searchCustomLinks(filters?: any) { From f1e40f13fac1c53aef294aeddc2ee855d6bd31b9 Mon Sep 17 00:00:00 2001 From: iblancof Date: Thu, 21 Nov 2024 10:43:40 +0100 Subject: [PATCH 20/21] Remove duplicated writeUser test --- .../settings/custom_link/custom_link.spec.ts | 120 +++++++++--------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/x-pack/test/apm_api_integration/tests/settings/custom_link/custom_link.spec.ts b/x-pack/test/apm_api_integration/tests/settings/custom_link/custom_link.spec.ts index 490a2fc768688..e6b565cde2b34 100644 --- a/x-pack/test/apm_api_integration/tests/settings/custom_link/custom_link.spec.ts +++ b/x-pack/test/apm_api_integration/tests/settings/custom_link/custom_link.spec.ts @@ -91,79 +91,77 @@ export default function customLinksTests({ getService }: FtrProviderContext) { }); }); - (['writeUser', 'apmReadPrivilegesWithWriteSettingsUser'] as ApmApiClientKey[]).forEach( - (user) => { - it(`creates a custom link as ${user}`, async () => { - const customLink = { - url: 'https://elastic.co', - label: 'with filters', - filters: [ - { key: 'service.name', value: 'baz' }, - { key: 'transaction.type', value: 'qux' }, - ], - } as CustomLink; + (['apmReadPrivilegesWithWriteSettingsUser'] as ApmApiClientKey[]).forEach((user) => { + it(`creates a custom link as ${user}`, async () => { + const customLink = { + url: 'https://elastic.co', + label: 'with filters', + filters: [ + { key: 'service.name', value: 'baz' }, + { key: 'transaction.type', value: 'qux' }, + ], + } as CustomLink; + + await createCustomLink(customLink, { user }); + }); - await createCustomLink(customLink, { user }); + it(`updates a custom link as ${user}`, async () => { + const { status, body } = await searchCustomLinks({ + 'service.name': 'baz', + 'transaction.type': 'qux', }); + expect(status).to.equal(200); - it(`updates a custom link as ${user}`, async () => { - const { status, body } = await searchCustomLinks({ - 'service.name': 'baz', - 'transaction.type': 'qux', - }); - expect(status).to.equal(200); - - const id = body.customLinks[0].id!; - await updateCustomLink( - id, - { - label: 'foo', - url: 'https://elastic.co?service.name={{service.name}}', - filters: [ - { key: 'service.name', value: 'quz' }, - { key: 'transaction.name', value: 'bar' }, - ], - }, - { user } - ); - - const { status: newStatus, body: newBody } = await searchCustomLinks({ - 'service.name': 'quz', - 'transaction.name': 'bar', - }); - - const { label, url, filters } = newBody.customLinks[0]; - expect(newStatus).to.equal(200); - expect({ label, url, filters }).to.eql({ + const id = body.customLinks[0].id!; + await updateCustomLink( + id, + { label: 'foo', url: 'https://elastic.co?service.name={{service.name}}', filters: [ { key: 'service.name', value: 'quz' }, { key: 'transaction.name', value: 'bar' }, ], - }); + }, + { user } + ); + + const { status: newStatus, body: newBody } = await searchCustomLinks({ + 'service.name': 'quz', + 'transaction.name': 'bar', }); - it(`deletes a custom link as ${user}`, async () => { - const { status, body } = await searchCustomLinks({ - 'service.name': 'quz', - 'transaction.name': 'bar', - }); - expect(status).to.equal(200); - expect(body.customLinks.length).to.be(1); - - const id = body.customLinks[0].id!; - await deleteCustomLink(id, { user }); - - const { status: newStatus, body: newBody } = await searchCustomLinks({ - 'service.name': 'quz', - 'transaction.name': 'bar', - }); - expect(newStatus).to.equal(200); - expect(newBody.customLinks.length).to.be(0); + const { label, url, filters } = newBody.customLinks[0]; + expect(newStatus).to.equal(200); + expect({ label, url, filters }).to.eql({ + label: 'foo', + url: 'https://elastic.co?service.name={{service.name}}', + filters: [ + { key: 'service.name', value: 'quz' }, + { key: 'transaction.name', value: 'bar' }, + ], }); - } - ); + }); + + it(`deletes a custom link as ${user}`, async () => { + const { status, body } = await searchCustomLinks({ + 'service.name': 'quz', + 'transaction.name': 'bar', + }); + expect(status).to.equal(200); + expect(body.customLinks.length).to.be(1); + + const id = body.customLinks[0].id!; + await deleteCustomLink(id, { user }); + + const { status: newStatus, body: newBody } = await searchCustomLinks({ + 'service.name': 'quz', + 'transaction.name': 'bar', + }); + expect(newStatus).to.equal(200); + expect(newBody.customLinks.length).to.be(0); + }); + }); it('fetches a transaction sample', async () => { const response = await apmApiClient.readUser({ From 269f33f170274ee7d74cd0dca78f4b6d5676250e Mon Sep 17 00:00:00 2001 From: iblancof Date: Thu, 21 Nov 2024 18:09:27 +0100 Subject: [PATCH 21/21] Add deleteSavedObject again afterEach --- .../apm/settings/apm_indices/apm_indices.spec.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts index 6bdcc8049e9f4..1fe51b69fccb4 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/apm_indices/apm_indices.spec.ts @@ -34,6 +34,10 @@ export default function apmIndicesTests({ getService }: DeploymentAgnosticFtrPro await deleteSavedObject(); }); + afterEach(async () => { + await deleteSavedObject(); + }); + it('returns APM Indices', async () => { const response = await apmApiClient.readUser({ endpoint: 'GET /internal/apm/settings/apm-indices',