From f2402cef373c1335f994a8c2f79225933e489f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Mon, 1 Nov 2021 12:31:06 -0400 Subject: [PATCH] [APM] Adding api tests for error group (#116771) * adding api tests for error group * addresing pr changes --- .../tests/errors/distribution.ts | 56 +---------- .../tests/errors/generate_data.ts | 73 +++++++++++++++ .../tests/errors/group_id.ts | 92 +++++++++++++++++++ .../test/apm_api_integration/tests/index.ts | 4 + 4 files changed, 172 insertions(+), 53 deletions(-) create mode 100644 x-pack/test/apm_api_integration/tests/errors/generate_data.ts create mode 100644 x-pack/test/apm_api_integration/tests/errors/group_id.ts diff --git a/x-pack/test/apm_api_integration/tests/errors/distribution.ts b/x-pack/test/apm_api_integration/tests/errors/distribution.ts index 4f4b457de86b..750ddf59ed2c 100644 --- a/x-pack/test/apm_api_integration/tests/errors/distribution.ts +++ b/x-pack/test/apm_api_integration/tests/errors/distribution.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { service, timerange } from '@elastic/apm-synthtrace'; import expect from '@kbn/expect'; import { first, last, sumBy } from 'lodash'; import { isFiniteNumber } from '../../../../plugins/apm/common/utils/is_finite_number'; @@ -15,6 +14,7 @@ import { import { RecursivePartial } from '../../../../plugins/apm/typings/common'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { registry } from '../../common/registry'; +import { config, generateData } from './generate_data'; type ErrorsDistribution = APIReturnType<'GET /internal/apm/services/{serviceName}/errors/distribution'>; @@ -65,59 +65,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, () => { describe('errors distribution', () => { - const appleTransaction = { - name: 'GET /apple 🍎 ', - successRate: 75, - failureRate: 25, - }; - const bananaTransaction = { - name: 'GET /banana 🍌', - successRate: 50, - failureRate: 50, - }; - + const { appleTransaction, bananaTransaction } = config; before(async () => { - const serviceGoProdInstance = service(serviceName, 'production', 'go').instance( - 'instance-a' - ); - - const interval = '1m'; - - const indices = [appleTransaction, bananaTransaction] - .map((transaction, index) => { - return [ - ...timerange(start, end) - .interval(interval) - .rate(transaction.successRate) - .flatMap((timestamp) => - serviceGoProdInstance - .transaction(transaction.name) - .timestamp(timestamp) - .duration(1000) - .success() - .serialize() - ), - ...timerange(start, end) - .interval(interval) - .rate(transaction.failureRate) - .flatMap((timestamp) => - serviceGoProdInstance - .transaction(transaction.name) - .errors( - serviceGoProdInstance - .error(`Error ${index}`, transaction.name) - .timestamp(timestamp) - ) - .duration(1000) - .timestamp(timestamp) - .failure() - .serialize() - ), - ]; - }) - .flatMap((_) => _); - - await synthtraceEsClient.index(indices); + await generateData({ serviceName, start, end, synthtraceEsClient }); }); after(() => synthtraceEsClient.clean()); diff --git a/x-pack/test/apm_api_integration/tests/errors/generate_data.ts b/x-pack/test/apm_api_integration/tests/errors/generate_data.ts new file mode 100644 index 000000000000..d31db77ad750 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/errors/generate_data.ts @@ -0,0 +1,73 @@ +/* + * 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 { service, timerange } from '@elastic/apm-synthtrace'; +import type { SynthtraceEsClient } from '../../common/synthtrace_es_client'; + +export const config = { + appleTransaction: { + name: 'GET /apple 🍎 ', + successRate: 75, + failureRate: 25, + }, + bananaTransaction: { + name: 'GET /banana 🍌', + successRate: 50, + failureRate: 50, + }, +}; + +export async function generateData({ + synthtraceEsClient, + serviceName, + start, + end, +}: { + synthtraceEsClient: SynthtraceEsClient; + serviceName: string; + start: number; + end: number; +}) { + const serviceGoProdInstance = service(serviceName, 'production', 'go').instance('instance-a'); + + const interval = '1m'; + + const { bananaTransaction, appleTransaction } = config; + + const documents = [appleTransaction, bananaTransaction] + .map((transaction, index) => { + return [ + ...timerange(start, end) + .interval(interval) + .rate(transaction.successRate) + .flatMap((timestamp) => + serviceGoProdInstance + .transaction(transaction.name) + .timestamp(timestamp) + .duration(1000) + .success() + .serialize() + ), + ...timerange(start, end) + .interval(interval) + .rate(transaction.failureRate) + .flatMap((timestamp) => + serviceGoProdInstance + .transaction(transaction.name) + .errors( + serviceGoProdInstance.error(`Error ${index}`, transaction.name).timestamp(timestamp) + ) + .duration(1000) + .timestamp(timestamp) + .failure() + .serialize() + ), + ]; + }) + .flatMap((_) => _); + + await synthtraceEsClient.index(documents); +} diff --git a/x-pack/test/apm_api_integration/tests/errors/group_id.ts b/x-pack/test/apm_api_integration/tests/errors/group_id.ts new file mode 100644 index 000000000000..ef9e293355a7 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/errors/group_id.ts @@ -0,0 +1,92 @@ +/* + * 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 { + APIClientRequestParamsOf, + APIReturnType, +} from '../../../../plugins/apm/public/services/rest/createCallApmApi'; +import { RecursivePartial } from '../../../../plugins/apm/typings/common'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { registry } from '../../common/registry'; +import { config, generateData } from './generate_data'; + +type ErrorsDistribution = + APIReturnType<'GET /internal/apm/services/{serviceName}/errors/{groupId}'>; + +export default function ApiTest({ getService }: FtrProviderContext) { + const apmApiClient = getService('apmApiClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + + const serviceName = 'synth-go'; + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + + async function callApi( + overrides?: RecursivePartial< + APIClientRequestParamsOf<'GET /internal/apm/services/{serviceName}/errors/{groupId}'>['params'] + > + ) { + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/services/{serviceName}/errors/{groupId}', + params: { + path: { + serviceName, + groupId: 'foo', + ...overrides?.path, + }, + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + environment: 'ENVIRONMENT_ALL', + kuery: '', + ...overrides?.query, + }, + }, + }); + return response; + } + + registry.when('when data is not loaded', { config: 'basic', archives: [] }, () => { + it('handles the empty state', async () => { + const response = await callApi(); + expect(response.status).to.be(200); + expect(response.body.occurrencesCount).to.be(0); + }); + }); + + registry.when( + 'when data is loaded', + { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, + () => { + const { bananaTransaction } = config; + describe('error group id', () => { + before(async () => { + await generateData({ serviceName, start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + describe('return correct data', () => { + let errorsDistribution: ErrorsDistribution; + before(async () => { + const response = await callApi({ + path: { groupId: '0000000000000000000000000Error 1' }, + }); + errorsDistribution = response.body; + }); + + it('displays correct number of occurrences', () => { + const numberOfBuckets = 15; + expect(errorsDistribution.occurrencesCount).to.equal( + bananaTransaction.failureRate * numberOfBuckets + ); + }); + }); + }); + } + ); +} diff --git a/x-pack/test/apm_api_integration/tests/index.ts b/x-pack/test/apm_api_integration/tests/index.ts index 29b40b6ff62c..c5b6e6554efd 100644 --- a/x-pack/test/apm_api_integration/tests/index.ts +++ b/x-pack/test/apm_api_integration/tests/index.ts @@ -241,6 +241,10 @@ export default function apmApiIntegrationTests(providerContext: FtrProviderConte loadTestFile(require.resolve('./latency/service_apis')); }); + describe('errors/group_id', function () { + loadTestFile(require.resolve('./errors/group_id')); + }); + describe('errors/distribution', function () { loadTestFile(require.resolve('./errors/distribution')); });