diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_groups/service_group_count/service_group_count.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_groups/service_group_count/service_group_count.spec.ts index cbb29e2729dcb..08816f01d0f2b 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_groups/service_group_count/service_group_count.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_groups/service_group_count/service_group_count.spec.ts @@ -6,6 +6,9 @@ */ import expect from '@kbn/expect'; import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import type { RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { ApmRuleType } from '@kbn/rule-data-utils'; +import { AggregationType } from '@kbn/apm-plugin/common/rules/apm_rule_types'; import type { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; import { createServiceGroupApi, @@ -13,10 +16,14 @@ import { getServiceGroupCounts, } from '../service_groups_api_methods'; import { generateData } from './generate_data'; +import { APM_ACTION_VARIABLE_INDEX, APM_ALERTS_INDEX } from '../../alerts/helpers/alerting_helper'; export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { const synthtrace = getService('synthtrace'); const apmApiClient = getService('apmApi'); + const alertingApi = getService('alertingApi'); + const samlAuth = getService('samlAuth'); + const start = Date.now() - 24 * 60 * 60 * 1000; const end = Date.now(); @@ -24,6 +31,7 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon let synthbeansServiceGroupId: string; let opbeansServiceGroupId: string; let apmSynthtraceEsClient: ApmSynthtraceEsClient; + let roleAuthc: RoleCredentials; before(async () => { apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); @@ -59,5 +67,50 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon expect(response.body[synthbeansServiceGroupId]).to.have.property('services', 2); expect(response.body[opbeansServiceGroupId]).to.have.property('services', 1); }); + + describe('with alerts', () => { + let ruleId: string; + + before(async () => { + roleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); + const createdRule = await alertingApi.createRule({ + name: 'Latency threshold | synth-go', + params: { + serviceName: 'synth-go', + transactionType: undefined, + windowSize: 5, + windowUnit: 'h', + threshold: 100, + aggregationType: AggregationType.Avg, + environment: 'testing', + }, + ruleTypeId: ApmRuleType.TransactionDuration, + consumer: 'apm', + roleAuthc, + }); + + ruleId = createdRule.id; + await alertingApi.waitForAlertInIndex({ ruleId, indexName: APM_ALERTS_INDEX }); + }); + + after(async () => { + await alertingApi.cleanUpAlerts({ + roleAuthc, + ruleId, + alertIndexName: APM_ALERTS_INDEX, + connectorIndexName: APM_ACTION_VARIABLE_INDEX, + consumer: 'apm', + }); + await samlAuth.invalidateM2mApiKeyWithRoleScope(roleAuthc); + }); + + it('returns the correct number of alerts', async () => { + const response = await getServiceGroupCounts(apmApiClient); + expect(response.status).to.be(200); + expect(Object.keys(response.body).length).to.be(2); + expect(response.body[synthbeansServiceGroupId]).to.have.property('alerts', 1); + expect(response.body[opbeansServiceGroupId]).to.have.property('alerts', 0); + }); + }); }); } diff --git a/x-pack/test/apm_api_integration/tests/service_groups/service_group_count/generate_data.ts b/x-pack/test/apm_api_integration/tests/service_groups/service_group_count/generate_data.ts deleted file mode 100644 index 7f9b1487bb8ef..0000000000000 --- a/x-pack/test/apm_api_integration/tests/service_groups/service_group_count/generate_data.ts +++ /dev/null @@ -1,74 +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 { apm, timerange } from '@kbn/apm-synthtrace-client'; -import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; - -export async function generateData({ - apmSynthtraceEsClient, - start, - end, -}: { - apmSynthtraceEsClient: ApmSynthtraceEsClient; - start: number; - end: number; -}) { - const synthServices = [ - apm - .service({ name: 'synth-go', environment: 'testing', agentName: 'go' }) - .instance('instance-1'), - apm - .service({ name: 'synth-java', environment: 'testing', agentName: 'java' }) - .instance('instance-2'), - apm - .service({ name: 'opbeans-node', environment: 'testing', agentName: 'nodejs' }) - .instance('instance-3'), - ]; - - await apmSynthtraceEsClient.index( - synthServices.map((service) => - timerange(start, end) - .interval('5m') - .rate(1) - .generator((timestamp) => - service - .transaction({ - transactionName: 'GET /api/product/list', - transactionType: 'request', - }) - .duration(2000) - .timestamp(timestamp) - .children( - service - .span({ - spanName: '/_search', - spanType: 'db', - spanSubtype: 'elasticsearch', - }) - .destination('elasticsearch') - .duration(100) - .success() - .timestamp(timestamp), - service - .span({ - spanName: '/_search', - spanType: 'db', - spanSubtype: 'elasticsearch', - }) - .destination('elasticsearch') - .duration(300) - .success() - .timestamp(timestamp) - ) - .errors( - service.error({ message: 'error 1', type: 'foo' }).timestamp(timestamp), - service.error({ message: 'error 2', type: 'foo' }).timestamp(timestamp), - service.error({ message: 'error 3', type: 'bar' }).timestamp(timestamp) - ) - ) - ) - ); -} diff --git a/x-pack/test/apm_api_integration/tests/service_groups/service_group_count/service_group_count.spec.ts b/x-pack/test/apm_api_integration/tests/service_groups/service_group_count/service_group_count.spec.ts deleted file mode 100644 index 24a38cfa8e356..0000000000000 --- a/x-pack/test/apm_api_integration/tests/service_groups/service_group_count/service_group_count.spec.ts +++ /dev/null @@ -1,98 +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 { AggregationType } from '@kbn/apm-plugin/common/rules/apm_rule_types'; -import { ApmRuleType } from '@kbn/rule-data-utils'; -import expect from '@kbn/expect'; -import { waitForActiveApmAlert } from '../../alerts/helpers/wait_for_active_apm_alerts'; -import { FtrProviderContext } from '../../../common/ftr_provider_context'; -import { createApmRule } from '../../alerts/helpers/alerting_api_helper'; -import { cleanupRuleAndAlertState } from '../../alerts/helpers/cleanup_rule_and_alert_state'; -import { - createServiceGroupApi, - deleteAllServiceGroups, - getServiceGroupCounts, -} from '../service_groups_api_methods'; -import { generateData } from './generate_data'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - const supertest = getService('supertest'); - const apmSynthtraceEsClient = getService('apmSynthtraceEsClient'); - const es = getService('es'); - const log = getService('log'); - const start = Date.now() - 24 * 60 * 60 * 1000; - const end = Date.now(); - - function createRule() { - return createApmRule({ - supertest, - name: 'Latency threshold | synth-go', - params: { - serviceName: 'synth-go', - transactionType: undefined, - windowSize: 5, - windowUnit: 'h', - threshold: 100, - aggregationType: AggregationType.Avg, - environment: 'testing', - }, - ruleTypeId: ApmRuleType.TransactionDuration, - }); - } - - // FLAKY: https://github.com/elastic/kibana/issues/197912 - registry.when.skip('Service group counts', { config: 'basic', archives: [] }, () => { - let synthbeansServiceGroupId: string; - let opbeansServiceGroupId: string; - before(async () => { - const [, { body: synthbeansServiceGroup }, { body: opbeansServiceGroup }] = await Promise.all( - [ - generateData({ start, end, apmSynthtraceEsClient }), - createServiceGroupApi({ - apmApiClient, - groupName: 'synthbeans', - kuery: 'service.name: synth*', - }), - createServiceGroupApi({ - apmApiClient, - groupName: 'opbeans', - kuery: 'service.name: opbeans*', - }), - ] - ); - synthbeansServiceGroupId = synthbeansServiceGroup.id; - opbeansServiceGroupId = opbeansServiceGroup.id; - }); - - after(async () => { - await deleteAllServiceGroups(apmApiClient); - await apmSynthtraceEsClient.clean(); - }); - - describe('with alerts', () => { - let ruleId: string; - before(async () => { - const createdRule = await createRule(); - ruleId = createdRule.id; - await waitForActiveApmAlert({ ruleId, esClient: es, log }); - }); - - after(async () => { - await cleanupRuleAndAlertState({ es, supertest, logger: log }); - }); - - it('returns the correct number of alerts', async () => { - const response = await getServiceGroupCounts(apmApiClient); - expect(response.status).to.be(200); - expect(Object.keys(response.body).length).to.be(2); - expect(response.body[synthbeansServiceGroupId]).to.have.property('alerts', 1); - expect(response.body[opbeansServiceGroupId]).to.have.property('alerts', 0); - }); - }); - }); -} diff --git a/x-pack/test/apm_api_integration/tests/service_groups/service_groups_api_methods.ts b/x-pack/test/apm_api_integration/tests/service_groups/service_groups_api_methods.ts deleted file mode 100644 index 2d0e5405cc3d1..0000000000000 --- a/x-pack/test/apm_api_integration/tests/service_groups/service_groups_api_methods.ts +++ /dev/null @@ -1,66 +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 { ApmApiClient } from '../../common/config'; - -export async function getServiceGroupsApi(apmApiClient: ApmApiClient) { - return apmApiClient.writeUser({ - endpoint: 'GET /internal/apm/service-groups', - }); -} - -export async function createServiceGroupApi({ - apmApiClient, - serviceGroupId, - groupName, - kuery, - description, - color, -}: { - apmApiClient: ApmApiClient; - serviceGroupId?: string; - groupName: string; - kuery: string; - description?: string; - color?: string; -}) { - const response = await apmApiClient.writeUser({ - endpoint: 'POST /internal/apm/service-group', - params: { - query: { - serviceGroupId, - }, - body: { - groupName, - kuery, - description, - color, - }, - }, - }); - return response; -} - -export async function getServiceGroupCounts(apmApiClient: ApmApiClient) { - return apmApiClient.readUser({ - endpoint: 'GET /internal/apm/service-group/counts', - }); -} - -export async function deleteAllServiceGroups(apmApiClient: ApmApiClient) { - return await getServiceGroupsApi(apmApiClient).then((response) => { - const promises = response.body.serviceGroups.map((item) => { - if (item.id) { - return apmApiClient.writeUser({ - endpoint: 'DELETE /internal/apm/service-group', - params: { query: { serviceGroupId: item.id } }, - }); - } - }); - return Promise.all(promises); - }); -}