mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[APM] Migrate api tests to use apm api client (#142229)
* Removed usage of legacySuperTestAsNoAccessUser * Removed usage of legacySupertestAsApmReadUser and legacySupertestAsApmAnnotationsWriteUser * Removed legacyprefixed services from config * Addressing PR comments * Addressing PR comments * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
4b37ede0cd
commit
8f8343b7c2
5 changed files with 178 additions and 152 deletions
|
@ -126,22 +126,10 @@ export function createTestConfig(config: ApmFtrConfig) {
|
|||
},
|
||||
ml: MachineLearningAPIProvider,
|
||||
// legacy clients
|
||||
legacySupertestAsNoAccessUser: getLegacySupertestClient(
|
||||
kibanaServer,
|
||||
ApmUsername.noAccessUser
|
||||
),
|
||||
legacySupertestAsApmReadUser: getLegacySupertestClient(
|
||||
kibanaServer,
|
||||
ApmUsername.viewerUser
|
||||
),
|
||||
legacySupertestAsApmWriteUser: getLegacySupertestClient(
|
||||
kibanaServer,
|
||||
ApmUsername.editorUser
|
||||
),
|
||||
legacySupertestAsApmAnnotationsWriteUser: getLegacySupertestClient(
|
||||
kibanaServer,
|
||||
ApmUsername.apmAnnotationsWriteUser
|
||||
),
|
||||
legacySupertestAsApmReadUserWithoutMlAccess: getLegacySupertestClient(
|
||||
kibanaServer,
|
||||
ApmUsername.apmReadUserWithoutMlAccess
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export async function expectToReject<T extends Error>(fn: () => Promise<any>): Promise<T> {
|
||||
try {
|
||||
await fn();
|
||||
} catch (e) {
|
||||
return e;
|
||||
}
|
||||
throw new Error(`Expected fn to throw`);
|
||||
}
|
|
@ -5,20 +5,33 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
ENVIRONMENT_ALL,
|
||||
ENVIRONMENT_NOT_DEFINED,
|
||||
} from '@kbn/apm-plugin/common/environment_filter_values';
|
||||
import {
|
||||
APIClientRequestParamsOf,
|
||||
APIReturnType,
|
||||
} from '@kbn/apm-plugin/public/services/rest/create_call_apm_api';
|
||||
import { RecursivePartial } from '@kbn/apm-plugin/typings/common';
|
||||
import expect from '@kbn/expect';
|
||||
import { merge, cloneDeep, isPlainObject } from 'lodash';
|
||||
import { JsonObject } from '@kbn/utility-types';
|
||||
import { cloneDeep, isPlainObject, merge } from 'lodash';
|
||||
import { ApmApiError } from '../../common/apm_api_supertest';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
import { expectToReject } from '../../common/utils/expect_to_reject';
|
||||
|
||||
const DEFAULT_INDEX_NAME = 'observability-annotations';
|
||||
|
||||
export default function annotationApiTests({ getService }: FtrProviderContext) {
|
||||
const registry = getService('registry');
|
||||
const supertestRead = getService('legacySupertestAsApmReadUser');
|
||||
const supertestWrite = getService('legacySupertestAsApmAnnotationsWriteUser');
|
||||
const apmApiClient = getService('apmApiClient');
|
||||
const es = getService('es');
|
||||
|
||||
function expectContainsObj(source: JsonObject, expected: JsonObject) {
|
||||
function expectContainsObj(
|
||||
source: APIReturnType<'POST /api/apm/services/{serviceName}/annotation'>,
|
||||
expected: JsonObject
|
||||
) {
|
||||
expect(source).to.eql(
|
||||
merge(cloneDeep(source), expected, (a: any, b: any) => {
|
||||
if (isPlainObject(a) && isPlainObject(b)) {
|
||||
|
@ -29,26 +42,46 @@ export default function annotationApiTests({ getService }: FtrProviderContext) {
|
|||
);
|
||||
}
|
||||
|
||||
function request({ method, url, data }: { method: string; url: string; data?: JsonObject }) {
|
||||
switch (method.toLowerCase()) {
|
||||
case 'get':
|
||||
return supertestRead.get(url).set('kbn-xsrf', 'foo');
|
||||
function createAnnotation(
|
||||
body: APIClientRequestParamsOf<'POST /api/apm/services/{serviceName}/annotation'>['params']['body']
|
||||
) {
|
||||
return apmApiClient.annotationWriterUser({
|
||||
endpoint: 'POST /api/apm/services/{serviceName}/annotation',
|
||||
params: {
|
||||
path: {
|
||||
serviceName: 'opbeans-java',
|
||||
},
|
||||
body,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
case 'post':
|
||||
return supertestWrite.post(url).send(data).set('kbn-xsrf', 'foo');
|
||||
|
||||
default:
|
||||
throw new Error(`Unsupported method ${method}`);
|
||||
}
|
||||
function getAnnotation(
|
||||
query: RecursivePartial<
|
||||
APIClientRequestParamsOf<'GET /api/apm/services/{serviceName}/annotation/search'>['params']['query']
|
||||
>
|
||||
) {
|
||||
return apmApiClient.readUser({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/annotation/search',
|
||||
params: {
|
||||
path: {
|
||||
serviceName: 'opbeans-java',
|
||||
},
|
||||
query: {
|
||||
environment: ENVIRONMENT_ALL.value,
|
||||
start: new Date().toISOString(),
|
||||
end: new Date().toISOString(),
|
||||
...query,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
registry.when('Annotations with a basic license', { config: 'basic', archives: [] }, () => {
|
||||
describe('when creating an annotation', () => {
|
||||
it('fails with a 403 forbidden', async () => {
|
||||
const response = await request({
|
||||
url: '/api/apm/services/opbeans-java/annotation',
|
||||
method: 'POST',
|
||||
data: {
|
||||
const err = await expectToReject<ApmApiError>(() =>
|
||||
createAnnotation({
|
||||
'@timestamp': new Date().toISOString(),
|
||||
message: 'New deployment',
|
||||
tags: ['foo'],
|
||||
|
@ -56,11 +89,11 @@ export default function annotationApiTests({ getService }: FtrProviderContext) {
|
|||
version: '1.1',
|
||||
environment: 'production',
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
expect(response.status).to.be(403);
|
||||
expect(response.body.message).to.be(
|
||||
expect(err.res.status).to.be(403);
|
||||
expect(err.res.body.message).eql(
|
||||
'Annotations require at least a gold license or a trial license.'
|
||||
);
|
||||
});
|
||||
|
@ -79,52 +112,48 @@ export default function annotationApiTests({ getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
it('fails with a 400 bad request if data is missing', async () => {
|
||||
const response = await request({
|
||||
url: '/api/apm/services/opbeans-java/annotation',
|
||||
method: 'POST',
|
||||
});
|
||||
const err = await expectToReject<ApmApiError>(() =>
|
||||
// @ts-expect-error
|
||||
createAnnotation()
|
||||
);
|
||||
|
||||
expect(response.status).to.be(400);
|
||||
expect(err.res.status).to.be(400);
|
||||
});
|
||||
|
||||
it('fails with a 400 bad request if timestamp is invalid', async () => {
|
||||
const invalidTimestampErr = await expectToReject<ApmApiError>(() =>
|
||||
// @ts-expect-error
|
||||
createAnnotation({
|
||||
'@timestamp': 'foo',
|
||||
message: 'foo',
|
||||
})
|
||||
);
|
||||
|
||||
expect(invalidTimestampErr.res.status).to.be(400);
|
||||
});
|
||||
|
||||
it('fails with a 400 bad request if data is invalid', async () => {
|
||||
const invalidTimestampResponse = await request({
|
||||
url: '/api/apm/services/opbeans-java/annotation',
|
||||
method: 'POST',
|
||||
data: {
|
||||
'@timestamp': 'foo',
|
||||
message: 'foo',
|
||||
},
|
||||
});
|
||||
|
||||
expect(invalidTimestampResponse.status).to.be(400);
|
||||
|
||||
const missingServiceVersionResponse = await request({
|
||||
url: '/api/apm/services/opbeans-java/annotation',
|
||||
method: 'POST',
|
||||
data: {
|
||||
const err = await expectToReject<ApmApiError>(() =>
|
||||
// @ts-expect-error
|
||||
createAnnotation({
|
||||
'@timestamp': new Date().toISOString(),
|
||||
message: 'New deployment',
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
expect(missingServiceVersionResponse.status).to.be(400);
|
||||
expect(err.res.status).to.be(400);
|
||||
});
|
||||
|
||||
it('completes with a 200 and the created annotation if data is complete and valid', async () => {
|
||||
const timestamp = new Date().toISOString();
|
||||
|
||||
const response = await request({
|
||||
url: '/api/apm/services/opbeans-java/annotation',
|
||||
method: 'POST',
|
||||
data: {
|
||||
'@timestamp': timestamp,
|
||||
message: 'New deployment',
|
||||
tags: ['foo'],
|
||||
service: {
|
||||
version: '1.1',
|
||||
environment: 'production',
|
||||
},
|
||||
const response = await createAnnotation({
|
||||
'@timestamp': timestamp,
|
||||
message: 'New deployment',
|
||||
tags: ['foo'],
|
||||
service: {
|
||||
version: '1.1',
|
||||
environment: 'production',
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -150,14 +179,10 @@ export default function annotationApiTests({ getService }: FtrProviderContext) {
|
|||
it('prefills `message` and `tags`', async () => {
|
||||
const timestamp = new Date().toISOString();
|
||||
|
||||
const response = await request({
|
||||
url: '/api/apm/services/opbeans-java/annotation',
|
||||
method: 'POST',
|
||||
data: {
|
||||
'@timestamp': timestamp,
|
||||
service: {
|
||||
version: '1.1',
|
||||
},
|
||||
const response = await createAnnotation({
|
||||
'@timestamp': timestamp,
|
||||
service: {
|
||||
version: '1.1',
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -263,9 +288,10 @@ export default function annotationApiTests({ getService }: FtrProviderContext) {
|
|||
end: new Date(2020, 4, 2, 20).toISOString(),
|
||||
};
|
||||
|
||||
const response = await request({
|
||||
url: `/api/apm/services/${serviceName}/annotation/search?start=${range.start}&end=${range.end}&environment=ENVIRONMENT_ALL`,
|
||||
method: 'GET',
|
||||
const response = await getAnnotation({
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
environment: ENVIRONMENT_ALL.value,
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
|
@ -283,22 +309,19 @@ export default function annotationApiTests({ getService }: FtrProviderContext) {
|
|||
|
||||
expect(
|
||||
(
|
||||
await request({
|
||||
url: `/api/apm/services/${serviceName}/annotation`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
service: {
|
||||
version: '1.3',
|
||||
},
|
||||
'@timestamp': new Date(2020, 4, 2, 21, 30).toISOString(),
|
||||
await createAnnotation({
|
||||
service: {
|
||||
version: '1.3',
|
||||
},
|
||||
'@timestamp': new Date(2020, 4, 2, 21, 30).toISOString(),
|
||||
})
|
||||
).status
|
||||
).to.be(200);
|
||||
|
||||
const response = await request({
|
||||
url: `/api/apm/services/${serviceName}/annotation/search?start=${range.start}&end=${range.end}&environment=ENVIRONMENT_ALL`,
|
||||
method: 'GET',
|
||||
const response = await getAnnotation({
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
environment: ENVIRONMENT_ALL.value,
|
||||
});
|
||||
|
||||
expect(response.body.annotations.length).to.be(1);
|
||||
|
@ -311,22 +334,19 @@ export default function annotationApiTests({ getService }: FtrProviderContext) {
|
|||
|
||||
expect(
|
||||
(
|
||||
await request({
|
||||
url: `/api/apm/services/${serviceName}/annotation`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
service: {
|
||||
version: '1.3',
|
||||
},
|
||||
'@timestamp': new Date(2020, 4, 2, 21, 30).toISOString(),
|
||||
await createAnnotation({
|
||||
service: {
|
||||
version: '1.3',
|
||||
},
|
||||
'@timestamp': new Date(2020, 4, 2, 21, 30).toISOString(),
|
||||
})
|
||||
).status
|
||||
).to.be(200);
|
||||
|
||||
const responseFromEarlierRange = await request({
|
||||
url: `/api/apm/services/${serviceName}/annotation/search?start=${earlierRange.start}&end=${earlierRange.end}&environment=ENVIRONMENT_ALL`,
|
||||
method: 'GET',
|
||||
const responseFromEarlierRange = await getAnnotation({
|
||||
start: earlierRange.start,
|
||||
end: earlierRange.end,
|
||||
environment: ENVIRONMENT_ALL.value,
|
||||
});
|
||||
|
||||
expect(responseFromEarlierRange.body.annotations.length).to.be(2);
|
||||
|
@ -337,31 +357,23 @@ export default function annotationApiTests({ getService }: FtrProviderContext) {
|
|||
it('returns stored annotations for the given environment', async () => {
|
||||
expect(
|
||||
(
|
||||
await request({
|
||||
url: `/api/apm/services/${serviceName}/annotation`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
service: {
|
||||
version: '1.3',
|
||||
},
|
||||
'@timestamp': new Date(2020, 4, 2, 21, 30).toISOString(),
|
||||
await createAnnotation({
|
||||
service: {
|
||||
version: '1.3',
|
||||
},
|
||||
'@timestamp': new Date(2020, 4, 2, 21, 30).toISOString(),
|
||||
})
|
||||
).status
|
||||
).to.be(200);
|
||||
|
||||
expect(
|
||||
(
|
||||
await request({
|
||||
url: `/api/apm/services/${serviceName}/annotation`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
service: {
|
||||
version: '1.4',
|
||||
environment: 'production',
|
||||
},
|
||||
'@timestamp': new Date(2020, 4, 2, 21, 31).toISOString(),
|
||||
await createAnnotation({
|
||||
service: {
|
||||
version: '1.4',
|
||||
environment: 'production',
|
||||
},
|
||||
'@timestamp': new Date(2020, 4, 2, 21, 31).toISOString(),
|
||||
})
|
||||
).status
|
||||
).to.be(200);
|
||||
|
@ -371,24 +383,27 @@ export default function annotationApiTests({ getService }: FtrProviderContext) {
|
|||
end: new Date(2020, 4, 2, 23).toISOString(),
|
||||
};
|
||||
|
||||
const allEnvironmentsResponse = await request({
|
||||
url: `/api/apm/services/${serviceName}/annotation/search?start=${range.start}&end=${range.end}&environment=ENVIRONMENT_ALL`,
|
||||
method: 'GET',
|
||||
const allEnvironmentsResponse = await getAnnotation({
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
environment: ENVIRONMENT_ALL.value,
|
||||
});
|
||||
|
||||
expect(allEnvironmentsResponse.body.annotations.length).to.be(2);
|
||||
|
||||
const productionEnvironmentResponse = await request({
|
||||
url: `/api/apm/services/${serviceName}/annotation/search?start=${range.start}&end=${range.end}&environment=production`,
|
||||
method: 'GET',
|
||||
const productionEnvironmentResponse = await getAnnotation({
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
environment: 'production',
|
||||
});
|
||||
|
||||
expect(productionEnvironmentResponse.body.annotations.length).to.be(1);
|
||||
expect(productionEnvironmentResponse.body.annotations[0].text).to.be('1.4');
|
||||
|
||||
const missingEnvironmentsResponse = await request({
|
||||
url: `/api/apm/services/${serviceName}/annotation/search?start=${range.start}&end=${range.end}&environment=ENVIRONMENT_NOT_DEFINED`,
|
||||
method: 'GET',
|
||||
const missingEnvironmentsResponse = await getAnnotation({
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
environment: ENVIRONMENT_NOT_DEFINED.value,
|
||||
});
|
||||
|
||||
expect(missingEnvironmentsResponse.body.annotations.length).to.be(1);
|
||||
|
|
|
@ -10,6 +10,7 @@ import { PrivilegeType } from '@kbn/apm-plugin/common/privilege_type';
|
|||
import { ApmUsername } from '@kbn/apm-plugin/server/test_helpers/create_apm_users/authentication';
|
||||
import { FtrProviderContext } from '../../../common/ftr_provider_context';
|
||||
import { ApmApiError, ApmApiSupertest } from '../../../common/apm_api_supertest';
|
||||
import { expectToReject } from '../../../common/utils/expect_to_reject';
|
||||
|
||||
export default function ApiTest({ getService }: FtrProviderContext) {
|
||||
const registry = getService('registry');
|
||||
|
@ -50,20 +51,24 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
() => {
|
||||
describe('When the user does not have the required cluster privileges', () => {
|
||||
it('should return an error when creating an agent key', async () => {
|
||||
const error = await expectToReject(() => createAgentKey(apmApiClient.writeUser));
|
||||
const error = await expectToReject<ApmApiError>(() =>
|
||||
createAgentKey(apmApiClient.writeUser)
|
||||
);
|
||||
expect(error.res.status).to.be(500);
|
||||
expect(error.res.body.message).contain('is missing the following requested privilege');
|
||||
});
|
||||
|
||||
it('should return an error when invalidating an agent key', async () => {
|
||||
const error = await expectToReject(() =>
|
||||
const error = await expectToReject<ApmApiError>(() =>
|
||||
invalidateAgentKey(apmApiClient.writeUser, agentKeyName)
|
||||
);
|
||||
expect(error.res.status).to.be(500);
|
||||
});
|
||||
|
||||
it('should return an error when getting a list of agent keys', async () => {
|
||||
const error = await expectToReject(() => getAgentKeys(apmApiClient.writeUser));
|
||||
const error = await expectToReject<ApmApiError>(() =>
|
||||
getAgentKeys(apmApiClient.writeUser)
|
||||
);
|
||||
expect(error.res.status).to.be(500);
|
||||
});
|
||||
});
|
||||
|
@ -71,7 +76,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
describe('When the user does not have the required application privileges', () => {
|
||||
allApplicationPrivileges.map((privilege) => {
|
||||
it(`should return an error when creating an agent key with ${privilege} privilege`, async () => {
|
||||
const error = await expectToReject(() =>
|
||||
const error = await expectToReject<ApmApiError>(() =>
|
||||
createAgentKey(apmApiClient.manageOwnAgentKeysUser, [privilege])
|
||||
);
|
||||
expect(error.res.status).to.be(500);
|
||||
|
@ -159,13 +164,4 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
});
|
||||
}
|
||||
);
|
||||
|
||||
async function expectToReject(fn: () => Promise<any>): Promise<ApmApiError> {
|
||||
try {
|
||||
await fn();
|
||||
} catch (e) {
|
||||
return e;
|
||||
}
|
||||
throw new Error(`Expected fn to throw`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,38 +6,50 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { ApmApiError } from '../../../common/apm_api_supertest';
|
||||
import { FtrProviderContext } from '../../../common/ftr_provider_context';
|
||||
import { expectToReject } from '../../../common/utils/expect_to_reject';
|
||||
|
||||
export default function apiTest({ getService }: FtrProviderContext) {
|
||||
const registry = getService('registry');
|
||||
const noAccessUser = getService('legacySupertestAsNoAccessUser');
|
||||
const apmApiClient = getService('apmApiClient');
|
||||
|
||||
function getJobs() {
|
||||
return noAccessUser.get(`/internal/apm/settings/anomaly-detection/jobs`).set('kbn-xsrf', 'foo');
|
||||
return apmApiClient.noAccessUser({
|
||||
endpoint: 'GET /internal/apm/settings/anomaly-detection/jobs',
|
||||
});
|
||||
}
|
||||
|
||||
function createJobs(environments: string[]) {
|
||||
return noAccessUser
|
||||
.post(`/internal/apm/settings/anomaly-detection/jobs`)
|
||||
.send({ environments })
|
||||
.set('kbn-xsrf', 'foo');
|
||||
return apmApiClient.noAccessUser({
|
||||
endpoint: 'POST /internal/apm/settings/anomaly-detection/jobs',
|
||||
params: {
|
||||
body: {
|
||||
environments,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
registry.when('ML jobs', { config: 'trial', archives: [] }, () => {
|
||||
describe('when user does not have read access to ML', () => {
|
||||
describe('when calling the endpoint for listing jobs', () => {
|
||||
it('returns an error because the user does not have access', async () => {
|
||||
const { body } = await getJobs();
|
||||
expect(body.statusCode).to.be(403);
|
||||
expect(body.error).to.be('Forbidden');
|
||||
const err = await expectToReject<ApmApiError>(() => getJobs());
|
||||
|
||||
expect(err.res.status).to.be(403);
|
||||
expect(err.res.body.message).eql('Forbidden');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when calling create endpoint', () => {
|
||||
it('returns an error because the user does not have access', async () => {
|
||||
const { body } = await createJobs(['production', 'staging']);
|
||||
expect(body.statusCode).to.be(403);
|
||||
expect(body.error).to.be('Forbidden');
|
||||
const err = await expectToReject<ApmApiError>(() =>
|
||||
createJobs(['production', 'staging'])
|
||||
);
|
||||
|
||||
expect(err.res.status).to.be(403);
|
||||
expect(err.res.body.message).eql('Forbidden');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue