mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[APM] Migrate `/data_view` to deployment agnostic test (#199296)](https://github.com/elastic/kibana/pull/199296) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Sergi Romeu","email":"sergi.romeu@elastic.co"},"sourceCommit":{"committedDate":"2024-11-12T10:41:34Z","message":"[APM] Migrate `/data_view` to deployment agnostic test (#199296)\n\n## Summary\n\nCloses https://github.com/elastic/kibana/issues/198965\nPart of https://github.com/elastic/kibana/issues/193245\n\nThis PR contains the changes to migrate `data_view` test folder to\nDeployment-agnostic testing strategy.\n\n### How to test\n\n- Serverless\n\n```\nnode scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts\nnode scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts --grep=\"APM\"\n```\n\nIt's recommended to be run against\n[MKI](https://github.com/crespocarlos/kibana/blob/main/x-pack/test_serverless/README.md#run-tests-on-mki)\n\n- Stateful\n```\nnode scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts\nnode scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts --grep=\"APM\"\n```\n\n## Checks\n\n- [x] (OPTIONAL, only if a test has been unskipped) Run flaky test suite\n- [x] local run for serverless\n- [x] local run for stateful\n- [x] MKI run for serverless","sha":"803738fa0c8fea3cdfc4760c7b3dd667637de724","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:prev-minor","ci:project-deploy-observability","Team:obs-ux-infra_services"],"title":"[APM] Migrate `/data_view` to deployment agnostic test","number":199296,"url":"https://github.com/elastic/kibana/pull/199296","mergeCommit":{"message":"[APM] Migrate `/data_view` to deployment agnostic test (#199296)\n\n## Summary\n\nCloses https://github.com/elastic/kibana/issues/198965\nPart of https://github.com/elastic/kibana/issues/193245\n\nThis PR contains the changes to migrate `data_view` test folder to\nDeployment-agnostic testing strategy.\n\n### How to test\n\n- Serverless\n\n```\nnode scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts\nnode scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts --grep=\"APM\"\n```\n\nIt's recommended to be run against\n[MKI](https://github.com/crespocarlos/kibana/blob/main/x-pack/test_serverless/README.md#run-tests-on-mki)\n\n- Stateful\n```\nnode scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts\nnode scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts --grep=\"APM\"\n```\n\n## Checks\n\n- [x] (OPTIONAL, only if a test has been unskipped) Run flaky test suite\n- [x] local run for serverless\n- [x] local run for stateful\n- [x] MKI run for serverless","sha":"803738fa0c8fea3cdfc4760c7b3dd667637de724"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/199296","number":199296,"mergeCommit":{"message":"[APM] Migrate `/data_view` to deployment agnostic test (#199296)\n\n## Summary\n\nCloses https://github.com/elastic/kibana/issues/198965\nPart of https://github.com/elastic/kibana/issues/193245\n\nThis PR contains the changes to migrate `data_view` test folder to\nDeployment-agnostic testing strategy.\n\n### How to test\n\n- Serverless\n\n```\nnode scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts\nnode scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts --grep=\"APM\"\n```\n\nIt's recommended to be run against\n[MKI](https://github.com/crespocarlos/kibana/blob/main/x-pack/test_serverless/README.md#run-tests-on-mki)\n\n- Stateful\n```\nnode scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts\nnode scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts --grep=\"APM\"\n```\n\n## Checks\n\n- [x] (OPTIONAL, only if a test has been unskipped) Run flaky test suite\n- [x] local run for serverless\n- [x] local run for stateful\n- [x] MKI run for serverless","sha":"803738fa0c8fea3cdfc4760c7b3dd667637de724"}}]}] BACKPORT--> Co-authored-by: Sergi Romeu <sergi.romeu@elastic.co>
This commit is contained in:
parent
ee0934ba8b
commit
8fe516a539
4 changed files with 306 additions and 268 deletions
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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('data_view', () => {
|
||||
loadTestFile(require.resolve('./static.spec.ts'));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* 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 '@kbn/apm-synthtrace-client';
|
||||
import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace';
|
||||
import expect from '@kbn/expect';
|
||||
import { DataView } from '@kbn/data-views-plugin/common';
|
||||
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
|
||||
import request from 'superagent';
|
||||
import { getStaticDataViewId } from '@kbn/apm-data-view';
|
||||
import { SupertestWithRoleScope } from '../../../../services/role_scoped_supertest';
|
||||
import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context';
|
||||
import {
|
||||
SupertestReturnType,
|
||||
ApmApiError,
|
||||
} from '../../../../../../apm_api_integration/common/apm_api_supertest';
|
||||
|
||||
export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) {
|
||||
const apmApiClient = getService('apmApi');
|
||||
const roleScopedSupertest = getService('roleScopedSupertest');
|
||||
const synthtraceService = getService('synthtrace');
|
||||
const logger = getService('log');
|
||||
const dataViewPattern =
|
||||
'traces-apm*,apm-*,traces-*.otel-*,logs-apm*,apm-*,logs-*.otel-*,metrics-apm*,apm-*,metrics-*.otel-*';
|
||||
|
||||
function createDataViewWithWriteUser({ spaceId }: { spaceId: string }) {
|
||||
return apmApiClient.writeUser({
|
||||
endpoint: 'POST /internal/apm/data_view/static',
|
||||
spaceId,
|
||||
});
|
||||
}
|
||||
|
||||
function createDataViewWithReadUser({ spaceId }: { spaceId: string }) {
|
||||
return apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/data_view/static',
|
||||
spaceId,
|
||||
});
|
||||
}
|
||||
|
||||
describe('Data view static', () => {
|
||||
let supertestEditorWithApiKey: SupertestWithRoleScope;
|
||||
let supertestEditorWithCookieCredentials: SupertestWithRoleScope;
|
||||
|
||||
before(async () => {
|
||||
supertestEditorWithApiKey = await roleScopedSupertest.getSupertestWithRoleScope('editor', {
|
||||
withInternalHeaders: true,
|
||||
});
|
||||
|
||||
supertestEditorWithCookieCredentials = await roleScopedSupertest.getSupertestWithRoleScope(
|
||||
'editor',
|
||||
{
|
||||
useCookieHeader: true,
|
||||
withInternalHeaders: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await supertestEditorWithApiKey.destroy();
|
||||
});
|
||||
|
||||
function deleteDataView(spaceId: string) {
|
||||
return supertestEditorWithApiKey.delete(
|
||||
`/s/${spaceId}/api/saved_objects/index-pattern/${getStaticDataViewId(spaceId)}?force=true`
|
||||
);
|
||||
}
|
||||
|
||||
function getDataView({ spaceId }: { spaceId: string }) {
|
||||
const spacePrefix = spaceId !== 'default' ? `/s/${spaceId}` : '';
|
||||
return supertestEditorWithApiKey.get(
|
||||
`${spacePrefix}/api/saved_objects/index-pattern/${getStaticDataViewId(spaceId)}`
|
||||
);
|
||||
}
|
||||
|
||||
function getDataViewSuggestions(field: string) {
|
||||
return supertestEditorWithCookieCredentials
|
||||
.post(`/internal/kibana/suggestions/values/${dataViewPattern}`)
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
|
||||
.send({ query: '', field, method: 'terms_agg' });
|
||||
}
|
||||
|
||||
describe('no mappings exist', () => {
|
||||
let response: SupertestReturnType<'POST /internal/apm/data_view/static'>;
|
||||
before(async () => {
|
||||
response = await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
});
|
||||
|
||||
it('does not create data view', async () => {
|
||||
expect(response.status).to.be(200);
|
||||
expect(response.body).to.eql({
|
||||
created: false,
|
||||
reason: 'No APM data',
|
||||
});
|
||||
});
|
||||
|
||||
it('cannot fetch data view', async () => {
|
||||
const res = await getDataView({ spaceId: 'default' });
|
||||
expect(res.status).to.be(404);
|
||||
expect(res.body.message).to.eql(
|
||||
'Saved object [index-pattern/apm_static_data_view_id_default] not found'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when mappings and APM data exists', () => {
|
||||
let synthtrace: ApmSynthtraceEsClient;
|
||||
|
||||
before(async () => {
|
||||
synthtrace = await synthtraceService.createApmSynthtraceEsClient();
|
||||
await generateApmData(synthtrace);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await synthtrace.clean();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
try {
|
||||
await Promise.all([deleteDataView('default'), deleteDataView('foo')]);
|
||||
} catch (e) {
|
||||
logger.error(`Could not delete data views ${e.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
describe('when creating data view with write user', () => {
|
||||
let response: SupertestReturnType<'POST /internal/apm/data_view/static'>;
|
||||
|
||||
before(async () => {
|
||||
response = await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
});
|
||||
|
||||
it('successfully creates the apm data view', async () => {
|
||||
expect(response.status).to.be(200);
|
||||
|
||||
const dataView = (response.body as { dataView: DataView }).dataView;
|
||||
|
||||
expect(dataView.id).to.be('apm_static_data_view_id_default');
|
||||
expect(dataView.name).to.be('APM');
|
||||
expect(dataView.title).to.be(
|
||||
'traces-apm*,apm-*,traces-*.otel-*,logs-apm*,apm-*,logs-*.otel-*,metrics-apm*,apm-*,metrics-*.otel-*'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when fetching the data view', () => {
|
||||
let dataViewResponse: request.Response;
|
||||
|
||||
before(async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
dataViewResponse = await getDataView({ spaceId: 'default' });
|
||||
});
|
||||
|
||||
it('return 200', () => {
|
||||
expect(dataViewResponse.status).to.be(200);
|
||||
});
|
||||
|
||||
it('has correct id', () => {
|
||||
expect(dataViewResponse.body.id).to.be('apm_static_data_view_id_default');
|
||||
});
|
||||
|
||||
it('has correct title', () => {
|
||||
expect(dataViewResponse.body.attributes.title).to.be(dataViewPattern);
|
||||
});
|
||||
|
||||
it('has correct attributes', () => {
|
||||
expect(dataViewResponse.body.attributes.fieldFormatMap).to.be(
|
||||
JSON.stringify({
|
||||
'trace.id': {
|
||||
id: 'url',
|
||||
params: {
|
||||
urlTemplate: 'apm/link-to/trace/{{value}}',
|
||||
labelTemplate: '{{value}}',
|
||||
},
|
||||
},
|
||||
'transaction.id': {
|
||||
id: 'url',
|
||||
params: {
|
||||
urlTemplate: 'apm/link-to/transaction/{{value}}',
|
||||
labelTemplate: '{{value}}',
|
||||
},
|
||||
},
|
||||
'transaction.duration.us': {
|
||||
id: 'duration',
|
||||
params: {
|
||||
inputFormat: 'microseconds',
|
||||
outputFormat: 'asMilliseconds',
|
||||
showSuffix: true,
|
||||
useShortSuffix: true,
|
||||
outputPrecision: 2,
|
||||
includeSpaceWithSuffix: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// this test ensures that the default APM Data View doesn't interfere with suggestions returned in the kuery bar (this has been a problem in the past)
|
||||
it('can get suggestions for `trace.id`', async () => {
|
||||
const suggestions = await getDataViewSuggestions('trace.id');
|
||||
expect(suggestions.body.length).to.be(10);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating data view via read user', () => {
|
||||
it('throws an error', async () => {
|
||||
try {
|
||||
await createDataViewWithReadUser({ spaceId: 'default' });
|
||||
} catch (e) {
|
||||
const err = e as ApmApiError;
|
||||
const responseBody = err.res.body;
|
||||
expect(err.res.status).to.eql(403);
|
||||
expect(responseBody.statusCode).to.eql(403);
|
||||
expect(responseBody.error).to.eql('Forbidden');
|
||||
expect(responseBody.message).to.eql('Unable to create index-pattern');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating data view twice', () => {
|
||||
it('returns 200 response with reason, if data view already exists', async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
const res = await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
|
||||
expect(res.status).to.be(200);
|
||||
expect(res.body).to.eql({
|
||||
created: false,
|
||||
reason: 'Dataview already exists in the active space and does not need to be updated',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating data view in "default" space', () => {
|
||||
it('can be retrieved from the "default" space', async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
const res = await getDataView({ spaceId: 'default' });
|
||||
expect(res.body.id).to.eql('apm_static_data_view_id_default');
|
||||
expect(res.body.namespaces).to.eql(['default']);
|
||||
});
|
||||
|
||||
it('cannot be retrieved from the "foo" space', async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
const res = await getDataView({ spaceId: 'foo' });
|
||||
expect(res.body.statusCode).to.be(404);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating data view in "foo" space', () => {
|
||||
it('can be retrieved from the "foo" space', async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'foo' });
|
||||
const res = await getDataView({ spaceId: 'foo' });
|
||||
expect(res.body.id).to.eql('apm_static_data_view_id_foo');
|
||||
expect(res.body.namespaces).to.eql(['foo']);
|
||||
});
|
||||
|
||||
it('cannot be retrieved from the "default" space', async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'foo' });
|
||||
const res = await getDataView({ spaceId: 'default' });
|
||||
expect(res.body.statusCode).to.be(404);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function generateApmData(synthtrace: ApmSynthtraceEsClient) {
|
||||
const range = timerange(
|
||||
new Date('2021-10-01T00:00:00.000Z').getTime(),
|
||||
new Date('2021-10-01T00:01:00.000Z').getTime()
|
||||
);
|
||||
|
||||
const instance = apm
|
||||
.service({ name: 'my-service', environment: 'production', agentName: 'go' })
|
||||
.instance('my-instance');
|
||||
|
||||
return synthtrace.index([
|
||||
range
|
||||
.interval('1s')
|
||||
.rate(1)
|
||||
.generator((timestamp) =>
|
||||
instance
|
||||
.transaction({ transactionName: 'GET /api' })
|
||||
.timestamp(timestamp)
|
||||
.duration(30)
|
||||
.success()
|
||||
),
|
||||
]);
|
||||
}
|
|
@ -14,6 +14,7 @@ export default function apmApiIntegrationTests({
|
|||
loadTestFile(require.resolve('./agent_explorer'));
|
||||
loadTestFile(require.resolve('./custom_dashboards'));
|
||||
loadTestFile(require.resolve('./dependencies'));
|
||||
loadTestFile(require.resolve('./data_view'));
|
||||
loadTestFile(require.resolve('./correlations'));
|
||||
loadTestFile(require.resolve('./entities'));
|
||||
loadTestFile(require.resolve('./cold_start'));
|
||||
|
|
|
@ -1,268 +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 { apm, timerange } from '@kbn/apm-synthtrace-client';
|
||||
import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace';
|
||||
import expect from '@kbn/expect';
|
||||
import { DataView } from '@kbn/data-views-plugin/common';
|
||||
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
|
||||
import request from 'superagent';
|
||||
import { getStaticDataViewId } from '@kbn/apm-data-view';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
import { SupertestReturnType, ApmApiError } from '../../common/apm_api_supertest';
|
||||
|
||||
export default function ApiTest({ getService }: FtrProviderContext) {
|
||||
const registry = getService('registry');
|
||||
const apmApiClient = getService('apmApiClient');
|
||||
const supertest = getService('supertest');
|
||||
const synthtrace = getService('apmSynthtraceEsClient');
|
||||
const logger = getService('log');
|
||||
const dataViewPattern =
|
||||
'traces-apm*,apm-*,traces-*.otel-*,logs-apm*,apm-*,logs-*.otel-*,metrics-apm*,apm-*,metrics-*.otel-*';
|
||||
|
||||
function createDataViewWithWriteUser({ spaceId }: { spaceId: string }) {
|
||||
return apmApiClient.writeUser({
|
||||
endpoint: 'POST /internal/apm/data_view/static',
|
||||
spaceId,
|
||||
});
|
||||
}
|
||||
|
||||
function createDataViewWithReadUser({ spaceId }: { spaceId: string }) {
|
||||
return apmApiClient.readUser({
|
||||
endpoint: 'POST /internal/apm/data_view/static',
|
||||
spaceId,
|
||||
});
|
||||
}
|
||||
|
||||
function deleteDataView(spaceId: string) {
|
||||
return supertest
|
||||
.delete(
|
||||
`/s/${spaceId}/api/saved_objects/index-pattern/${getStaticDataViewId(spaceId)}?force=true`
|
||||
)
|
||||
.set('kbn-xsrf', 'foo');
|
||||
}
|
||||
|
||||
function getDataView({ spaceId }: { spaceId: string }) {
|
||||
const spacePrefix = spaceId !== 'default' ? `/s/${spaceId}` : '';
|
||||
return supertest.get(
|
||||
`${spacePrefix}/api/saved_objects/index-pattern/${getStaticDataViewId(spaceId)}`
|
||||
);
|
||||
}
|
||||
|
||||
function getDataViewSuggestions(field: string) {
|
||||
return supertest
|
||||
.post(`/internal/kibana/suggestions/values/${dataViewPattern}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
|
||||
.send({ query: '', field, method: 'terms_agg' });
|
||||
}
|
||||
|
||||
registry.when('no mappings exist', { config: 'basic', archives: [] }, () => {
|
||||
let response: SupertestReturnType<'POST /internal/apm/data_view/static'>;
|
||||
before(async () => {
|
||||
response = await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
});
|
||||
|
||||
it('does not create data view', async () => {
|
||||
expect(response.status).to.be(200);
|
||||
expect(response.body).to.eql({
|
||||
created: false,
|
||||
reason: 'No APM data',
|
||||
});
|
||||
});
|
||||
|
||||
it('cannot fetch data view', async () => {
|
||||
const res = await getDataView({ spaceId: 'default' });
|
||||
expect(res.status).to.be(404);
|
||||
expect(res.body.message).to.eql(
|
||||
'Saved object [index-pattern/apm_static_data_view_id_default] not found'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// FLAKY: https://github.com/elastic/kibana/issues/177120
|
||||
registry.when('mappings and APM data exists', { config: 'basic', archives: [] }, () => {
|
||||
// eslint-disable-next-line mocha/no-sibling-hooks
|
||||
before(async () => {
|
||||
await generateApmData(synthtrace);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await synthtrace.clean();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
try {
|
||||
await Promise.all([deleteDataView('default'), deleteDataView('foo')]);
|
||||
} catch (e) {
|
||||
logger.error(`Could not delete data views ${e.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
describe('when creating data view with write user', () => {
|
||||
let response: SupertestReturnType<'POST /internal/apm/data_view/static'>;
|
||||
|
||||
before(async () => {
|
||||
response = await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
});
|
||||
|
||||
it('successfully creates the apm data view', async () => {
|
||||
expect(response.status).to.be(200);
|
||||
|
||||
// @ts-expect-error
|
||||
const dataView = response.body.dataView as DataView;
|
||||
|
||||
expect(dataView.id).to.be('apm_static_data_view_id_default');
|
||||
expect(dataView.name).to.be('APM');
|
||||
expect(dataView.title).to.be(
|
||||
'traces-apm*,apm-*,traces-*.otel-*,logs-apm*,apm-*,logs-*.otel-*,metrics-apm*,apm-*,metrics-*.otel-*'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when fetching the data view', () => {
|
||||
let dataViewResponse: request.Response;
|
||||
|
||||
before(async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
dataViewResponse = await getDataView({ spaceId: 'default' });
|
||||
});
|
||||
|
||||
it('return 200', () => {
|
||||
expect(dataViewResponse.status).to.be(200);
|
||||
});
|
||||
|
||||
it('has correct id', () => {
|
||||
expect(dataViewResponse.body.id).to.be('apm_static_data_view_id_default');
|
||||
});
|
||||
|
||||
it('has correct title', () => {
|
||||
expect(dataViewResponse.body.attributes.title).to.be(dataViewPattern);
|
||||
});
|
||||
|
||||
it('has correct attributes', () => {
|
||||
expect(dataViewResponse.body.attributes.fieldFormatMap).to.be(
|
||||
JSON.stringify({
|
||||
'trace.id': {
|
||||
id: 'url',
|
||||
params: {
|
||||
urlTemplate: 'apm/link-to/trace/{{value}}',
|
||||
labelTemplate: '{{value}}',
|
||||
},
|
||||
},
|
||||
'transaction.id': {
|
||||
id: 'url',
|
||||
params: {
|
||||
urlTemplate: 'apm/link-to/transaction/{{value}}',
|
||||
labelTemplate: '{{value}}',
|
||||
},
|
||||
},
|
||||
'transaction.duration.us': {
|
||||
id: 'duration',
|
||||
params: {
|
||||
inputFormat: 'microseconds',
|
||||
outputFormat: 'asMilliseconds',
|
||||
showSuffix: true,
|
||||
useShortSuffix: true,
|
||||
outputPrecision: 2,
|
||||
includeSpaceWithSuffix: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// this test ensures that the default APM Data View doesn't interfere with suggestions returned in the kuery bar (this has been a problem in the past)
|
||||
it('can get suggestions for `trace.id`', async () => {
|
||||
const suggestions = await getDataViewSuggestions('trace.id');
|
||||
expect(suggestions.body.length).to.be(10);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating data view via read user', () => {
|
||||
it('throws an error', async () => {
|
||||
try {
|
||||
await createDataViewWithReadUser({ spaceId: 'default' });
|
||||
} catch (e) {
|
||||
const err = e as ApmApiError;
|
||||
const responseBody = err.res.body;
|
||||
expect(err.res.status).to.eql(403);
|
||||
expect(responseBody.statusCode).to.eql(403);
|
||||
expect(responseBody.error).to.eql('Forbidden');
|
||||
expect(responseBody.message).to.eql('Unable to create index-pattern');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating data view twice', () => {
|
||||
it('returns 200 response with reason, if data view already exists', async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
const res = await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
|
||||
expect(res.status).to.be(200);
|
||||
expect(res.body).to.eql({
|
||||
created: false,
|
||||
reason: 'Dataview already exists in the active space and does not need to be updated',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating data view in "default" space', () => {
|
||||
it('can be retrieved from the "default" space', async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
const res = await getDataView({ spaceId: 'default' });
|
||||
expect(res.body.id).to.eql('apm_static_data_view_id_default');
|
||||
expect(res.body.namespaces).to.eql(['default']);
|
||||
});
|
||||
|
||||
it('cannot be retrieved from the "foo" space', async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'default' });
|
||||
const res = await getDataView({ spaceId: 'foo' });
|
||||
expect(res.body.statusCode).to.be(404);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating data view in "foo" space', () => {
|
||||
it('can be retrieved from the "foo" space', async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'foo' });
|
||||
const res = await getDataView({ spaceId: 'foo' });
|
||||
expect(res.body.id).to.eql('apm_static_data_view_id_foo');
|
||||
expect(res.body.namespaces).to.eql(['foo']);
|
||||
});
|
||||
|
||||
it('cannot be retrieved from the "default" space', async () => {
|
||||
await createDataViewWithWriteUser({ spaceId: 'foo' });
|
||||
const res = await getDataView({ spaceId: 'default' });
|
||||
expect(res.body.statusCode).to.be(404);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function generateApmData(synthtrace: ApmSynthtraceEsClient) {
|
||||
const range = timerange(
|
||||
new Date('2021-10-01T00:00:00.000Z').getTime(),
|
||||
new Date('2021-10-01T00:01:00.000Z').getTime()
|
||||
);
|
||||
|
||||
const instance = apm
|
||||
.service({ name: 'my-service', environment: 'production', agentName: 'go' })
|
||||
.instance('my-instance');
|
||||
|
||||
return synthtrace.index([
|
||||
range
|
||||
.interval('1s')
|
||||
.rate(1)
|
||||
.generator((timestamp) =>
|
||||
instance
|
||||
.transaction({ transactionName: 'GET /api' })
|
||||
.timestamp(timestamp)
|
||||
.duration(30)
|
||||
.success()
|
||||
),
|
||||
]);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue