Skip to content

Commit

Permalink
[APM] Migrate /mobile API tests to deployment agnostic folder (elas…
Browse files Browse the repository at this point in the history
…tic#199021)

closes elastic#198980

In addition to migrating the mobile api tests, the PR includes

- Fixing mapping issue with `error.grouping_name` which causing to drop
documents
- Fix and unskip mobile tests

### 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"

```

TODO 
- [x]   flaky runner 
- [x] locally pass
-  [x] mki run

---------

Co-authored-by: Carlos Crespo <[email protected]>
Co-authored-by: kibanamachine <[email protected]>
Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
4 people authored Nov 11, 2024
1 parent c050bb4 commit f77a805
Show file tree
Hide file tree
Showing 26 changed files with 1,223 additions and 1,198 deletions.
1 change: 0 additions & 1 deletion packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ export class Instance extends Entity<ApmFields> {
...this.fields,
'error.type': 'crash',
'error.exception': [{ message, ...(type ? { type } : {}) }],
'error.grouping_name': getErrorGroupingKey(message),
});
}
error({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ export class MobileDevice extends Entity<ApmFields> {
'error.type': 'crash',
'error.id': generateLongIdWithSeed(message),
'error.exception': [{ message, ...{ type: 'crash' } }],
'error.grouping_name': groupingName || message,
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon
it('returns a version when agent is listed in the file', async () => {
const { status, body } = await callApi();
expect(status).to.be(200);

const agents = body.data;

const nodeAgent = agents[nodeAgentName] as ElasticApmAgentLatestVersion;
expect(nodeAgent?.latest_version).not.to.be(undefined);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default function apmApiIntegrationTests({
}: DeploymentAgnosticFtrProviderContext) {
describe('APM', function () {
loadTestFile(require.resolve('./agent_explorer'));
loadTestFile(require.resolve('./mobile'));
loadTestFile(require.resolve('./custom_dashboards'));
loadTestFile(require.resolve('./dependencies'));
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* 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 { apm, timerange } from '@kbn/apm-synthtrace-client';
import {
APIClientRequestParamsOf,
APIReturnType,
} from '@kbn/apm-plugin/public/services/rest/create_call_apm_api';
import { RecursivePartial } from '@kbn/apm-plugin/typings/common';
import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace';
import type { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context';

type ErrorGroups =
APIReturnType<'GET /internal/apm/mobile-services/{serviceName}/crashes/groups/main_statistics'>['errorGroups'];

export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) {
const apmApiClient = getService('apmApi');
const synthtrace = getService('synthtrace');

const serviceName = 'synth-swift';
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/mobile-services/{serviceName}/crashes/groups/main_statistics'>['params']
>
) {
return await apmApiClient.readUser({
endpoint: 'GET /internal/apm/mobile-services/{serviceName}/crashes/groups/main_statistics',
params: {
path: { serviceName, ...overrides?.path },
query: {
start: new Date(start).toISOString(),
end: new Date(end).toISOString(),
environment: 'ENVIRONMENT_ALL',
kuery: '',
...overrides?.query,
},
},
});
}

describe('Crash group list', () => {
it('handles empty state', async () => {
const response = await callApi();
expect(response.status).to.be(200);
expect(response.body.errorGroups).to.empty();
});

describe('when data is loaded', () => {
describe('errors group', () => {
let apmSynthtraceEsClient: ApmSynthtraceEsClient;

const appleTransaction = {
name: 'GET /apple 🍎 ',
successRate: 75,
failureRate: 25,
};

const bananaTransaction = {
name: 'GET /banana 🍌',
successRate: 50,
failureRate: 50,
};

before(async () => {
const serviceInstance = apm
.service({ name: serviceName, environment: 'production', agentName: 'swift' })
.instance('instance-a');

apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient();

await apmSynthtraceEsClient.index([
timerange(start, end)
.interval('1m')
.rate(appleTransaction.successRate)
.generator((timestamp) =>
serviceInstance
.transaction({ transactionName: appleTransaction.name })
.timestamp(timestamp)
.duration(1000)
.success()
),
timerange(start, end)
.interval('1m')
.rate(appleTransaction.failureRate)
.generator((timestamp) =>
serviceInstance
.transaction({ transactionName: appleTransaction.name })
.errors(
serviceInstance
.crash({
message: 'crash 1',
})
.timestamp(timestamp)
)
.duration(1000)
.timestamp(timestamp)
.failure()
),
timerange(start, end)
.interval('1m')
.rate(bananaTransaction.successRate)
.generator((timestamp) =>
serviceInstance
.transaction({ transactionName: bananaTransaction.name })
.timestamp(timestamp)
.duration(1000)
.success()
),
timerange(start, end)
.interval('1m')
.rate(bananaTransaction.failureRate)
.generator((timestamp) =>
serviceInstance
.transaction({ transactionName: bananaTransaction.name })
.errors(
serviceInstance
.crash({
message: 'crash 2',
})
.timestamp(timestamp)
)
.duration(1000)
.timestamp(timestamp)
.failure()
),
]);
});

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

describe('returns the correct data', () => {
let errorGroups: ErrorGroups;
before(async () => {
const response = await callApi();
errorGroups = response.body.errorGroups;
});
it('returns correct number of crashes', () => {
expect(errorGroups.length).to.equal(2);
expect(errorGroups.map((error) => error.name).sort()).to.eql(['crash 1', 'crash 2']);
});

it('returns correct occurrences', () => {
const numberOfBuckets = 15;
expect(errorGroups.map((error) => error.occurrences).sort()).to.eql([
appleTransaction.failureRate * numberOfBuckets,
bananaTransaction.failureRate * numberOfBuckets,
]);
});
});
});
});
});
}
Loading

0 comments on commit f77a805

Please sign in to comment.