Skip to content

Commit

Permalink
[Logs Onboarding] Added api integration tests (#160165)
Browse files Browse the repository at this point in the history
Relates to #159451.


This PR adds api integration tests to:

- [x] GET /internal/observability_onboarding/custom_logs/privileges
- [x] GET
/internal/observability_onboarding/custom_logs/install_shipper_setup
- [x] POST /internal/observability_onboarding/custom_logs/save

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
yngrdyn and kibanamachine authored Jun 26, 2023
1 parent 875d40d commit 39ddf4d
Show file tree
Hide file tree
Showing 24 changed files with 1,326 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .buildkite/ftr_configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ enabled:
- x-pack/test/observability_api_integration/trial/config.ts
- x-pack/test/observability_api_integration/apis/config.ts
- x-pack/test/observability_functional/with_rac_write.config.ts
- x-pack/test/observability_onboarding_api_integration/basic/config.ts
- x-pack/test/observability_onboarding_api_integration/cloud/config.ts
- x-pack/test/plugin_api_integration/config.ts
- x-pack/test/plugin_functional/config.ts
- x-pack/test/reporting_api_integration/reporting_and_security.config.ts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { CoreSetup, CoreStart } from '@kbn/core/public';
import type {
ClientRequestParamsOf,
ReturnOf,
RouteRepositoryClient,
} from '@kbn/server-route-repository';
Expand Down Expand Up @@ -40,6 +41,12 @@ export type APIReturnType<TEndpoint extends APIEndpoint> = ReturnOf<
TEndpoint
>;

export type APIClientRequestParamsOf<TEndpoint extends APIEndpoint> =
ClientRequestParamsOf<
ObservabilityOnboardingServerRouteRepository,
TEndpoint
>;

export let callObservabilityOnboardingApi: ObservabilityOnboardingClient =
() => {
throw new Error(
Expand Down
120 changes: 120 additions & 0 deletions x-pack/plugins/observability_onboarding/scripts/test/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* 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.
*/

/* eslint-disable no-console */
const { times } = require('lodash');
const yargs = require('yargs');
const path = require('path');
const childProcess = require('child_process');

const { argv } = yargs(process.argv.slice(2))
.option('basic', {
default: false,
type: 'boolean',
description: 'Run tests with basic license',
})
.option('cloud', {
default: false,
type: 'boolean',
description: 'Run tests with trial license',
})
.option('server', {
default: false,
type: 'boolean',
description: 'Only start ES and Kibana',
})
.option('runner', {
default: false,
type: 'boolean',
description: 'Only run tests',
})
.option('grep', {
alias: 'spec',
type: 'string',
description: 'Specify the specs to run',
})
.option('grep-files', {
alias: 'files',
type: 'array',
string: true,
description: 'Specify the files to run',
})
.option('times', {
type: 'number',
description: 'Repeat the test n number of times',
})
.option('updateSnapshots', {
default: false,
type: 'boolean',
description: 'Update snapshots',
})
.check((argv) => {
const { inspect, runner } = argv;
if (inspect && !runner) {
throw new Error('--inspect can only be used with --runner');
} else {
return true;
}
})
.help();

const { basic, cloud, server, runner, grep, grepFiles, updateSnapshots } = argv;

if (cloud === false && basic === false) {
throw new Error('Please specify either --basic or --cloud');
}

const license = basic ? 'basic' : 'cloud';

let ftrScript = 'functional_tests';
if (server) {
ftrScript = 'functional_tests_server';
} else if (runner) {
ftrScript = 'functional_test_runner';
}

const cmd = [
'node',
`../../../../../scripts/${ftrScript}`,
...(grep ? [`--grep "${grep}"`] : []),
...(updateSnapshots ? [`--updateSnapshots`] : []),
`--config ../../../../test/observability_onboarding_api_integration/${license}/config.ts`,
].join(' ');

console.log(`Running: "${cmd}"`);

function runTests() {
childProcess.execSync(cmd, {
cwd: path.join(__dirname),
stdio: 'inherit',
env: {
...process.env,
OBSERVABILITY_ONBOARDING_TEST_GREP_FILES: JSON.stringify(grepFiles),
},
});
}

if (argv.times) {
const runCounter = { succeeded: 0, failed: 0, remaining: argv.times };
let exitStatus = 0;
times(argv.times, () => {
try {
runTests();
runCounter.succeeded++;
} catch (e) {
exitStatus = 1;
runCounter.failed++;
}
runCounter.remaining--;
if (argv.times > 1) {
console.log(runCounter);
}
});
process.exit(exitStatus);
} else {
runTests();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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 {
cluster,
indices,
} from '../../routes/custom_logs/api_key/monitoring_config';

export enum ObservabilityOnboardingUsername {
noAccessUser = 'no_access_user',
viewerUser = 'viewer',
editorUser = 'editor',
logMonitoringUser = 'log_monitoring_user',
}

export enum ObservabilityOnboardingCustomRolename {
logMonitoringUser = 'log_monitoring_user',
}

export const customRoles = {
[ObservabilityOnboardingCustomRolename.logMonitoringUser]: {
elasticsearch: {
cluster: [...cluster, 'manage_own_api_key'],
indices,
},
},
};

export const users: Record<
ObservabilityOnboardingUsername,
{
builtInRoleNames?: string[];
customRoleNames?: ObservabilityOnboardingCustomRolename[];
}
> = {
[ObservabilityOnboardingUsername.noAccessUser]: {},
[ObservabilityOnboardingUsername.viewerUser]: {
builtInRoleNames: ['viewer'],
},
[ObservabilityOnboardingUsername.editorUser]: {
builtInRoleNames: ['editor'],
},
[ObservabilityOnboardingUsername.logMonitoringUser]: {
builtInRoleNames: ['editor'],
customRoleNames: [ObservabilityOnboardingCustomRolename.logMonitoringUser],
},
};

export const OBSERVABILITY_ONBOARDING_TEST_PASSWORD = 'changeme';
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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 axios, { AxiosRequestConfig, AxiosError } from 'axios';
import { once } from 'lodash';
import { Elasticsearch, Kibana } from '..';

export async function callKibana<T>({
elasticsearch,
kibana,
options,
}: {
elasticsearch: Omit<Elasticsearch, 'node'>;
kibana: Kibana;
options: AxiosRequestConfig;
}): Promise<T> {
const baseUrl = await getBaseUrl(kibana.hostname);
const { username, password } = elasticsearch;

const { data } = await axios.request({
...options,
baseURL: baseUrl,
auth: { username, password },
headers: { 'kbn-xsrf': 'true', ...options.headers },
});
return data;
}

const getBaseUrl = once(async (kibanaHostname: string) => {
try {
await axios.request({ url: kibanaHostname, maxRedirects: 0 });
} catch (e) {
if (isAxiosError(e)) {
const location = e.response?.headers?.location ?? '';
const hasBasePath = RegExp(/^\/\w{3}$/).test(location);
const basePath = hasBasePath ? location : '';
return `${kibanaHostname}${basePath}`;
}

throw e;
}
return kibanaHostname;
});

export function isAxiosError(e: AxiosError | Error): e is AxiosError {
return 'isAxiosError' in e;
}

export class AbortError extends Error {
constructor(message: string) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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 { Elasticsearch, Kibana } from '..';
import { callKibana } from './call_kibana';
import {
customRoles,
ObservabilityOnboardingCustomRolename,
} from '../authentication';

export async function createCustomRole({
elasticsearch,
kibana,
roleName,
}: {
elasticsearch: Elasticsearch;
kibana: Kibana;
roleName: ObservabilityOnboardingCustomRolename;
}) {
const role = customRoles[roleName];

await callKibana({
elasticsearch,
kibana,
options: {
method: 'PUT',
url: `/api/security/role/${roleName}`,
data: role,
},
});
}
Loading

0 comments on commit 39ddf4d

Please sign in to comment.