mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[APM] Migrate /correlations
to deployment agnostic test (#199276)
## Summary Closes https://github.com/elastic/kibana/issues/198962 Part of https://github.com/elastic/kibana/issues/193245 This PR contains the changes to migrate `correlations` test folder to Deployment-agnostic testing strategy. ### How to test - Serverless ``` node scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts node scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts --grep="APM" ``` It's recommended to be run against [MKI](https://github.com/crespocarlos/kibana/blob/main/x-pack/test_serverless/README.md#run-tests-on-mki) - Stateful ``` node scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts node scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts --grep="APM" ``` ## Checks - [ ] (OPTIONAL, only if a test has been unskipped) Run flaky test suite - [x] local run for serverless - [x] local run for stateful - [x] MKI run for serverless
This commit is contained in:
parent
e4298492b5
commit
c97b85d169
12 changed files with 452 additions and 388 deletions
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
type ArchiveName =
|
||||
| '8.0.0'
|
||||
| 'apm_8.0.0'
|
||||
| 'apm_mappings_only_8.0.0'
|
||||
| 'infra_metrics_and_apm'
|
||||
| 'metrics_8.0.0'
|
||||
| 'ml_8.0.0'
|
||||
| 'observability_overview'
|
||||
| 'rum_8.0.0'
|
||||
| 'rum_test_data';
|
||||
|
||||
export const ARCHIVER_ROUTES: { [key in ArchiveName]: string } = {
|
||||
'8.0.0': 'x-pack/test/apm_api_integration/common/fixtures/es_archiver/8.0.0',
|
||||
'apm_8.0.0': 'x-pack/test/apm_api_integration/common/fixtures/es_archiver/apm_8.0.0',
|
||||
'apm_mappings_only_8.0.0':
|
||||
'x-pack/test/apm_api_integration/common/fixtures/es_archiver/apm_mappings_only_8.0.0',
|
||||
infra_metrics_and_apm:
|
||||
'x-pack/test/apm_api_integration/common/fixtures/es_archiver/infra_metrics_and_apm',
|
||||
'metrics_8.0.0': 'x-pack/test/apm_api_integration/common/fixtures/es_archiver/metrics_8.0.0',
|
||||
'ml_8.0.0': 'x-pack/test/apm_api_integration/common/fixtures/es_archiver/ml_8.0.0',
|
||||
observability_overview:
|
||||
'x-pack/test/apm_api_integration/common/fixtures/es_archiver/observability_overview',
|
||||
'rum_8.0.0': 'x-pack/test/apm_api_integration/common/fixtures/es_archiver/rum_8.0.0',
|
||||
rum_test_data: 'x-pack/test/apm_api_integration/common/fixtures/es_archiver/rum_test_data',
|
||||
};
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* 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 { orderBy } from 'lodash';
|
||||
import expect from '@kbn/expect';
|
||||
import type { FailedTransactionsCorrelationsResponse } from '@kbn/apm-plugin/common/correlations/failed_transactions_correlations/types';
|
||||
import { EVENT_OUTCOME } from '@kbn/apm-plugin/common/es_fields/apm';
|
||||
import { EventOutcome } from '@kbn/apm-plugin/common/event_outcome';
|
||||
import { LatencyDistributionChartType } from '@kbn/apm-plugin/common/latency_distribution_chart_types';
|
||||
import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context';
|
||||
import { ARCHIVER_ROUTES } from '../constants/archiver';
|
||||
|
||||
// These tests go through the full sequence of queries required
|
||||
// to get the final results for a failed transactions correlation analysis.
|
||||
export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) {
|
||||
const apmApiClient = getService('apmApi');
|
||||
const esArchiver = getService('esArchiver');
|
||||
// This matches the parameters used for the other tab's queries in `../correlations/*`.
|
||||
const getOptions = () => ({
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
start: '2020',
|
||||
end: '2021',
|
||||
kuery: '',
|
||||
});
|
||||
|
||||
describe('failed transactions', () => {
|
||||
describe('without data', () => {
|
||||
it('handles the empty state', async () => {
|
||||
const overallDistributionResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
percentileThreshold: 95,
|
||||
chartType: LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(overallDistributionResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${overallDistributionResponse.status}'`
|
||||
);
|
||||
|
||||
const errorDistributionResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
percentileThreshold: 95,
|
||||
termFilters: [{ fieldName: EVENT_OUTCOME, fieldValue: EventOutcome.failure }],
|
||||
chartType: LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(errorDistributionResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${errorDistributionResponse.status}'`
|
||||
);
|
||||
|
||||
const fieldCandidatesResponse = await apmApiClient.readUser({
|
||||
endpoint: 'GET /internal/apm/correlations/field_candidates/transactions',
|
||||
params: {
|
||||
query: getOptions(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(fieldCandidatesResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${fieldCandidatesResponse.status}'`
|
||||
);
|
||||
|
||||
const failedTransactionsCorrelationsResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/correlations/p_values/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
fieldCandidates: fieldCandidatesResponse.body?.fieldCandidates,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(failedTransactionsCorrelationsResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${failedTransactionsCorrelationsResponse.status}'`
|
||||
);
|
||||
|
||||
const finalRawResponse: FailedTransactionsCorrelationsResponse = {
|
||||
ccsWarning: failedTransactionsCorrelationsResponse.body?.ccsWarning,
|
||||
percentileThresholdValue: overallDistributionResponse.body?.percentileThresholdValue,
|
||||
overallHistogram: overallDistributionResponse.body?.overallHistogram,
|
||||
failedTransactionsCorrelations:
|
||||
failedTransactionsCorrelationsResponse.body?.failedTransactionsCorrelations,
|
||||
};
|
||||
|
||||
expect(finalRawResponse?.failedTransactionsCorrelations?.length).to.eql(
|
||||
0,
|
||||
`Expected 0 identified correlations, got ${finalRawResponse?.failedTransactionsCorrelations?.length}.`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with data', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
|
||||
it('runs queries and returns results', async () => {
|
||||
const overallDistributionResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
percentileThreshold: 95,
|
||||
chartType: LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(overallDistributionResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${overallDistributionResponse.status}'`
|
||||
);
|
||||
|
||||
const errorDistributionResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
percentileThreshold: 95,
|
||||
termFilters: [{ fieldName: EVENT_OUTCOME, fieldValue: EventOutcome.failure }],
|
||||
chartType: LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(errorDistributionResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${errorDistributionResponse.status}'`
|
||||
);
|
||||
|
||||
const fieldCandidatesResponse = await apmApiClient.readUser({
|
||||
endpoint: 'GET /internal/apm/correlations/field_candidates/transactions',
|
||||
params: {
|
||||
query: getOptions(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(fieldCandidatesResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${fieldCandidatesResponse.status}'`
|
||||
);
|
||||
|
||||
const fieldCandidates = fieldCandidatesResponse.body?.fieldCandidates.filter(
|
||||
(t) => !(t === EVENT_OUTCOME)
|
||||
);
|
||||
|
||||
// Identified 80 fieldCandidates.
|
||||
expect(fieldCandidates.length).to.eql(
|
||||
80,
|
||||
`Expected field candidates length to be '80', got '${fieldCandidates.length}'`
|
||||
);
|
||||
|
||||
const failedTransactionsCorrelationsResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/correlations/p_values/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
fieldCandidates,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(failedTransactionsCorrelationsResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${failedTransactionsCorrelationsResponse.status}'`
|
||||
);
|
||||
|
||||
const fieldsToSample = new Set<string>();
|
||||
if (
|
||||
failedTransactionsCorrelationsResponse.body?.failedTransactionsCorrelations.length > 0
|
||||
) {
|
||||
failedTransactionsCorrelationsResponse.body?.failedTransactionsCorrelations.forEach(
|
||||
(d) => {
|
||||
fieldsToSample.add(d.fieldName);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const finalRawResponse: FailedTransactionsCorrelationsResponse = {
|
||||
ccsWarning: failedTransactionsCorrelationsResponse.body?.ccsWarning,
|
||||
percentileThresholdValue: overallDistributionResponse.body?.percentileThresholdValue,
|
||||
overallHistogram: overallDistributionResponse.body?.overallHistogram,
|
||||
errorHistogram: errorDistributionResponse.body?.overallHistogram,
|
||||
failedTransactionsCorrelations:
|
||||
failedTransactionsCorrelationsResponse.body?.failedTransactionsCorrelations,
|
||||
};
|
||||
|
||||
expect(finalRawResponse?.percentileThresholdValue).to.be(1309695.875);
|
||||
expect(finalRawResponse?.errorHistogram?.length).to.be(101);
|
||||
expect(finalRawResponse?.overallHistogram?.length).to.be(101);
|
||||
|
||||
expect(finalRawResponse?.failedTransactionsCorrelations?.length).to.eql(
|
||||
29,
|
||||
`Expected 29 identified correlations, got ${finalRawResponse?.failedTransactionsCorrelations?.length}.`
|
||||
);
|
||||
|
||||
const sortedCorrelations = orderBy(
|
||||
finalRawResponse?.failedTransactionsCorrelations,
|
||||
['score', 'fieldName', 'fieldValue'],
|
||||
['desc', 'asc', 'asc']
|
||||
);
|
||||
const correlation = sortedCorrelations?.[0];
|
||||
|
||||
expect(typeof correlation).to.be('object');
|
||||
expect(correlation?.doc_count).to.be(31);
|
||||
expect(correlation?.score).to.be(83.70467673605746);
|
||||
expect(correlation?.bg_count).to.be(31);
|
||||
expect(correlation?.fieldName).to.be('transaction.result');
|
||||
expect(correlation?.fieldValue).to.be('HTTP 5xx');
|
||||
expect(typeof correlation?.pValue).to.be('number');
|
||||
expect(typeof correlation?.normalizedScore).to.be('number');
|
||||
expect(typeof correlation?.failurePercentage).to.be('number');
|
||||
expect(typeof correlation?.successPercentage).to.be('number');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 { ARCHIVER_ROUTES } from '../constants/archiver';
|
||||
|
||||
export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) {
|
||||
const apmApiClient = getService('apmApi');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
const endpoint = 'GET /internal/apm/correlations/field_candidates/transactions';
|
||||
|
||||
const getOptions = () => ({
|
||||
params: {
|
||||
query: {
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
start: '2020',
|
||||
end: '2021',
|
||||
kuery: '',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
describe('field candidates', () => {
|
||||
describe('without data', () => {
|
||||
it('handles the empty state', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
...getOptions(),
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
// If the source indices are empty, there will be no field candidates
|
||||
// because of the `include_empty_fields: false` option in the query.
|
||||
expect(response.body?.fieldCandidates.length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with data and default args', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
|
||||
it('returns field candidates', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
...getOptions(),
|
||||
});
|
||||
|
||||
expect(response.status).to.eql(200);
|
||||
expect(response.body?.fieldCandidates.length).to.be(81);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -6,11 +6,12 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context';
|
||||
import { ARCHIVER_ROUTES } from '../constants/archiver';
|
||||
|
||||
export default function ApiTest({ getService }: FtrProviderContext) {
|
||||
const apmApiClient = getService('apmApiClient');
|
||||
const registry = getService('registry');
|
||||
export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) {
|
||||
const apmApiClient = getService('apmApi');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
const endpoint = 'POST /internal/apm/correlations/field_value_pairs/transactions';
|
||||
|
||||
|
@ -41,22 +42,27 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
},
|
||||
});
|
||||
|
||||
registry.when('field value pairs without data', { config: 'trial', archives: [] }, () => {
|
||||
it('handles the empty state', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
...getOptions(),
|
||||
describe('field value pairs', () => {
|
||||
describe('without data', () => {
|
||||
it('handles the empty state', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
...getOptions(),
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
expect(response.body?.fieldValuePairs.length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with data and default args', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
expect(response.body?.fieldValuePairs.length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
registry.when(
|
||||
'field value pairs with data and default args',
|
||||
{ config: 'trial', archives: ['8.0.0'] },
|
||||
() => {
|
||||
it('returns field value pairs', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
|
@ -66,6 +72,6 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
expect(response.status).to.eql(200);
|
||||
expect(response.body?.fieldValuePairs.length).to.be(124);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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('correlations', () => {
|
||||
loadTestFile(require.resolve('./failed_transactions.spec.ts'));
|
||||
loadTestFile(require.resolve('./field_candidates.spec.ts'));
|
||||
loadTestFile(require.resolve('./field_value_pairs.spec.ts'));
|
||||
loadTestFile(require.resolve('./latency.spec.ts'));
|
||||
loadTestFile(require.resolve('./p_values.spec.ts'));
|
||||
});
|
||||
}
|
|
@ -14,13 +14,14 @@ import type {
|
|||
LatencyCorrelationsResponse,
|
||||
} from '@kbn/apm-plugin/common/correlations/latency_correlations/types';
|
||||
import { LatencyDistributionChartType } from '@kbn/apm-plugin/common/latency_distribution_chart_types';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context';
|
||||
import { ARCHIVER_ROUTES } from '../constants/archiver';
|
||||
|
||||
// These tests go through the full sequence of queries required
|
||||
// to get the final results for a latency correlation analysis.
|
||||
export default function ApiTest({ getService }: FtrProviderContext) {
|
||||
const apmApiClient = getService('apmApiClient');
|
||||
const registry = getService('registry');
|
||||
export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) {
|
||||
const apmApiClient = getService('apmApi');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
// This matches the parameters used for the other tab's queries in `../correlations/*`.
|
||||
const getOptions = () => ({
|
||||
|
@ -30,10 +31,8 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
kuery: '',
|
||||
});
|
||||
|
||||
registry.when(
|
||||
'correlations latency overall without data',
|
||||
{ config: 'trial', archives: [] },
|
||||
() => {
|
||||
describe('latency', () => {
|
||||
describe('overall without data', () => {
|
||||
it('handles the empty state', async () => {
|
||||
const overallDistributionResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
|
@ -104,13 +103,16 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
expect(finalRawResponse?.overallHistogram).to.be(undefined);
|
||||
expect(finalRawResponse?.latencyCorrelations?.length).to.be(0);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('with data and opbeans-node args', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
|
||||
registry.when(
|
||||
'correlations latency with data and opbeans-node args',
|
||||
{ config: 'trial', archives: ['8.0.0'] },
|
||||
() => {
|
||||
// putting this into a single `it` because the responses depend on each other
|
||||
it('runs queries and returns results', async () => {
|
||||
const overallDistributionResponse = await apmApiClient.readUser({
|
||||
|
@ -250,6 +252,6 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
expect(correlation?.ksTest).to.be(1.9848961005439386e-12);
|
||||
expect(correlation?.histogram?.length).to.be(101);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -6,11 +6,12 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context';
|
||||
import { ARCHIVER_ROUTES } from '../constants/archiver';
|
||||
|
||||
export default function ApiTest({ getService }: FtrProviderContext) {
|
||||
const apmApiClient = getService('apmApiClient');
|
||||
const registry = getService('registry');
|
||||
export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) {
|
||||
const apmApiClient = getService('apmApi');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
const endpoint = 'POST /internal/apm/correlations/p_values/transactions';
|
||||
|
||||
|
@ -41,22 +42,27 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
},
|
||||
});
|
||||
|
||||
registry.when('p values without data', { config: 'trial', archives: [] }, () => {
|
||||
it('handles the empty state', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
...getOptions(),
|
||||
describe('p values', () => {
|
||||
describe('without data', () => {
|
||||
it('handles the empty state', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
...getOptions(),
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
expect(response.body?.failedTransactionsCorrelations.length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with data and default args', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
expect(response.body?.failedTransactionsCorrelations.length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
registry.when(
|
||||
'p values with data and default args',
|
||||
{ config: 'trial', archives: ['8.0.0'] },
|
||||
() => {
|
||||
it('returns p values', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
|
@ -66,6 +72,6 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
expect(response.status).to.eql(200);
|
||||
expect(response.body?.failedTransactionsCorrelations.length).to.be(15);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -6,11 +6,12 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context';
|
||||
import { ARCHIVER_ROUTES } from '../constants/archiver';
|
||||
|
||||
export default function ApiTest({ getService }: FtrProviderContext) {
|
||||
const apmApiClient = getService('apmApiClient');
|
||||
const registry = getService('registry');
|
||||
export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) {
|
||||
const apmApiClient = getService('apmApi');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
const endpoint = 'POST /internal/apm/correlations/significant_correlations/transactions';
|
||||
|
||||
|
@ -65,22 +66,27 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
},
|
||||
});
|
||||
|
||||
registry.when('significant correlations without data', { config: 'trial', archives: [] }, () => {
|
||||
it('handles the empty state', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
...getOptions(),
|
||||
describe('significant correlations', () => {
|
||||
describe('without data', () => {
|
||||
it('handles the empty state', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
...getOptions(),
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
expect(response.body?.latencyCorrelations.length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with data and default args', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload(ARCHIVER_ROUTES['8.0.0']);
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
expect(response.body?.latencyCorrelations.length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
registry.when(
|
||||
'significant correlations with data and default args',
|
||||
{ config: 'trial', archives: ['8.0.0'] },
|
||||
() => {
|
||||
it('returns significant correlations', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
|
@ -90,6 +96,6 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
expect(response.status).to.eql(200);
|
||||
expect(response.body?.latencyCorrelations.length).to.be(7);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -15,6 +15,7 @@ export default function apmApiIntegrationTests({
|
|||
loadTestFile(require.resolve('./mobile'));
|
||||
loadTestFile(require.resolve('./custom_dashboards'));
|
||||
loadTestFile(require.resolve('./dependencies'));
|
||||
loadTestFile(require.resolve('./correlations'));
|
||||
loadTestFile(require.resolve('./entities'));
|
||||
loadTestFile(require.resolve('./cold_start'));
|
||||
});
|
||||
|
|
|
@ -3786,10 +3786,6 @@
|
|||
"index": {
|
||||
"auto_expand_replicas": "0-1",
|
||||
"codec": "best_compression",
|
||||
"lifecycle": {
|
||||
"name": "apm-rollover-30-days",
|
||||
"rollover_alias": "apm-8.0.0-error"
|
||||
},
|
||||
"mapping": {
|
||||
"total_fields": {
|
||||
"limit": "2000"
|
||||
|
@ -4243,8 +4239,7 @@
|
|||
"transaction.message.queue.name",
|
||||
"fields.*"
|
||||
]
|
||||
},
|
||||
"refresh_interval": "1ms"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8183,10 +8178,6 @@
|
|||
"index": {
|
||||
"auto_expand_replicas": "0-1",
|
||||
"codec": "best_compression",
|
||||
"lifecycle": {
|
||||
"name": "apm-rollover-30-days",
|
||||
"rollover_alias": "apm-8.0.0-metric"
|
||||
},
|
||||
"mapping": {
|
||||
"total_fields": {
|
||||
"limit": "2000"
|
||||
|
@ -8640,8 +8631,7 @@
|
|||
"transaction.message.queue.name",
|
||||
"fields.*"
|
||||
]
|
||||
},
|
||||
"refresh_interval": "1ms"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12871,8 +12861,7 @@
|
|||
"transaction.message.queue.name",
|
||||
"fields.*"
|
||||
]
|
||||
},
|
||||
"refresh_interval": "1ms"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16653,10 +16642,6 @@
|
|||
"index": {
|
||||
"auto_expand_replicas": "0-1",
|
||||
"codec": "best_compression",
|
||||
"lifecycle": {
|
||||
"name": "apm-rollover-30-days",
|
||||
"rollover_alias": "apm-8.0.0-profile"
|
||||
},
|
||||
"mapping": {
|
||||
"total_fields": {
|
||||
"limit": "2000"
|
||||
|
@ -17110,8 +17095,7 @@
|
|||
"transaction.message.queue.name",
|
||||
"fields.*"
|
||||
]
|
||||
},
|
||||
"refresh_interval": "1ms"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20899,10 +20883,6 @@
|
|||
"index": {
|
||||
"auto_expand_replicas": "0-1",
|
||||
"codec": "best_compression",
|
||||
"lifecycle": {
|
||||
"name": "apm-rollover-30-days",
|
||||
"rollover_alias": "apm-8.0.0-span"
|
||||
},
|
||||
"mapping": {
|
||||
"total_fields": {
|
||||
"limit": "2000"
|
||||
|
@ -21356,8 +21336,7 @@
|
|||
"transaction.message.queue.name",
|
||||
"fields.*"
|
||||
]
|
||||
},
|
||||
"refresh_interval": "1ms"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25242,10 +25221,6 @@
|
|||
"index": {
|
||||
"auto_expand_replicas": "0-1",
|
||||
"codec": "best_compression",
|
||||
"lifecycle": {
|
||||
"name": "apm-rollover-30-days",
|
||||
"rollover_alias": "apm-8.0.0-transaction"
|
||||
},
|
||||
"mapping": {
|
||||
"total_fields": {
|
||||
"limit": "2000"
|
||||
|
@ -25699,8 +25674,7 @@
|
|||
"transaction.message.queue.name",
|
||||
"fields.*"
|
||||
]
|
||||
},
|
||||
"refresh_interval": "1ms"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,223 +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 { orderBy } from 'lodash';
|
||||
import expect from '@kbn/expect';
|
||||
import type { FailedTransactionsCorrelationsResponse } from '@kbn/apm-plugin/common/correlations/failed_transactions_correlations/types';
|
||||
import { EVENT_OUTCOME } from '@kbn/apm-plugin/common/es_fields/apm';
|
||||
import { EventOutcome } from '@kbn/apm-plugin/common/event_outcome';
|
||||
import { LatencyDistributionChartType } from '@kbn/apm-plugin/common/latency_distribution_chart_types';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
|
||||
// These tests go through the full sequence of queries required
|
||||
// to get the final results for a failed transactions correlation analysis.
|
||||
export default function ApiTest({ getService }: FtrProviderContext) {
|
||||
const apmApiClient = getService('apmApiClient');
|
||||
const registry = getService('registry');
|
||||
|
||||
// This matches the parameters used for the other tab's queries in `../correlations/*`.
|
||||
const getOptions = () => ({
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
start: '2020',
|
||||
end: '2021',
|
||||
kuery: '',
|
||||
});
|
||||
|
||||
registry.when('failed transactions without data', { config: 'trial', archives: [] }, () => {
|
||||
it('handles the empty state', async () => {
|
||||
const overallDistributionResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
percentileThreshold: 95,
|
||||
chartType: LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(overallDistributionResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${overallDistributionResponse.status}'`
|
||||
);
|
||||
|
||||
const errorDistributionResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
percentileThreshold: 95,
|
||||
termFilters: [{ fieldName: EVENT_OUTCOME, fieldValue: EventOutcome.failure }],
|
||||
chartType: LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(errorDistributionResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${errorDistributionResponse.status}'`
|
||||
);
|
||||
|
||||
const fieldCandidatesResponse = await apmApiClient.readUser({
|
||||
endpoint: 'GET /internal/apm/correlations/field_candidates/transactions',
|
||||
params: {
|
||||
query: getOptions(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(fieldCandidatesResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${fieldCandidatesResponse.status}'`
|
||||
);
|
||||
|
||||
const failedTransactionsCorrelationsResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/correlations/p_values/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
fieldCandidates: fieldCandidatesResponse.body?.fieldCandidates,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(failedTransactionsCorrelationsResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${failedTransactionsCorrelationsResponse.status}'`
|
||||
);
|
||||
|
||||
const finalRawResponse: FailedTransactionsCorrelationsResponse = {
|
||||
ccsWarning: failedTransactionsCorrelationsResponse.body?.ccsWarning,
|
||||
percentileThresholdValue: overallDistributionResponse.body?.percentileThresholdValue,
|
||||
overallHistogram: overallDistributionResponse.body?.overallHistogram,
|
||||
failedTransactionsCorrelations:
|
||||
failedTransactionsCorrelationsResponse.body?.failedTransactionsCorrelations,
|
||||
};
|
||||
|
||||
expect(finalRawResponse?.failedTransactionsCorrelations?.length).to.eql(
|
||||
0,
|
||||
`Expected 0 identified correlations, got ${finalRawResponse?.failedTransactionsCorrelations?.length}.`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
registry.when('failed transactions with data', { config: 'trial', archives: ['8.0.0'] }, () => {
|
||||
it('runs queries and returns results', async () => {
|
||||
const overallDistributionResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
percentileThreshold: 95,
|
||||
chartType: LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(overallDistributionResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${overallDistributionResponse.status}'`
|
||||
);
|
||||
|
||||
const errorDistributionResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
percentileThreshold: 95,
|
||||
termFilters: [{ fieldName: EVENT_OUTCOME, fieldValue: EventOutcome.failure }],
|
||||
chartType: LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(errorDistributionResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${errorDistributionResponse.status}'`
|
||||
);
|
||||
|
||||
const fieldCandidatesResponse = await apmApiClient.readUser({
|
||||
endpoint: 'GET /internal/apm/correlations/field_candidates/transactions',
|
||||
params: {
|
||||
query: getOptions(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(fieldCandidatesResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${fieldCandidatesResponse.status}'`
|
||||
);
|
||||
|
||||
const fieldCandidates = fieldCandidatesResponse.body?.fieldCandidates.filter(
|
||||
(t) => !(t === EVENT_OUTCOME)
|
||||
);
|
||||
|
||||
// Identified 80 fieldCandidates.
|
||||
expect(fieldCandidates.length).to.eql(
|
||||
80,
|
||||
`Expected field candidates length to be '80', got '${fieldCandidates.length}'`
|
||||
);
|
||||
|
||||
const failedTransactionsCorrelationsResponse = await apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/correlations/p_values/transactions',
|
||||
params: {
|
||||
body: {
|
||||
...getOptions(),
|
||||
fieldCandidates,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(failedTransactionsCorrelationsResponse.status).to.eql(
|
||||
200,
|
||||
`Expected status to be '200', got '${failedTransactionsCorrelationsResponse.status}'`
|
||||
);
|
||||
|
||||
const fieldsToSample = new Set<string>();
|
||||
if (failedTransactionsCorrelationsResponse.body?.failedTransactionsCorrelations.length > 0) {
|
||||
failedTransactionsCorrelationsResponse.body?.failedTransactionsCorrelations.forEach((d) => {
|
||||
fieldsToSample.add(d.fieldName);
|
||||
});
|
||||
}
|
||||
|
||||
const finalRawResponse: FailedTransactionsCorrelationsResponse = {
|
||||
ccsWarning: failedTransactionsCorrelationsResponse.body?.ccsWarning,
|
||||
percentileThresholdValue: overallDistributionResponse.body?.percentileThresholdValue,
|
||||
overallHistogram: overallDistributionResponse.body?.overallHistogram,
|
||||
errorHistogram: errorDistributionResponse.body?.overallHistogram,
|
||||
failedTransactionsCorrelations:
|
||||
failedTransactionsCorrelationsResponse.body?.failedTransactionsCorrelations,
|
||||
};
|
||||
|
||||
expect(finalRawResponse?.percentileThresholdValue).to.be(1309695.875);
|
||||
expect(finalRawResponse?.errorHistogram?.length).to.be(101);
|
||||
expect(finalRawResponse?.overallHistogram?.length).to.be(101);
|
||||
|
||||
expect(finalRawResponse?.failedTransactionsCorrelations?.length).to.eql(
|
||||
29,
|
||||
`Expected 29 identified correlations, got ${finalRawResponse?.failedTransactionsCorrelations?.length}.`
|
||||
);
|
||||
|
||||
const sortedCorrelations = orderBy(
|
||||
finalRawResponse?.failedTransactionsCorrelations,
|
||||
['score', 'fieldName', 'fieldValue'],
|
||||
['desc', 'asc', 'asc']
|
||||
);
|
||||
const correlation = sortedCorrelations?.[0];
|
||||
|
||||
expect(typeof correlation).to.be('object');
|
||||
expect(correlation?.doc_count).to.be(31);
|
||||
expect(correlation?.score).to.be(83.70467673605746);
|
||||
expect(correlation?.bg_count).to.be(31);
|
||||
expect(correlation?.fieldName).to.be('transaction.result');
|
||||
expect(correlation?.fieldValue).to.be('HTTP 5xx');
|
||||
expect(typeof correlation?.pValue).to.be('number');
|
||||
expect(typeof correlation?.normalizedScore).to.be('number');
|
||||
expect(typeof correlation?.failurePercentage).to.be('number');
|
||||
expect(typeof correlation?.successPercentage).to.be('number');
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,57 +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';
|
||||
|
||||
export default function ApiTest({ getService }: FtrProviderContext) {
|
||||
const apmApiClient = getService('apmApiClient');
|
||||
const registry = getService('registry');
|
||||
|
||||
const endpoint = 'GET /internal/apm/correlations/field_candidates/transactions';
|
||||
|
||||
const getOptions = () => ({
|
||||
params: {
|
||||
query: {
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
start: '2020',
|
||||
end: '2021',
|
||||
kuery: '',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
registry.when('field candidates without data', { config: 'trial', archives: [] }, () => {
|
||||
it('handles the empty state', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
...getOptions(),
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
// If the source indices are empty, there will be no field candidates
|
||||
// because of the `include_empty_fields: false` option in the query.
|
||||
expect(response.body?.fieldCandidates.length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
registry.when(
|
||||
'field candidates with data and default args',
|
||||
{ config: 'trial', archives: ['8.0.0'] },
|
||||
() => {
|
||||
it('returns field candidates', async () => {
|
||||
const response = await apmApiClient.readUser({
|
||||
endpoint,
|
||||
...getOptions(),
|
||||
});
|
||||
|
||||
expect(response.status).to.eql(200);
|
||||
expect(response.body?.fieldCandidates.length).to.be(81);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue