diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/create_logs_onboarding_flow.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/create_logs_onboarding_flow.ts new file mode 100644 index 0000000000000..1a4a130bb4d38 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/create_logs_onboarding_flow.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE } from '@kbn/observability-onboarding-plugin/server/saved_objects/observability_onboarding_status'; +import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { SupertestWithRoleScopeType } from '../../../services'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const roleScopedSupertest = getService('roleScopedSupertest'); + let viewerClient: SupertestWithRoleScopeType; + let adminClient: SupertestWithRoleScopeType; + + describe('Creating onboarding logs flow', () => { + before(async () => { + viewerClient = await roleScopedSupertest.getSupertestWithRoleScope('viewer', { + withInternalHeaders: true, + useCookieHeader: true, + }); + adminClient = await roleScopedSupertest.getSupertestWithRoleScope('admin', { + withInternalHeaders: true, + useCookieHeader: true, + }); + }); + + it('fails with a 500 error when missing privileges', async () => { + const response = await viewerClient + .post('/internal/observability_onboarding/logs/flow') + .send({ + type: 'logFiles', + name: 'name', + state: {}, + }); + + expect(response.statusCode).to.be(500); + expect(response.body.message).to.contain('unauthorized'); + }); + + it('returns a flow id and apiKey encoded', async () => { + const state = { + datasetName: 'my-dataset', + serviceName: 'my-service', + namespace: 'my-namespace', + logFilePaths: ['my-service-logs.log'], + }; + + const response = await adminClient.post('/internal/observability_onboarding/logs/flow').send({ + type: 'logFiles', + name: 'name', + state, + }); + + expect(response.statusCode).to.be(200); + expect(response.body.apiKeyEncoded).to.not.empty(); + expect(response.body.onboardingId).to.not.empty(); + }); + + it('saves the expected state for logFiles', async () => { + const state = { + datasetName: 'my-dataset', + serviceName: 'my-service', + namespace: 'my-namespace', + logFilePaths: ['my-service-logs.log'], + }; + + const response = await adminClient.post('/internal/observability_onboarding/logs/flow').send({ + type: 'logFiles', + name: 'name', + state, + }); + + const savedState = await kibanaServer.savedObjects.get({ + type: OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE, + id: response.body.onboardingId, + }); + + expect(savedState.attributes).to.be.eql({ type: 'logFiles', state, progress: {} }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/get_elastic_agent_config.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/get_elastic_agent_config.ts new file mode 100644 index 0000000000000..734bd45f3fa53 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/get_elastic_agent_config.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 expect from '@kbn/expect'; +import { load } from 'js-yaml'; +import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { SupertestWithRoleScopeType } from '../../../services'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const roleScopedSupertest = getService('roleScopedSupertest'); + let adminClient: SupertestWithRoleScopeType; + + describe('Generate Elastic Agent configuration', () => { + before(async () => { + adminClient = await roleScopedSupertest.getSupertestWithRoleScope('admin', { + withInternalHeaders: true, + useCookieHeader: true, + }); + }); + + it(`should return input properties empty when onboardingId doesn't exists`, async () => { + const response = await adminClient + .get('/internal/observability_onboarding/elastic_agent/config') + .query({ onboardingId: 'my-onboarding-id' }); + + expect(response.status).to.be(200); + + const ymlConfig = load(response.text); + expect(ymlConfig.inputs[0].data_stream.namespace).to.be(''); + expect(ymlConfig.inputs[0].streams[0].data_stream.dataset).to.be(''); + expect(ymlConfig.inputs[0].streams[0].paths).to.be.empty(); + }); + + it('should return input properties configured when onboardingId exists', async () => { + const datasetName = 'api-tests'; + const namespace = 'default'; + const logFilepath = '/my-logs.log'; + const serviceName = 'my-service'; + + const createFlowResponse = await adminClient + .post('/internal/observability_onboarding/logs/flow') + .send({ + type: 'logFiles', + name: 'name', + state: { + datasetName, + namespace, + logFilePaths: [logFilepath], + serviceName, + }, + }); + + const onboardingId = createFlowResponse.body.onboardingId; + + const response = await adminClient + .get('/internal/observability_onboarding/elastic_agent/config') + .query({ onboardingId }); + + expect(response.status).to.be(200); + + const ymlConfig = load(response.text); + expect(ymlConfig.inputs[0].data_stream.namespace).to.be(namespace); + expect(ymlConfig.inputs[0].streams[0].data_stream.dataset).to.be(datasetName); + expect(ymlConfig.inputs[0].streams[0].paths).to.be.eql([logFilepath]); + expect(ymlConfig.inputs[0].streams[0].processors[0].add_fields.fields.name).to.be.eql( + serviceName + ); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/get_privileges.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/get_privileges.ts new file mode 100644 index 0000000000000..d6bcefb8cf438 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/get_privileges.ts @@ -0,0 +1,44 @@ +/* + * 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 { type DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { type SupertestWithRoleScopeType } from '../../../services'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const roleScopedSupertest = getService('roleScopedSupertest'); + + let viewerClient: SupertestWithRoleScopeType; + let adminClient: SupertestWithRoleScopeType; + + describe('Api Key privileges check', () => { + before(async () => { + viewerClient = await roleScopedSupertest.getSupertestWithRoleScope('viewer', { + withInternalHeaders: true, + }); + adminClient = await roleScopedSupertest.getSupertestWithRoleScope('admin', { + withInternalHeaders: true, + }); + }); + + it('returns false when user has reader privileges', async () => { + const response = await viewerClient.get( + `/internal/observability_onboarding/logs/setup/privileges` + ); + + expect(response.body.hasPrivileges).not.ok(); + }); + + it('returns true when user has admin privileges', async () => { + const response = await adminClient.get( + `/internal/observability_onboarding/logs/setup/privileges` + ); + + expect(response.body.hasPrivileges).ok(); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/get_progress.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/get_progress.ts new file mode 100644 index 0000000000000..c3b17e8a4e3aa --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/get_progress.ts @@ -0,0 +1,175 @@ +/* + * 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 { type LogsSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import { log, timerange } from '@kbn/apm-synthtrace-client'; +import { type DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { type SupertestWithRoleScopeType } from '../../../services'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const roleScopedSupertest = getService('roleScopedSupertest'); + const synthtrace = getService('synthtrace'); + + let synthtraceLogsEsClient: LogsSynthtraceEsClient; + let adminClient: SupertestWithRoleScopeType; + + describe('Get progress', () => { + const datasetName = 'api-tests'; + const namespace = 'default'; + let onboardingId: string; + + before(async () => { + synthtraceLogsEsClient = await synthtrace.createLogsSynthtraceEsClient(); + adminClient = await roleScopedSupertest.getSupertestWithRoleScope('admin', { + withInternalHeaders: true, + useCookieHeader: true, + }); + + const createFlowResponse = await adminClient + .post('/internal/observability_onboarding/logs/flow') + .send({ + type: 'logFiles', + name: 'name', + state: { + datasetName, + namespace, + logFilePaths: ['my-service.log'], + }, + }); + + onboardingId = createFlowResponse.body.onboardingId; + }); + + it(`fails with a 404 error when onboardingId doesn't exists`, async () => { + const response = await adminClient.get( + `/internal/observability_onboarding/flow/test-onboarding-id/progress` + ); + + expect(response.status).to.be(404); + expect(response.body.message).to.contain('onboarding session not found'); + }); + + it('should skip log verification and return log-ingest as incomplete when ea-status is not complete', async () => { + const response = await adminClient.get( + `/internal/observability_onboarding/flow/${onboardingId}/progress` + ); + + expect(response.status).to.be(200); + + const logsIngestProgress = response.body.progress['logs-ingest']; + expect(logsIngestProgress).to.have.property('status', 'incomplete'); + }); + + describe('when ea-status is complete', () => { + describe('should not skip logs verification', () => { + const agentId = 'my-agent-id'; + + before(async () => { + await adminClient + .post(`/internal/observability_onboarding/flow/${onboardingId}/step/ea-status`) + .send({ + status: 'complete', + payload: { + agentId, + }, + }); + }); + + describe('when no logs have been ingested', () => { + it('should return log-ingest as loading', async () => { + const response = await adminClient.get( + `/internal/observability_onboarding/flow/${onboardingId}/progress` + ); + + expect(response.status).to.be(200); + + const logsIngestProgress = response.body.progress['logs-ingest']; + expect(logsIngestProgress).to.have.property('status', 'loading'); + }); + }); + + describe('when logs have been ingested', () => { + describe('with a different agentId', () => { + describe('and onboarding type is logFiles', () => { + before(async () => { + await synthtraceLogsEsClient.index([ + timerange('2023-11-20T10:00:00.000Z', '2023-11-20T10:01:00.000Z') + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a log message') + .timestamp(timestamp) + .dataset(datasetName) + .namespace(namespace) + .service('my-service') + .defaults({ + 'agent.id': 'another-agent-id', + 'log.file.path': '/my-service.log', + }) + ), + ]); + }); + + it('should return log-ingest as incomplete', async () => { + const response = await adminClient.get( + `/internal/observability_onboarding/flow/${onboardingId}/progress` + ); + expect(response.status).to.be(200); + const logsIngestProgress = response.body.progress['logs-ingest']; + expect(logsIngestProgress).to.have.property('status', 'loading'); + }); + + after(async () => { + await synthtraceLogsEsClient.clean(); + }); + }); + }); + + describe('with the expected agentId', () => { + describe('and onboarding type is logFiles', () => { + before(async () => { + await synthtraceLogsEsClient.index([ + timerange('2023-11-20T10:00:00.000Z', '2023-11-20T10:01:00.000Z') + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a log message') + .timestamp(timestamp) + .dataset(datasetName) + .namespace(namespace) + .service('my-service') + .defaults({ + 'agent.id': agentId, + 'log.file.path': '/my-service.log', + }) + ), + ]); + }); + it('should return log-ingest as complete', async () => { + const response = await adminClient.get( + `/internal/observability_onboarding/flow/${onboardingId}/progress` + ); + expect(response.status).to.be(200); + const logsIngestProgress = response.body.progress['logs-ingest']; + expect(logsIngestProgress).to.have.property('status', 'complete'); + }); + + after(async () => { + await synthtraceLogsEsClient.clean(); + }); + }); + }); + }); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/index.ts new file mode 100644 index 0000000000000..580af4d9ee685 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/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('Onboarding', () => { + loadTestFile(require.resolve('./create_logs_onboarding_flow')); + loadTestFile(require.resolve('./get_elastic_agent_config')); + loadTestFile(require.resolve('./get_progress')); + loadTestFile(require.resolve('./update_progress')); + loadTestFile(require.resolve('./get_privileges')); + }); +} diff --git a/x-pack/test/observability_onboarding_api_integration/tests/logs/update_step_progress.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/update_progress.ts similarity index 50% rename from x-pack/test/observability_onboarding_api_integration/tests/logs/update_step_progress.spec.ts rename to x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/update_progress.ts index 7c53792769e5e..383782cffd696 100644 --- a/x-pack/test/observability_onboarding_api_integration/tests/logs/update_step_progress.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/onboarding/update_progress.ts @@ -7,55 +7,40 @@ import expect from '@kbn/expect'; import { OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE } from '@kbn/observability-onboarding-plugin/server/saved_objects/observability_onboarding_status'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { ObservabilityOnboardingApiError } from '../../common/observability_onboarding_api_supertest'; -import { expectToReject } from '../../common/utils/expect_to_reject'; +import { type DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { type SupertestWithRoleScopeType } from '../../../services'; -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const kibanaServer = getService('kibanaServer'); - const observabilityOnboardingApiClient = getService('observabilityOnboardingApiClient'); - - async function callApi({ - id, - name, - status, - message, - }: { - id: string; - name: string; - status: string; - message?: string; - }) { - return await observabilityOnboardingApiClient.logMonitoringUser({ - endpoint: 'POST /internal/observability_onboarding/flow/{id}/step/{name}', - params: { - path: { - id, - name, - }, - body: { - status, - message, - }, - }, + const roleScopedSupertest = getService('roleScopedSupertest'); + let adminClient: SupertestWithRoleScopeType; + let adminClientWithAPIKey: SupertestWithRoleScopeType; + + describe('Update step progress', () => { + before(async () => { + adminClient = await roleScopedSupertest.getSupertestWithRoleScope('admin', { + withInternalHeaders: true, + useCookieHeader: true, + }); + adminClientWithAPIKey = await roleScopedSupertest.getSupertestWithRoleScope('admin', { + withInternalHeaders: true, + }); + }); + + after(async () => { + await adminClientWithAPIKey.destroy(); }); - } - registry.when('Update step progress', { config: 'basic' }, () => { describe("when onboardingId doesn't exists", () => { it('fails with a 404 error', async () => { - const err = await expectToReject( - async () => - await callApi({ - id: 'my-onboarding-id', - name: 'ea-download', - status: 'complete', - }) - ); - - expect(err.res.status).to.be(404); - expect(err.res.body.message).to.contain('onboarding session not found'); + const response = await adminClient + .post(`/internal/observability_onboarding/flow/test-onboarding-id/step/ea-download`) + .send({ + status: 'complete', + }); + + expect(response.status).to.be(404); + expect(response.body.message).to.contain('onboarding session not found'); }); }); @@ -63,23 +48,21 @@ export default function ApiTest({ getService }: FtrProviderContext) { let onboardingId: string; beforeEach(async () => { - const req = await observabilityOnboardingApiClient.logMonitoringUser({ - endpoint: 'POST /internal/observability_onboarding/logs/flow', - params: { - body: { - type: 'logFiles', - name: 'name', - state: { - datasetName: 'my-dataset', - serviceName: 'my-service', - namespace: 'my-namespace', - logFilePaths: ['my-service.log'], - }, + const createFlowResponse = await adminClient + .post('/internal/observability_onboarding/logs/flow') + .send({ + type: 'logFiles', + name: 'name', + state: { + datasetName: 'my-dataset', + serviceName: 'my-service', + namespace: 'my-namespace', + logFilePaths: ['my-service.log'], }, - }, - }); + }); + + onboardingId = createFlowResponse.body.onboardingId; - onboardingId = req.body.onboardingId; const savedState = await kibanaServer.savedObjects.get({ type: OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE, id: onboardingId, @@ -88,18 +71,26 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(savedState.attributes.progress).eql({}); }); + afterEach(async () => { + await kibanaServer.savedObjects.delete({ + type: OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE, + id: onboardingId, + }); + }); + it('updates step status', async () => { const step = { name: 'ea-download', status: 'complete', }; - const request = await callApi({ - id: onboardingId, - ...step, - }); + const response = await adminClientWithAPIKey + .post(`/internal/observability_onboarding/flow/${onboardingId}/step/${step.name}`) + .send({ + status: step.status, + }); - expect(request.status).to.be(200); + expect(response.status).to.be(200); const savedState = await kibanaServer.savedObjects.get({ type: OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE, @@ -116,12 +107,14 @@ export default function ApiTest({ getService }: FtrProviderContext) { status: 'danger', message: 'Download failed', }; - const request = await callApi({ - id: onboardingId, - ...step, - }); + const response = await adminClientWithAPIKey + .post(`/internal/observability_onboarding/flow/${onboardingId}/step/${step.name}`) + .send({ + status: step.status, + message: step.message, + }); - expect(request.status).to.be(200); + expect(response.status).to.be(200); const savedState = await kibanaServer.savedObjects.get({ type: OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE, @@ -132,13 +125,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(stepProgress).to.have.property('status', step.status); expect(stepProgress).to.have.property('message', step.message); }); - - afterEach(async () => { - await kibanaServer.savedObjects.delete({ - type: OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE, - id: onboardingId, - }); - }); }); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts b/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts index bf722be7b391e..8705e7553ed60 100644 --- a/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts @@ -23,5 +23,6 @@ export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) loadTestFile(require.resolve('../../apis/observability/synthetics')); loadTestFile(require.resolve('../../apis/observability/ai_assistant')); loadTestFile(require.resolve('../../apis/observability/streams')); + loadTestFile(require.resolve('../../apis/observability/onboarding')); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts b/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts index 3ac428860a588..93ad9a193b26b 100644 --- a/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts @@ -17,5 +17,6 @@ export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) loadTestFile(require.resolve('../../apis/observability/infra')); loadTestFile(require.resolve('../../apis/observability/ai_assistant')); loadTestFile(require.resolve('../../apis/observability/streams')); + loadTestFile(require.resolve('../../apis/observability/onboarding')); }); } diff --git a/x-pack/test/observability_onboarding_api_integration/tests/elastic_agent/config.spec.ts b/x-pack/test/observability_onboarding_api_integration/tests/elastic_agent/config.spec.ts deleted file mode 100644 index 6dcbaf629a374..0000000000000 --- a/x-pack/test/observability_onboarding_api_integration/tests/elastic_agent/config.spec.ts +++ /dev/null @@ -1,89 +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 { load } from 'js-yaml'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const observabilityOnboardingApiClient = getService('observabilityOnboardingApiClient'); - - async function callApi({ onboardingId }: { onboardingId: string }) { - return await observabilityOnboardingApiClient.logMonitoringUser({ - endpoint: 'GET /internal/observability_onboarding/elastic_agent/config', - params: { - query: { - onboardingId, - }, - }, - }); - } - - registry.when('Generate elastic_agent yml', { config: 'basic' }, () => { - let onboardingId: string; - const datasetName = 'api-tests'; - const namespace = 'default'; - const logFilepath = '/my-logs.log'; - const serviceName = 'my-service'; - - describe("when onboardingId doesn't exists", () => { - it('should return input properties empty', async () => { - const req = await callApi({ - onboardingId: 'my-onboarding-id', - }); - - expect(req.status).to.be(200); - - const ymlConfig = load(req.text); - expect(ymlConfig.inputs[0].data_stream.namespace).to.be(''); - expect(ymlConfig.inputs[0].streams[0].data_stream.dataset).to.be(''); - expect(ymlConfig.inputs[0].streams[0].paths).to.be.empty(); - }); - }); - - describe('when onboardingId exists', () => { - describe('and onboarding type is logFiles', () => { - before(async () => { - const req = await observabilityOnboardingApiClient.logMonitoringUser({ - endpoint: 'POST /internal/observability_onboarding/logs/flow', - params: { - body: { - type: 'logFiles', - name: 'name', - state: { - datasetName, - namespace, - logFilePaths: [logFilepath], - serviceName, - }, - }, - }, - }); - - onboardingId = req.body.onboardingId; - }); - - it('should return input properties configured', async () => { - const req = await callApi({ - onboardingId, - }); - - expect(req.status).to.be(200); - - const ymlConfig = load(req.text); - expect(ymlConfig.inputs[0].data_stream.namespace).to.be(namespace); - expect(ymlConfig.inputs[0].streams[0].data_stream.dataset).to.be(datasetName); - expect(ymlConfig.inputs[0].streams[0].paths).to.be.eql([logFilepath]); - expect(ymlConfig.inputs[0].streams[0].processors[0].add_fields.fields.name).to.be.eql( - serviceName - ); - }); - }); - }); - }); -} diff --git a/x-pack/test/observability_onboarding_api_integration/tests/flow/progress/progress.spec.ts b/x-pack/test/observability_onboarding_api_integration/tests/flow/progress/progress.spec.ts index bc3a5873d1bf9..ef02d8680919e 100644 --- a/x-pack/test/observability_onboarding_api_integration/tests/flow/progress/progress.spec.ts +++ b/x-pack/test/observability_onboarding_api_integration/tests/flow/progress/progress.spec.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { log, timerange } from '@kbn/apm-synthtrace-client'; import expect from '@kbn/expect'; import { ObservabilityOnboardingApiClientKey } from '../../../common/config'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; @@ -15,7 +14,6 @@ import { expectToReject } from '../../../common/utils/expect_to_reject'; export default function ApiTest({ getService }: FtrProviderContext) { const registry = getService('registry'); const observabilityOnboardingApiClient = getService('observabilityOnboardingApiClient'); - const synthtrace = getService('logSynthtraceEsClient'); async function callApi({ onboardingId, @@ -72,155 +70,5 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(err.res.body.message).to.contain('onboarding session not found'); }); }); - - describe('when required privileges are set', () => { - describe("when onboardingId doesn't exists", () => { - it('fails with a 404 error', async () => { - const err = await expectToReject( - async () => - await callApi({ - onboardingId: 'my-onboarding-id', - }) - ); - - expect(err.res.status).to.be(404); - expect(err.res.body.message).to.contain('onboarding session not found'); - }); - }); - - describe('when onboardingId exists', () => { - describe('when ea-status is not complete', () => { - it('should skip log verification and return log-ingest as incomplete', async () => { - const request = await callApi({ - onboardingId, - }); - - expect(request.status).to.be(200); - - const logsIngestProgress = request.body.progress['logs-ingest']; - expect(logsIngestProgress).to.have.property('status', 'incomplete'); - }); - }); - - describe('when ea-status is complete', () => { - describe('should not skip logs verification', () => { - const agentId = 'my-agent-id'; - - before(async () => { - await observabilityOnboardingApiClient.logMonitoringUser({ - endpoint: 'POST /internal/observability_onboarding/flow/{id}/step/{name}', - params: { - path: { - id: onboardingId, - name: 'ea-status', - }, - body: { - status: 'complete', - payload: { - agentId, - }, - }, - }, - }); - }); - - describe('when no logs have been ingested', () => { - it('should return log-ingest as loading', async () => { - const request = await callApi({ - onboardingId, - }); - - expect(request.status).to.be(200); - - const logsIngestProgress = request.body.progress['logs-ingest']; - expect(logsIngestProgress).to.have.property('status', 'loading'); - }); - }); - - describe('when logs have been ingested', () => { - describe('with a different agentId', () => { - describe('and onboarding type is logFiles', () => { - before(async () => { - await synthtrace.index([ - timerange('2023-11-20T10:00:00.000Z', '2023-11-20T10:01:00.000Z') - .interval('1m') - .rate(1) - .generator((timestamp) => - log - .create() - .message('This is a log message') - .timestamp(timestamp) - .dataset(datasetName) - .namespace(namespace) - .service('my-service') - .defaults({ - 'agent.id': 'another-agent-id', - 'log.file.path': '/my-service.log', - }) - ), - ]); - }); - - it('should return log-ingest as incomplete', async () => { - const request = await callApi({ - onboardingId, - }); - - expect(request.status).to.be(200); - - const logsIngestProgress = request.body.progress['logs-ingest']; - expect(logsIngestProgress).to.have.property('status', 'loading'); - }); - - after(async () => { - await synthtrace.clean(); - }); - }); - }); - - describe('with the expected agentId', () => { - describe('and onboarding type is logFiles', () => { - before(async () => { - await synthtrace.index([ - timerange('2023-11-20T10:00:00.000Z', '2023-11-20T10:01:00.000Z') - .interval('1m') - .rate(1) - .generator((timestamp) => - log - .create() - .message('This is a log message') - .timestamp(timestamp) - .dataset(datasetName) - .namespace(namespace) - .service('my-service') - .defaults({ - 'agent.id': agentId, - 'log.file.path': '/my-service.log', - }) - ), - ]); - }); - - it('should return log-ingest as complete', async () => { - const request = await callApi({ - onboardingId, - }); - - expect(request.status).to.be(200); - - const logsIngestProgress = request.body.progress['logs-ingest']; - expect(logsIngestProgress).to.have.property('status', 'complete'); - }); - - after(async () => { - await synthtrace.clean(); - }); - }); - }); - }); - }); - }); - }); - }); }); } diff --git a/x-pack/test/observability_onboarding_api_integration/tests/logs/create.spec.ts b/x-pack/test/observability_onboarding_api_integration/tests/logs/create.spec.ts deleted file mode 100644 index 7904bd344c270..0000000000000 --- a/x-pack/test/observability_onboarding_api_integration/tests/logs/create.spec.ts +++ /dev/null @@ -1,92 +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 { OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE } from '@kbn/observability-onboarding-plugin/server/saved_objects/observability_onboarding_status'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { ObservabilityOnboardingApiError } from '../../common/observability_onboarding_api_supertest'; -import { expectToReject } from '../../common/utils/expect_to_reject'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const kibanaServer = getService('kibanaServer'); - const observabilityOnboardingApiClient = getService('observabilityOnboardingApiClient'); - - async function callApiWithoutPrivileges(state = {}) { - return await observabilityOnboardingApiClient.readUser({ - endpoint: 'POST /internal/observability_onboarding/logs/flow', - params: { - body: { - type: 'logFiles', - name: 'name', - state, - }, - }, - }); - } - - async function callApiWithPrivileges(type: 'logFiles', state = {}) { - return await observabilityOnboardingApiClient.logMonitoringUser({ - endpoint: 'POST /internal/observability_onboarding/logs/flow', - params: { - body: { - type, - name: 'name', - state, - }, - }, - }); - } - - registry.when('Save state', { config: 'basic' }, () => { - describe('when missing required privileges', () => { - it('fails with a 500 error', async () => { - const err = await expectToReject( - async () => await callApiWithoutPrivileges() - ); - - expect(err.res.status).to.be(500); - expect(err.res.body.message).to.contain('unauthorized'); - }); - }); - - describe('when required privileges are set', () => { - it('returns a flow id and apiKey encoded', async () => { - const state = { - datasetName: 'my-dataset', - serviceName: 'my-service', - namespace: 'my-namespace', - logFilePaths: ['my-service-logs.log'], - }; - - const request = await callApiWithPrivileges('logFiles', state); - - expect(request.status).to.be(200); - expect(request.body.apiKeyEncoded).to.not.empty(); - expect(request.body.onboardingId).to.not.empty(); - }); - - it('saves the expected state for logFiles', async () => { - const state = { - datasetName: 'my-dataset', - serviceName: 'my-service', - namespace: 'my-namespace', - logFilePaths: ['my-service-logs.log'], - }; - - const request = await callApiWithPrivileges('logFiles', state); - - const savedState = await kibanaServer.savedObjects.get({ - type: OBSERVABILITY_ONBOARDING_STATE_SAVED_OBJECT_TYPE, - id: request.body.onboardingId, - }); - - expect(savedState.attributes).to.be.eql({ type: 'logFiles', state, progress: {} }); - }); - }); - }); -} diff --git a/x-pack/test/observability_onboarding_api_integration/tests/logs/privileges.spec.ts b/x-pack/test/observability_onboarding_api_integration/tests/logs/privileges.spec.ts index 02de274373b20..0d5d76c339b05 100644 --- a/x-pack/test/observability_onboarding_api_integration/tests/logs/privileges.spec.ts +++ b/x-pack/test/observability_onboarding_api_integration/tests/logs/privileges.spec.ts @@ -21,31 +21,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when('Api Key privileges check', { config: 'basic' }, () => { describe('when missing required privileges', () => { - it('returns false when user has reader privileges', async () => { - const privileges = await callApiAs('readUser'); - - expect(privileges.body.hasPrivileges).not.ok(); - }); - it('returns false when user has no access privileges', async () => { const privileges = await callApiAs('noAccessUser'); expect(privileges.body.hasPrivileges).not.ok(); }); }); - - describe('when required privileges are set', () => { - it('returns true when user has logMonitoring privileges', async () => { - const privileges = await callApiAs('logMonitoringUser'); - - expect(privileges.body.hasPrivileges).ok(); - }); - - it('returns true when user has admin privileges', async () => { - const privileges = await callApiAs('adminUser'); - - expect(privileges.body.hasPrivileges).ok(); - }); - }); }); }