mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Add API tests for top dependencies (#116788)
* Add top dependencies API tests Co-authored-by: Søren Louv-Jansen <sorenlouv@gmail.com>
This commit is contained in:
parent
12af558898
commit
4feeeeb34f
4 changed files with 170 additions and 17 deletions
|
@ -8,40 +8,47 @@ import { service, timerange } from '@elastic/apm-synthtrace';
|
|||
import type { SynthtraceEsClient } from '../../common/synthtrace_es_client';
|
||||
|
||||
export const dataConfig = {
|
||||
spanType: 'db',
|
||||
rate: 20,
|
||||
transaction: {
|
||||
name: 'GET /api/product/list',
|
||||
duration: 1000,
|
||||
},
|
||||
span: {
|
||||
name: 'GET apm-*/_search',
|
||||
type: 'db',
|
||||
subType: 'elasticsearch',
|
||||
destination: 'elasticsearch',
|
||||
},
|
||||
};
|
||||
|
||||
export async function generateData({
|
||||
synthtraceEsClient,
|
||||
backendName,
|
||||
start,
|
||||
end,
|
||||
}: {
|
||||
synthtraceEsClient: SynthtraceEsClient;
|
||||
backendName: string;
|
||||
start: number;
|
||||
end: number;
|
||||
}) {
|
||||
const instance = service('synth-go', 'production', 'go').instance('instance-a');
|
||||
const transactionName = 'GET /api/product/list';
|
||||
const spanName = 'GET apm-*/_search';
|
||||
const { rate, transaction, span } = dataConfig;
|
||||
|
||||
await synthtraceEsClient.index(
|
||||
timerange(start, end)
|
||||
.interval('1m')
|
||||
.rate(10)
|
||||
.rate(rate)
|
||||
.flatMap((timestamp) =>
|
||||
instance
|
||||
.transaction(transactionName)
|
||||
.transaction(transaction.name)
|
||||
.timestamp(timestamp)
|
||||
.duration(1000)
|
||||
.duration(transaction.duration)
|
||||
.success()
|
||||
.children(
|
||||
instance
|
||||
.span(spanName, dataConfig.spanType, backendName)
|
||||
.duration(1000)
|
||||
.span(span.name, span.type, span.subType)
|
||||
.duration(transaction.duration)
|
||||
.success()
|
||||
.destination(backendName)
|
||||
.destination(span.destination)
|
||||
.timestamp(timestamp)
|
||||
)
|
||||
.serialize()
|
||||
|
|
|
@ -15,14 +15,13 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
|
||||
const start = new Date('2021-01-01T00:00:00.000Z').getTime();
|
||||
const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1;
|
||||
const backendName = 'elasticsearch';
|
||||
|
||||
async function callApi() {
|
||||
return await apmApiClient.readUser({
|
||||
endpoint: `GET /internal/apm/backends/metadata`,
|
||||
params: {
|
||||
query: {
|
||||
backendName,
|
||||
backendName: dataConfig.span.destination,
|
||||
start: new Date(start).toISOString(),
|
||||
end: new Date(end).toISOString(),
|
||||
},
|
||||
|
@ -44,16 +43,17 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
);
|
||||
|
||||
registry.when(
|
||||
'Dependency metadata when data is loaded',
|
||||
'Dependency metadata when data is generated',
|
||||
{ config: 'basic', archives: ['apm_mappings_only_8.0.0'] },
|
||||
() => {
|
||||
it('returns correct metadata for the dependency', async () => {
|
||||
await generateData({ synthtraceEsClient, backendName, start, end });
|
||||
await generateData({ synthtraceEsClient, start, end });
|
||||
const { status, body } = await callApi();
|
||||
const { span } = dataConfig;
|
||||
|
||||
expect(status).to.be(200);
|
||||
expect(body.metadata.spanType).to.equal(dataConfig.spanType);
|
||||
expect(body.metadata.spanSubtype).to.equal(backendName);
|
||||
expect(body.metadata.spanType).to.equal(span.type);
|
||||
expect(body.metadata.spanSubtype).to.equal(span.subType);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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 { APIReturnType } from '../../../../plugins/apm/public/services/rest/createCallApmApi';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
import { registry } from '../../common/registry';
|
||||
import { dataConfig, generateData } from './generate_data';
|
||||
import { NodeType, BackendNode } from '../../../../plugins/apm/common/connections';
|
||||
import { roundNumber } from '../../utils';
|
||||
|
||||
type TopDependencies = APIReturnType<'GET /internal/apm/backends/top_backends'>;
|
||||
|
||||
export default function ApiTest({ getService }: FtrProviderContext) {
|
||||
const apmApiClient = getService('apmApiClient');
|
||||
const synthtraceEsClient = getService('synthtraceEsClient');
|
||||
|
||||
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() {
|
||||
return await apmApiClient.readUser({
|
||||
endpoint: 'GET /internal/apm/backends/top_backends',
|
||||
params: {
|
||||
query: {
|
||||
start: new Date(start).toISOString(),
|
||||
end: new Date(end).toISOString(),
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
kuery: '',
|
||||
numBuckets: 20,
|
||||
offset: '',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
registry.when(
|
||||
'Top dependencies when data is not loaded',
|
||||
{ config: 'basic', archives: [] },
|
||||
() => {
|
||||
it('handles empty state', async () => {
|
||||
const { status, body } = await callApi();
|
||||
expect(status).to.be(200);
|
||||
expect(body.backends).to.empty();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
registry.when(
|
||||
'Top dependencies',
|
||||
{ config: 'basic', archives: ['apm_mappings_only_8.0.0'] },
|
||||
() => {
|
||||
describe('when data is generated', () => {
|
||||
let topDependencies: TopDependencies;
|
||||
|
||||
before(async () => {
|
||||
await generateData({ synthtraceEsClient, start, end });
|
||||
const response = await callApi();
|
||||
topDependencies = response.body;
|
||||
});
|
||||
|
||||
after(() => synthtraceEsClient.clean());
|
||||
|
||||
it('returns an array of dependencies', () => {
|
||||
expect(topDependencies).to.have.property('backends');
|
||||
expect(topDependencies.backends).to.have.length(1);
|
||||
});
|
||||
|
||||
it('returns correct dependency information', () => {
|
||||
const location = topDependencies.backends[0].location as BackendNode;
|
||||
const { span } = dataConfig;
|
||||
|
||||
expect(location.type).to.be(NodeType.backend);
|
||||
expect(location.backendName).to.be(span.destination);
|
||||
expect(location.spanType).to.be(span.type);
|
||||
expect(location.spanSubtype).to.be(span.subType);
|
||||
expect(location).to.have.property('id');
|
||||
});
|
||||
|
||||
describe('returns the correct stats', () => {
|
||||
let backends: TopDependencies['backends'][number];
|
||||
|
||||
before(() => {
|
||||
backends = topDependencies.backends[0];
|
||||
});
|
||||
|
||||
it("doesn't have previous stats", () => {
|
||||
expect(backends.previousStats).to.be(null);
|
||||
});
|
||||
|
||||
it('has an "impact" property', () => {
|
||||
expect(backends.currentStats).to.have.property('impact');
|
||||
});
|
||||
|
||||
it('returns the correct latency', () => {
|
||||
const {
|
||||
currentStats: { latency },
|
||||
} = backends;
|
||||
|
||||
const { transaction } = dataConfig;
|
||||
|
||||
expect(latency.value).to.be(transaction.duration * 1000);
|
||||
expect(latency.timeseries.every(({ y }) => y === transaction.duration * 1000)).to.be(
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the correct throughput', () => {
|
||||
const {
|
||||
currentStats: { throughput },
|
||||
} = backends;
|
||||
const { rate } = dataConfig;
|
||||
|
||||
expect(roundNumber(throughput.value)).to.be(roundNumber(rate));
|
||||
});
|
||||
|
||||
it('returns the correct total time', () => {
|
||||
const {
|
||||
currentStats: { totalTime },
|
||||
} = backends;
|
||||
const { rate, transaction } = dataConfig;
|
||||
|
||||
expect(
|
||||
totalTime.timeseries.every(({ y }) => y === rate * transaction.duration * 1000)
|
||||
).to.be(true);
|
||||
});
|
||||
|
||||
it('returns the correct error rate', () => {
|
||||
const {
|
||||
currentStats: { errorRate },
|
||||
} = backends;
|
||||
expect(errorRate.value).to.be(0);
|
||||
expect(errorRate.timeseries.every(({ y }) => y === 0)).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
|
@ -250,6 +250,10 @@ export default function apmApiIntegrationTests(providerContext: FtrProviderConte
|
|||
loadTestFile(require.resolve('./dependencies/metadata'));
|
||||
});
|
||||
|
||||
describe('dependencies/top_dependencies', function () {
|
||||
loadTestFile(require.resolve('./dependencies/top_dependencies'));
|
||||
});
|
||||
|
||||
registry.run(providerContext);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue