[Synthetics] Port enablement API tests to Serverless (#179861)

## Summary

Related to #179100.

Sets up Synthetics API Integrations suite in Serverless Tests and adds
tests for the enablement endpoint.

Additional API test ports will be posted following up on this in the
coming days.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Justin Kambic 2024-04-04 12:23:58 -04:00 committed by GitHub
parent 526fd86743
commit 6a50dae95d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 221 additions and 0 deletions

1
.github/CODEOWNERS vendored
View file

@ -1109,6 +1109,7 @@ x-pack/plugins/observability_solution/infra/server/lib/alerting @elastic/obs-ux-
/x-pack/test/api_integration/apis/synthetics @elastic/obs-ux-infra_services-team
/x-pack/test/alerting_api_integration/observability/synthetics_rule.ts @elastic/obs-ux-infra_services-team
/x-pack/test/alerting_api_integration/observability/index.ts @elastic/obs-ux-management-team
/x-pack/test_serverless/api_integration/test_suites/observability/synthetics @elastic/obs-ux-infra_services-team
# Logs
/x-pack/test/api_integration/apis/logs_ui @elastic/obs-ux-logs-team

View file

@ -20,4 +20,6 @@ export default createTestConfig({
// include settings from project controller
// https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml
esServerArgs: ['xpack.ml.dfa.enabled=false', 'xpack.ml.nlp.enabled=false'],
// defined in MKI control plane
kbnServerArgs: ['--xpack.uptime.service.manifestUrl=mockDevUrl'],
});

View file

@ -18,5 +18,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./burn_rate_rule/burn_rate_rule'));
loadTestFile(require.resolve('./es_query_rule/es_query_rule'));
loadTestFile(require.resolve('./slos'));
loadTestFile(require.resolve('./synthetics'));
});
}

View file

@ -0,0 +1,21 @@
/*
* 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 { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ getService, loadTestFile }: FtrProviderContext) {
const esDeleteAllIndices = getService('esDeleteAllIndices');
describe('Synthetics API Tests', () => {
before(async () => {
await esDeleteAllIndices('heartbeat*');
await esDeleteAllIndices('synthetics*');
});
loadTestFile(require.resolve('./synthetics_enablement'));
});
}

View file

@ -0,0 +1,195 @@
/*
* 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 { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants';
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
interface CommonRequestHeader {
'kbn-xsrf': string;
}
type InternalRequestHeader = CommonRequestHeader & { 'x-elastic-internal-origin': string };
type RoleName = 'system_indices_superuser' | 'admin' | 'editor' | 'viewer';
const ALL_ENABLED = {
areApiKeysEnabled: true,
canManageApiKeys: true,
canEnable: true,
isEnabled: true,
isValidApiKey: true,
};
export default function ({ getService }: FtrProviderContext) {
const correctPrivileges = {
applications: [],
cluster: ['monitor', 'read_pipeline'],
indices: [
{
allow_restricted_indices: false,
names: ['synthetics-*'],
privileges: ['view_index_metadata', 'create_doc', 'auto_configure', 'read'],
},
],
metadata: {},
run_as: [],
transient_metadata: {
enabled: true,
},
};
describe('SyntheticsEnablement', () => {
const svlUserManager = getService('svlUserManager');
const svlCommonApi = getService('svlCommonApi');
const supertestWithoutAuth = getService('supertestWithoutAuth');
const esSupertest = getService('esSupertest');
const getApiKeys = async () => {
const { body } = await esSupertest.get(`/_security/api_key`).query({ with_limited_by: true });
const apiKeys = body.api_keys || [];
const filtered = apiKeys.filter(
(apiKey: any) => apiKey.name.includes('synthetics-api-key') && apiKey.invalidated === false
);
return filtered;
};
let internalRequestHeader: InternalRequestHeader;
before(async () => {
internalRequestHeader = svlCommonApi.getInternalRequestHeader();
});
async function enablementPut(role: RoleName = 'admin', expectedStatus: number = 200) {
return supertestWithoutAuth
.put(SYNTHETICS_API_URLS.SYNTHETICS_ENABLEMENT)
.set(internalRequestHeader)
.set(await svlUserManager.getApiCredentialsForRole(role))
.expect(expectedStatus);
}
async function enablementDelete(role: RoleName = 'admin', expectedStatus: number = 200) {
return supertestWithoutAuth
.delete(SYNTHETICS_API_URLS.SYNTHETICS_ENABLEMENT)
.set(internalRequestHeader)
.set(await svlUserManager.getApiCredentialsForRole(role))
.expect(expectedStatus);
}
describe('[PUT] /internal/uptime/service/enablement', () => {
const roles: RoleName[] = ['admin', 'editor', 'system_indices_superuser', 'viewer'];
roles.forEach((role) => {
it(`${role} role has appropriate permissions for API keys`, async () => {
if ((await getApiKeys()).length) {
await enablementDelete();
}
const { body } = await enablementPut(role);
if (['system_indices_superuser', 'admin'].indexOf(role) !== -1) {
expect(body).to.eql(ALL_ENABLED);
} else {
expect(body).to.eql({
areApiKeysEnabled: true,
canEnable: false,
canManageApiKeys: false,
isValidApiKey: false,
// api key is not there, as it's deleted at the start of the tests
isEnabled: false,
});
}
});
});
it(`returns response for an admin with privilege`, async () => {
if ((await getApiKeys()).length) {
await enablementDelete();
}
const { body } = await enablementPut();
expect(body).eql(ALL_ENABLED);
const validApiKeys = await getApiKeys();
expect(validApiKeys.length).eql(1);
expect(validApiKeys[0].role_descriptors.synthetics_writer).eql(correctPrivileges);
});
it(`does not create excess api keys`, async () => {
const apiKeysResult = await getApiKeys();
expect(apiKeysResult.length).to.be.lessThan(2);
if (apiKeysResult.length === 0) {
await enablementPut();
}
const apiResponse = await enablementPut();
expect(apiResponse.body).eql(ALL_ENABLED);
const validApiKeys = await getApiKeys();
expect(validApiKeys.length).eql(1);
expect(validApiKeys[0].role_descriptors.synthetics_writer).eql(correctPrivileges);
});
it(`auto re-enables api key when invalidated`, async () => {
const apiResponse = await enablementPut();
expect(apiResponse.body).eql(ALL_ENABLED);
const validApiKeys = await getApiKeys();
expect(validApiKeys.length).eql(1);
expect(validApiKeys[0].role_descriptors.synthetics_writer).eql(correctPrivileges);
// delete api key
await esSupertest
.delete(`/_security/api_key`)
.send({
ids: [validApiKeys[0].id],
})
.expect(200);
const validApiKeysAferDeletion = await getApiKeys();
expect(validApiKeysAferDeletion.length).eql(0);
// call api a second time
const apiResponse2 = await enablementPut();
expect(apiResponse2.body).eql(ALL_ENABLED);
const validApiKeys2 = await getApiKeys();
expect(validApiKeys2.length).eql(1);
expect(validApiKeys2[0].role_descriptors.synthetics_writer).eql(correctPrivileges);
});
});
describe('[DELETE] /internal/uptime/service/enablement', () => {
beforeEach(async () => {
const apiKeys = await getApiKeys();
if (apiKeys.length) {
await enablementDelete('system_indices_superuser');
}
});
it('admin can delete api key', async () => {
await enablementPut('system_indices_superuser');
const delResponse = await enablementDelete('system_indices_superuser');
expect(delResponse.body).eql({});
const apiResponse = await enablementPut();
expect(apiResponse.body).eql(ALL_ENABLED);
});
it('with an editor user', async () => {
await enablementPut();
await enablementDelete('editor', 403);
const apiResponse = await enablementPut('editor');
expect(apiResponse.body).eql({
areApiKeysEnabled: true,
canManageApiKeys: false,
canEnable: false,
isEnabled: true,
isValidApiKey: true,
});
});
});
});
}

View file

@ -97,5 +97,6 @@
"@kbn/share-plugin",
"@kbn/es-query",
"@kbn/utility-types",
"@kbn/synthetics-plugin",
]
}