[APM] Add e2e tests for storage explorer (#141959)

* Refactor APM user creation and add tests for storage explorer
This commit is contained in:
Giorgos Bamparopoulos 2022-09-29 09:05:12 +01:00 committed by GitHub
parent 6a0b2fd717
commit e3bf5539a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 370 additions and 165 deletions

View file

@ -0,0 +1,192 @@
/*
* 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 moment from 'moment';
import url from 'url';
import { synthtrace } from '../../../../synthtrace';
import { opbeans } from '../../../fixtures/synthtrace/opbeans';
import { checkA11y } from '../../../support/commands';
const timeRange = {
rangeFrom: '2021-10-10T00:00:00.000Z',
rangeTo: '2021-10-10T00:15:00.000Z',
};
const storageExplorerHref = url.format({
pathname: '/app/apm/storage-explorer',
query: timeRange,
});
const mainApiRequestsToIntercept = [
{
endpoint: '/internal/apm/storage_chart',
aliasName: 'storageChartRequest',
},
{
endpoint: '/internal/apm/storage_explorer_summary_stats',
aliasName: 'summaryStatsRequest',
},
{
endpoint: '/internal/apm/storage_explorer',
aliasName: 'storageExlorerRequest',
},
];
const mainAliasNames = mainApiRequestsToIntercept.map(
({ aliasName }) => `@${aliasName}`
);
describe('Storage Explorer', () => {
before(() => {
const { rangeFrom, rangeTo } = timeRange;
synthtrace.index(
opbeans({
from: new Date(rangeFrom).getTime(),
to: new Date(rangeTo).getTime(),
})
);
});
after(() => {
synthtrace.clean();
});
describe('When navigating to storage explorer without the required permissions', () => {
beforeEach(() => {
cy.loginAsViewerUser();
cy.visitKibana(storageExplorerHref);
});
it('displays a prompt for permissions', () => {
cy.contains('You need permission');
});
});
describe('When navigating to storage explorer with the required permissions', () => {
beforeEach(() => {
cy.loginAsMonitorUser();
cy.visitKibana(storageExplorerHref);
});
it('has no detectable a11y violations on load', () => {
cy.contains('h1', 'Storage explorer');
// set skipFailures to true to not fail the test when there are accessibility failures
checkA11y({ skipFailures: true });
});
it('has a list of summary stats', () => {
cy.contains('Total APM size');
cy.contains('Daily data generation');
cy.contains('Traces per minute');
cy.contains('Number of services');
});
it('renders the storage timeseries chart', () => {
cy.get('[data-test-subj="storageExplorerTimeseriesChart"]');
});
it('has a list of services and environments', () => {
cy.contains('opbeans-node');
cy.contains('opbeans-java');
cy.contains('opbeans-rum');
cy.get('td:contains(production)').should('have.length', 3);
});
it('when clicking on a service it loads the service overview for that service', () => {
cy.contains('opbeans-node').click({ force: true });
cy.url().should('include', '/apm/services/opbeans-node/overview');
cy.contains('h1', 'opbeans-node');
});
});
describe('Calls APIs', () => {
beforeEach(() => {
mainApiRequestsToIntercept.forEach(({ endpoint, aliasName }) => {
cy.intercept({ pathname: endpoint }).as(aliasName);
});
cy.loginAsMonitorUser();
cy.visitKibana(storageExplorerHref);
});
it('with the correct environment when changing the environment', () => {
cy.wait(mainAliasNames);
cy.get('[data-test-subj="environmentFilter"]').type('production');
cy.contains('button', 'production').click({ force: true });
cy.expectAPIsToHaveBeenCalledWith({
apisIntercepted: mainAliasNames,
value: 'environment=production',
});
});
it('when clicking the refresh button', () => {
cy.wait(mainAliasNames);
cy.contains('Refresh').click();
cy.wait(mainAliasNames);
});
it('when selecting a different time range and clicking the update button', () => {
cy.wait(mainAliasNames);
cy.selectAbsoluteTimeRange(
moment(timeRange.rangeFrom).subtract(5, 'm').toISOString(),
moment(timeRange.rangeTo).subtract(5, 'm').toISOString()
);
cy.contains('Update').click();
cy.wait(mainAliasNames);
cy.contains('Refresh').click();
cy.wait(mainAliasNames);
});
it('with the correct lifecycle phase when changing the lifecycle phase', () => {
cy.wait(mainAliasNames);
cy.get('[data-test-subj="storageExplorerLifecyclePhaseSelect"]').click();
cy.contains('button', 'Warm').click();
cy.expectAPIsToHaveBeenCalledWith({
apisIntercepted: mainAliasNames,
value: 'indexLifecyclePhase=warm',
});
});
});
describe('Storage details per service', () => {
beforeEach(() => {
const apiRequestsToIntercept = [
...mainApiRequestsToIntercept,
{
endpoint: '/internal/apm/services/opbeans-node/storage_details',
aliasName: 'storageDetailsRequest',
},
];
apiRequestsToIntercept.forEach(({ endpoint, aliasName }) => {
cy.intercept({ pathname: endpoint }).as(aliasName);
});
cy.loginAsMonitorUser();
cy.visitKibana(storageExplorerHref);
});
it('shows storage details', () => {
cy.wait(mainAliasNames);
cy.contains('opbeans-node');
cy.get('[data-test-subj="storageDetailsButton_opbeans-node"]').click();
cy.get('[data-test-subj="loadingSpinner"]').should('be.visible');
cy.wait('@storageDetailsRequest');
cy.contains('Service storage details');
cy.get('[data-test-subj="storageExplorerTimeseriesChart"]');
cy.get('[data-test-subj="serviceStorageDetailsTable"]');
});
});
});

View file

@ -9,13 +9,21 @@ import { Interception } from 'cypress/types/net-stubbing';
import 'cypress-axe';
import moment from 'moment';
import { AXE_CONFIG, AXE_OPTIONS } from '@kbn/axe-config';
import { ApmUsername } from '../../../server/test_helpers/create_apm_users/authentication';
Cypress.Commands.add('loginAsViewerUser', () => {
return cy.loginAs({ username: 'viewer', password: 'changeme' });
return cy.loginAs({ username: ApmUsername.viewerUser, password: 'changeme' });
});
Cypress.Commands.add('loginAsEditorUser', () => {
return cy.loginAs({ username: 'editor', password: 'changeme' });
return cy.loginAs({ username: ApmUsername.editorUser, password: 'changeme' });
});
Cypress.Commands.add('loginAsMonitorUser', () => {
return cy.loginAs({
username: ApmUsername.apmMonitorIndices,
password: 'changeme',
});
});
Cypress.Commands.add(

View file

@ -9,6 +9,7 @@ declare namespace Cypress {
interface Chainable {
loginAsViewerUser(): Cypress.Chainable<Cypress.Response<any>>;
loginAsEditorUser(): Cypress.Chainable<Cypress.Response<any>>;
loginAsMonitorUser(): Cypress.Chainable<Cypress.Response<any>>;
loginAs(params: {
username: string;
password: string;

View file

@ -11,7 +11,7 @@ import { esTestConfig } from '@kbn/test';
import { apm, createLogger, LogLevel } from '@kbn/apm-synthtrace';
import path from 'path';
import { FtrProviderContext } from './ftr_provider_context';
import { createApmUsers } from '../scripts/create_apm_users/create_apm_users';
import { createApmUsers } from '../server/test_helpers/create_apm_users/create_apm_users';
export async function cypressTestRunner({ getService }: FtrProviderContext) {
const config = getService('config');
@ -26,12 +26,6 @@ export async function cypressTestRunner({ getService }: FtrProviderContext) {
const username = config.get('servers.elasticsearch.username');
const password = config.get('servers.elasticsearch.password');
// Creates APM users
await createApmUsers({
elasticsearch: { username, password },
kibana: { hostname: kibanaUrl },
});
const esNode = Url.format({
protocol: config.get('servers.elasticsearch.protocol'),
port: config.get('servers.elasticsearch.port'),
@ -39,6 +33,12 @@ export async function cypressTestRunner({ getService }: FtrProviderContext) {
auth: `${username}:${password}`,
});
// Creates APM users
await createApmUsers({
elasticsearch: { node: esNode, username, password },
kibana: { hostname: kibanaUrl },
});
const esRequestTimeout = config.get('timeouts.esRequestTimeout');
const kibanaClient = new apm.ApmSynthtraceKibanaClient(
createLogger(LogLevel.info)

View file

@ -18,5 +18,6 @@
"references": [
{ "path": "../../../test/tsconfig.json" },
{ "path": "../../../../test/tsconfig.json" },
{ "path": "../tsconfig.json" },
]
}

View file

@ -130,6 +130,7 @@ export function IndexLifecyclePhaseSelect() {
}}
hasDividers
style={{ minWidth: 200 }}
data-test-subj="storageExplorerLifecyclePhaseSelect"
/>
);
}

View file

@ -186,7 +186,10 @@ export function StorageDetailsPerService({
<EuiFlexItem>
<EuiFlexGroup justifyContent="spaceBetween" gutterSize="m">
<EuiFlexItem>
<EuiPanel hasShadow={false}>
<EuiPanel
hasShadow={false}
data-test-subj="serviceStorageDetailsChart"
>
<Chart>
<Settings
theme={[
@ -224,7 +227,11 @@ export function StorageDetailsPerService({
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiPanel hasShadow={false} paddingSize="l">
<EuiPanel
hasShadow={false}
paddingSize="l"
data-test-subj="serviceStorageDetailsTable"
>
{processorEventStats.map(
({ processorEventLabel, docs, size }) => (
<>

View file

@ -8,13 +8,17 @@
/* eslint-disable no-console */
import { argv } from 'yargs';
import { AbortError, isAxiosError } from './helpers/call_kibana';
import { createApmUsers } from './create_apm_users';
import { getKibanaVersion } from './helpers/get_version';
import {
AbortError,
isAxiosError,
} from '../../server/test_helpers/create_apm_users/helpers/call_kibana';
import { createApmUsers } from '../../server/test_helpers/create_apm_users/create_apm_users';
import { getKibanaVersion } from '../../server/test_helpers/create_apm_users/helpers/get_version';
async function init() {
const esUserName = (argv.username as string) || 'elastic';
const esPassword = argv.password as string | undefined;
const esUrl = argv.esUrl as string | undefined;
const kibanaBaseUrl = argv.kibanaUrl as string | undefined;
if (!esPassword) {
@ -24,6 +28,20 @@ async function init() {
process.exit();
}
if (!esUrl) {
console.error(
'Please specify the url for elasticsearch: `--es-url http://localhost:9200` '
);
process.exit();
}
if (!esUrl.startsWith('https://') && !esUrl.startsWith('http://')) {
console.error(
'Elasticsearch url must be prefixed with http(s):// `--es-url http://localhost:9200`'
);
process.exit();
}
if (!kibanaBaseUrl) {
console.error(
'Please specify the url for Kibana: `--kibana-url http://localhost:5601` '
@ -42,7 +60,11 @@ async function init() {
}
const kibana = { hostname: kibanaBaseUrl };
const elasticsearch = { username: esUserName, password: esPassword };
const elasticsearch = {
node: esUrl,
username: esUserName,
password: esPassword,
};
console.log({ kibana, elasticsearch });
@ -50,9 +72,7 @@ async function init() {
console.log(`Connected to Kibana ${version}`);
const users = await createApmUsers({ elasticsearch, kibana });
const credentials = users
.map((u) => ` - ${u.username} / ${esPassword}`)
.join('\n');
const credentials = users.map((u) => ` - ${u} / ${esPassword}`).join('\n');
console.log(
`\nYou can now login to ${kibana.hostname} with:\n${credentials}`

View file

@ -5,15 +5,7 @@
* 2.0.
*/
import { Client } from '@elastic/elasticsearch';
import { PrivilegeType } from '@kbn/apm-plugin/common/privilege_type';
import { ToolingLog } from '@kbn/tooling-log';
import { omit } from 'lodash';
import { KbnClientRequesterError } from '@kbn/test';
import { AxiosError } from 'axios';
import { SecurityServiceProvider } from '../../../../test/common/services/security';
type SecurityService = Awaited<ReturnType<typeof SecurityServiceProvider>>;
import { PrivilegeType } from '../../../common/privilege_type';
export enum ApmUsername {
noAccessUser = 'no_access_user',
@ -34,7 +26,7 @@ export enum ApmCustomRolename {
apmMonitorIndices = 'apm_monitor_indices',
}
const customRoles = {
export const customRoles = {
[ApmCustomRolename.apmReadUserWithoutMlAccess]: {
elasticsearch: {
cluster: [],
@ -97,7 +89,7 @@ const customRoles = {
},
};
const users: Record<
export const users: Record<
ApmUsername,
{ builtInRoleNames?: string[]; customRoleNames?: ApmCustomRolename[] }
> = {
@ -132,70 +124,4 @@ const users: Record<
},
};
function logErrorResponse(logger: ToolingLog, e: Error) {
if (e instanceof KbnClientRequesterError) {
logger.error(`KbnClientRequesterError: ${JSON.stringify(e.axiosError?.response?.data)}`);
} else if (e instanceof AxiosError) {
logger.error(`AxiosError: ${JSON.stringify(e.response?.data)}`);
} else {
logger.error(`Unknown error: ${e.constructor.name}`);
}
}
export async function createApmUser({
username,
security,
es,
logger,
}: {
username: ApmUsername;
security: SecurityService;
es: Client;
logger: ToolingLog;
}) {
const user = users[username];
if (!user) {
throw new Error(`No configuration found for ${username}`);
}
const { builtInRoleNames = [], customRoleNames = [] } = user;
try {
// create custom roles
await Promise.all(
customRoleNames.map(async (roleName) => createCustomRole({ roleName, security, es }))
);
// create user
await security.user.create(username, {
full_name: username,
password: APM_TEST_PASSWORD,
roles: [...builtInRoleNames, ...customRoleNames],
});
} catch (e) {
logErrorResponse(logger, e);
throw e;
}
}
async function createCustomRole({
roleName,
security,
es,
}: {
roleName: ApmCustomRolename;
security: SecurityService;
es: Client;
}) {
const role = customRoles[roleName];
// Add application privileges with es client as they are not supported by
// security.user.create. They are preserved when updating the role below
if ('applications' in role) {
await es.security.putRole({ name: roleName, body: role });
}
await security.role.create(roleName, omit(role, 'applications'));
}
export const APM_TEST_PASSWORD = 'changeme';

View file

@ -5,10 +5,13 @@
* 2.0.
*/
import { asyncForEach } from '@kbn/std';
import { AbortError, callKibana } from './helpers/call_kibana';
import { createOrUpdateUser } from './helpers/create_or_update_user';
import { ApmUsername, users } from './authentication';
import { createCustomRole } from './helpers/create_custom_role';
export interface Elasticsearch {
node: string;
username: string;
password: string;
}
@ -28,6 +31,7 @@ export async function createApmUsers({
elasticsearch,
kibana,
});
if (!isCredentialsValid) {
throw new AbortError('Invalid username/password');
}
@ -36,24 +40,33 @@ export async function createApmUsers({
elasticsearch,
kibana,
});
if (!isSecurityEnabled) {
throw new AbortError('Security must be enabled!');
}
// user definitions
const users = [
{ username: 'viewer', roles: ['viewer'] },
{ username: 'editor', roles: ['editor'] },
];
const apmUsers = Object.values(ApmUsername);
await asyncForEach(apmUsers, async (username) => {
const user = users[username];
const { builtInRoleNames = [], customRoleNames = [] } = user;
// create users
await Promise.all(
users.map(async (user) =>
createOrUpdateUser({ elasticsearch, kibana, user })
)
);
// create custom roles
await Promise.all(
customRoleNames.map(async (roleName) =>
createCustomRole({ elasticsearch, kibana, roleName })
)
);
return users;
// create user
const roles = builtInRoleNames.concat(customRoleNames);
await createOrUpdateUser({
elasticsearch,
kibana,
user: { username, roles },
});
});
return apmUsers;
}
async function getIsSecurityEnabled({

View file

@ -13,7 +13,7 @@ export async function callKibana<T>({
kibana,
options,
}: {
elasticsearch: Elasticsearch;
elasticsearch: Omit<Elasticsearch, 'node'>;
kibana: Kibana;
options: AxiosRequestConfig;
}): Promise<T> {

View file

@ -0,0 +1,60 @@
/*
* 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 { Client } from '@elastic/elasticsearch';
import { omit } from 'lodash';
import { Elasticsearch, Kibana } from '../create_apm_users';
import { callKibana } from './call_kibana';
import { customRoles, ApmCustomRolename } from '../authentication';
export async function createCustomRole({
elasticsearch,
kibana,
roleName,
}: {
elasticsearch: Elasticsearch;
kibana: Kibana;
roleName: ApmCustomRolename;
}) {
const role = customRoles[roleName];
// Add application privileges with es client as they are not supported by
// the security API. They are preserved when updating the role below
if ('applications' in role) {
const esClient = getEsClient(elasticsearch);
await esClient.security.putRole({ name: roleName, body: role });
}
await callKibana({
elasticsearch,
kibana,
options: {
method: 'PUT',
url: `/api/security/role/${roleName}`,
data: {
...omit(role, 'applications'),
},
},
});
}
export function getEsClient(elasticsearch: Elasticsearch) {
const { node, username, password } = elasticsearch;
const client = new Client({
node,
tls: {
rejectUnauthorized: false,
},
requestTimeout: 120000,
auth: {
username,
password,
},
});
return client;
}

View file

@ -13,7 +13,7 @@ export async function getKibanaVersion({
elasticsearch,
kibana,
}: {
elasticsearch: Elasticsearch;
elasticsearch: Omit<Elasticsearch, 'node'>;
kibana: Kibana;
}) {
try {

View file

@ -10,7 +10,7 @@
import Url from 'url';
import { run as syntheticsRun } from '@elastic/synthetics';
import { PromiseType } from 'utility-types';
import { createApmUsers } from '@kbn/apm-plugin/scripts/create_apm_users/create_apm_users';
import { createApmUsers } from '@kbn/apm-plugin/server/test_helpers/create_apm_users/create_apm_users';
import { esArchiverUnload } from './tasks/es_archiver';
@ -23,6 +23,7 @@ export interface ArgParams {
export class SyntheticsRunner {
public getService: any;
public kibanaUrl: string;
private elasticsearchUrl: string;
public testFilesLoaded: boolean = false;
@ -31,6 +32,7 @@ export class SyntheticsRunner {
constructor(getService: any, params: ArgParams) {
this.getService = getService;
this.kibanaUrl = this.getKibanaUrl();
this.elasticsearchUrl = this.getElasticsearchUrl();
this.params = params;
}
@ -40,7 +42,7 @@ export class SyntheticsRunner {
async createTestUsers() {
await createApmUsers({
elasticsearch: { username: 'elastic', password: 'changeme' },
elasticsearch: { node: this.elasticsearchUrl, username: 'elastic', password: 'changeme' },
kibana: { hostname: this.kibanaUrl },
});
}
@ -79,6 +81,16 @@ export class SyntheticsRunner {
});
}
getElasticsearchUrl() {
const config = this.getService('config');
return Url.format({
protocol: config.get('servers.elasticsearch.protocol'),
hostname: config.get('servers.elasticsearch.hostname'),
port: config.get('servers.elasticsearch.port'),
});
}
async run() {
if (!this.testFilesLoaded) {
throw new Error('Test files not loaded');

View file

@ -6,7 +6,7 @@
*/
import { journey, step, expect, before } from '@elastic/synthetics';
import { callKibana } from '@kbn/apm-plugin/scripts/create_apm_users/helpers/call_kibana';
import { callKibana } from '@kbn/apm-plugin/server/test_helpers/create_apm_users/helpers/call_kibana';
import { byTestId, waitForLoadingToFinish } from '@kbn/observability-plugin/e2e/utils';
import { loginPageProvider } from '../page_objects/login';

View file

@ -7,7 +7,7 @@
import { apm, createLogger, LogLevel } from '@kbn/apm-synthtrace';
import { esTestConfig } from '@kbn/test';
import { APM_TEST_PASSWORD } from './authentication';
import { APM_TEST_PASSWORD } from '@kbn/apm-plugin/server/test_helpers/create_apm_users/authentication';
import { InheritedFtrProviderContext } from './ftr_provider_context';
export async function bootstrapApmSynthtrace(

View file

@ -8,11 +8,12 @@
import { FtrConfigProviderContext } from '@kbn/test';
import supertest from 'supertest';
import { format, UrlObject } from 'url';
import { Client } from '@elastic/elasticsearch';
import { ToolingLog } from '@kbn/tooling-log';
import { SecurityServiceProvider } from '../../../../test/common/services/security';
import {
ApmUsername,
APM_TEST_PASSWORD,
} from '@kbn/apm-plugin/server/test_helpers/create_apm_users/authentication';
import { createApmUsers } from '@kbn/apm-plugin/server/test_helpers/create_apm_users/create_apm_users';
import { InheritedFtrProviderContext, InheritedServices } from './ftr_provider_context';
import { createApmUser, APM_TEST_PASSWORD, ApmUsername } from './authentication';
import { APMFtrConfigName } from '../configs';
import { createApmApiClient } from './apm_api_supertest';
import { RegistryProvider } from './registry';
@ -25,17 +26,8 @@ export interface ApmFtrConfig {
kibanaConfig?: Record<string, string | string[]>;
}
type SecurityService = Awaited<ReturnType<typeof SecurityServiceProvider>>;
function getLegacySupertestClient(kibanaServer: UrlObject, username: ApmUsername) {
return async (context: InheritedFtrProviderContext) => {
const security = context.getService('security');
const es = context.getService('es');
const logger = context.getService('log');
await security.init();
await createApmUser({ security, username, es, logger });
const url = format({
...kibanaServer,
auth: `${username}:${APM_TEST_PASSWORD}`,
@ -47,19 +39,11 @@ function getLegacySupertestClient(kibanaServer: UrlObject, username: ApmUsername
async function getApmApiClient({
kibanaServer,
security,
username,
es,
logger,
}: {
kibanaServer: UrlObject;
security: SecurityService;
username: ApmUsername;
es: Client;
logger: ToolingLog;
}) {
await createApmUser({ security, username, es, logger });
const url = format({
...kibanaServer,
auth: `${username}:${APM_TEST_PASSWORD}`,
@ -81,6 +65,8 @@ export function createTestConfig(config: ApmFtrConfig) {
const services = xPackAPITestsConfig.get('services') as InheritedServices;
const servers = xPackAPITestsConfig.get('servers');
const kibanaServer = servers.kibana as UrlObject;
const kibanaServerUrl = format(kibanaServer);
const esServer = servers.elasticsearch as UrlObject;
return {
testFiles: [require.resolve('../tests')],
@ -91,72 +77,50 @@ export function createTestConfig(config: ApmFtrConfig) {
apmFtrConfig: () => config,
registry: RegistryProvider,
synthtraceEsClient: (context: InheritedFtrProviderContext) => {
const kibanaServerUrl = format(kibanaServer);
return bootstrapApmSynthtrace(context, kibanaServerUrl);
},
apmApiClient: async (context: InheritedFtrProviderContext) => {
const security = context.getService('security');
const es = context.getService('es');
const logger = context.getService('log');
const { username, password } = servers.kibana;
const esUrl = format(esServer);
await security.init();
// Creates APM users
await createApmUsers({
elasticsearch: { node: esUrl, username, password },
kibana: { hostname: kibanaServerUrl },
});
return {
noAccessUser: await getApmApiClient({
kibanaServer,
security,
username: ApmUsername.noAccessUser,
es,
logger,
}),
readUser: await getApmApiClient({
kibanaServer,
security,
username: ApmUsername.viewerUser,
es,
logger,
}),
writeUser: await getApmApiClient({
kibanaServer,
security,
username: ApmUsername.editorUser,
es,
logger,
}),
annotationWriterUser: await getApmApiClient({
kibanaServer,
security,
username: ApmUsername.apmAnnotationsWriteUser,
es,
logger,
}),
noMlAccessUser: await getApmApiClient({
kibanaServer,
security,
username: ApmUsername.apmReadUserWithoutMlAccess,
es,
logger,
}),
manageOwnAgentKeysUser: await getApmApiClient({
kibanaServer,
security,
username: ApmUsername.apmManageOwnAgentKeys,
es,
logger,
}),
createAndAllAgentKeysUser: await getApmApiClient({
kibanaServer,
security,
username: ApmUsername.apmManageOwnAndCreateAgentKeys,
es,
logger,
}),
monitorIndicesUser: await getApmApiClient({
kibanaServer,
security,
username: ApmUsername.apmMonitorIndices,
es,
logger,
}),
};
},

View file

@ -7,9 +7,9 @@
import expect from '@kbn/expect';
import { first } from 'lodash';
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 { ApmUsername } from '../../../common/authentication';
export default function ApiTest({ getService }: FtrProviderContext) {
const registry = getService('registry');