Skip to content

Commit

Permalink
Change service details API tests to use synthrace and add test for se…
Browse files Browse the repository at this point in the history
…rverless
  • Loading branch information
gbamparop committed Jan 19, 2022
1 parent c0de1b0 commit 6d14201
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 141 deletions.
8 changes: 8 additions & 0 deletions packages/elastic-apm-synthtrace/src/lib/apm/apm_fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,12 @@ export type ApmFields = Fields &
};
'transaction.sampled': true;
'service.name': string;
'service.version': string;
'service.environment': string;
'service.node.name': string;
'service.runtime.name': string;
'service.runtime.version': string;
'service.framework.name': string;
'span.id': string;
'span.name': string;
'span.type': string;
Expand All @@ -79,7 +82,12 @@ export type ApmFields = Fields &
'span.self_time.count': number;
'span.self_time.sum.us': number;
'cloud.provider': string;
'cloud.project.name': string;
'cloud.service.name': string;
'cloud.availability_zone': string;
'cloud.machine.type': string;
'cloud.region': string;
'host.os.platform': string;
'faas.coldstart': string;
'faas.execution': string;
'faas.trigger.type': string;
Expand Down
141 changes: 0 additions & 141 deletions x-pack/test/apm_api_integration/tests/services/service_details.spec.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* 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 '@elastic/apm-synthtrace';
import type { ApmSynthtraceEsClient } from '@elastic/apm-synthtrace';

export const dataConfig = {
rate: 10,
service: {
name: 'lambda-python-dev-hello',
node: {
name: '2022/01/18/[$LATEST]89634b0ffc884be0b4964a1f4c5d808c',
},
version: '$LATEST',
runtime: {
name: 'AWS_Lambda_python3.8',
version: '3.8.11',
},
framework: 'AWS Lambda',
agent: {
name: 'python',
version: '6.6.0',
},
},
containerOs: 'linux',
serverless: {
faasTriggerType: 'other',
},
cloud: {
provider: 'aws',
availabilityZone: 'us-central1-c',
region: 'us-east-1',
machineType: 'e2-standard-4',
projectName: 'elastic-observability',
serviceName: 'lambda',
},
};

export async function generateData({
synthtraceEsClient,
start,
end,
}: {
synthtraceEsClient: ApmSynthtraceEsClient;
start: number;
end: number;
}) {
const { rate, service, containerOs, serverless, cloud } = dataConfig;
const {
provider,
availabilityZone,
region,
machineType,
projectName,
serviceName: cloudServiceName,
} = cloud;
const { faasTriggerType } = serverless;
const { version, runtime, framework, agent, node, name: serviceName } = service;
const { name: serviceRunTimeName, version: serviceRunTimeVersion } = runtime;
const { name: agentName, version: agentVersion } = agent;
const { name: serviceNodeName } = node;

const instance = apm.service(serviceName, 'production', agentName).instance('instance-a');

const metricsets = timerange(start, end)
.interval('30s')
.rate(rate)
.flatMap((timestamp) =>
instance
.appMetrics({})
.timestamp(timestamp)
.defaults({
'cloud.provider': provider,
'cloud.project.name': projectName,
'cloud.service.name': cloudServiceName,
'cloud.availability_zone': availabilityZone,
'cloud.machine.type': machineType,
'cloud.region': region,
'service.name': serviceName,
'faas.trigger.type': faasTriggerType,
'host.os.platform': containerOs,
'kubernetes.pod.uid': '48f4c5a5-0625-4bea-9d94-77ee94a17e70',
'container.id': '37509fe749719a494218b24b000da50f90e7bfc5de9c45741c40a811f1a4d647',
'service.version': version,
'service.node.name': serviceNodeName,
'service.runtime.name': serviceRunTimeName,
'service.runtime.version': serviceRunTimeVersion,
'service.framework.name': framework,
'agent.name': agentName,
'agent.version': agentVersion,
})
.serialize()
);

await synthtraceEsClient.index(metricsets);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* 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 { first } from 'lodash';
import { FtrProviderContext } from '../../../common/ftr_provider_context';
import { dataConfig, generateData } from './generate_data';
import { APIReturnType } from '../../../../../plugins/apm/public/services/rest/createCallApmApi';

type ServiceDetails = APIReturnType<'GET /internal/apm/services/{serviceName}/metadata/details'>;

export default function ApiTest({ getService }: FtrProviderContext) {
const registry = getService('registry');
const apmApiClient = getService('apmApiClient');
const synthtraceEsClient = getService('synthtraceEsClient');

const {
service: { name: serviceName },
} = dataConfig;
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/services/{serviceName}/metadata/details',
params: {
path: { serviceName },
query: {
start: new Date(start).toISOString(),
end: new Date(end).toISOString(),
},
},
});
}

registry.when(
'Service details 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).to.empty();
});
}
);

registry.when(
'Service details when data is generated',
{ config: 'basic', archives: ['apm_mappings_only_8.0.0'] },
() => {
let body: ServiceDetails;
let status: number;

before(async () => {
await generateData({ synthtraceEsClient, start, end });
const response = await callApi();
body = response.body;
status = response.status;
});

after(() => synthtraceEsClient.clean());

it('returns correct HTTP status', () => {
expect(status).to.be(200);
});

it('returns correct cloud details', () => {
const { cloud } = dataConfig;
const {
provider,
availabilityZone,
region,
machineType,
projectName,
serviceName: cloudServiceName,
} = cloud;

expect(first(body?.cloud?.availabilityZones)).to.be(availabilityZone);
expect(first(body?.cloud?.machineTypes)).to.be(machineType);
expect(body?.cloud?.provider).to.be(provider);
expect(body?.cloud?.projectName).to.be(projectName);
expect(body?.cloud?.serviceName).to.be(cloudServiceName);
expect(first(body?.cloud?.regions)).to.be(region);
});

it('returns correct container details', () => {
const { containerOs } = dataConfig;

expect(body?.container?.isContainerized).to.be(true);
expect(body?.container?.os).to.be(containerOs);
expect(body?.container?.totalNumberInstances).to.be(1);
expect(body?.container?.type).to.be('Kubernetes');
});

it('returns correct serverless details', () => {
const { cloud, serverless } = dataConfig;
const { serviceName: cloudServiceName } = cloud;
const { faasTriggerType } = serverless;

expect(body?.serverless?.type).to.be(cloudServiceName);
expect(body?.serverless?.functionName).to.be(serviceName);
expect(first(body?.serverless?.faasTriggerTypes)).to.be(faasTriggerType);
});

it('returns correct service details', () => {
const { service } = dataConfig;
const { version, runtime, framework, agent } = service;
const { name: runTimeName, version: runTimeVersion } = runtime;
const { name: agentName, version: agentVersion } = agent;

expect(body?.service?.framework).to.be(framework);
expect(body?.service?.agent.name).to.be(agentName);
expect(body?.service?.agent.version).to.be(agentVersion);
expect(body?.service?.runtime?.name).to.be(runTimeName);
expect(body?.service?.runtime?.version).to.be(runTimeVersion);
expect(first(body?.service?.versions)).to.be(version);
});
}
);
}

0 comments on commit 6d14201

Please sign in to comment.