From 489ddc488acc39b2fa0c4d5baf36162cc5bea9d2 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 12 Aug 2020 17:05:32 -0700 Subject: [PATCH] Migrated last pieces of legacy fixture code (#74470) (#74904) * Migrated last pieces of legacy fixture code * Implemented own server for webhook simulator * Fixed type checks. Moved slack simulator to own server * close server after tests run * Fixed due to comments * fixed failing tests --- x-pack/package.json | 4 +- .../actions/builtin_action_types/slack.ts | 25 ++-- .../actions/builtin_action_types/webhook.ts | 25 ++-- .../actions_simulators/server/plugin.ts | 11 ++ .../server/slack_simulation.ts | 69 +++++++++++ .../server/webhook_simulation.ts | 88 ++++++++++++++ .../actions_simulators_legacy/index.ts | 26 ---- .../actions_simulators_legacy/package.json | 7 -- .../slack_simulation.ts | 74 ------------ .../webhook_simulation.ts | 112 ------------------ .../actions/builtin_action_types/slack.ts | 25 ++-- .../actions/builtin_action_types/webhook.ts | 53 +++++++-- .../actions/builtin_action_types/webhook.ts | 30 ++--- yarn.lock | 2 +- 14 files changed, 269 insertions(+), 282 deletions(-) create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/slack_simulation.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/webhook_simulation.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/slack_simulation.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/webhook_simulation.ts diff --git a/x-pack/package.json b/x-pack/package.json index f2dc0b55bfa35e..aee5811ee52810 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -256,8 +256,8 @@ "cronstrue": "^1.51.0", "cytoscape": "^3.10.0", "d3": "3.5.17", - "d3-scale": "1.0.7", "d3-array": "1.2.4", + "d3-scale": "1.0.7", "dedent": "^0.7.0", "del": "^5.1.0", "dragselect": "1.13.1", @@ -268,7 +268,7 @@ "font-awesome": "4.7.0", "formsy-react": "^1.1.5", "fp-ts": "^2.3.1", - "get-port": "4.2.0", + "get-port": "^4.2.0", "getos": "^3.1.0", "git-url-parse": "11.1.2", "github-markdown-css": "^2.10.0", diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts index 90660cc99507d3..91511b508aca67 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts @@ -4,26 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ +import http from 'http'; +import getPort from 'get-port'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { - getExternalServiceSimulatorPath, - ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; +import { getSlackServer } from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // eslint-disable-next-line import/no-default-export export default function slackTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - const kibanaServer = getService('kibanaServer'); describe('slack action', () => { - let slackSimulatorURL: string = ''; + let slackSimulatorURL: string = ''; + let slackServer: http.Server; - // need to wait for kibanaServer to settle ... - before(() => { - slackSimulatorURL = kibanaServer.resolveUrl( - getExternalServiceSimulatorPath(ExternalServiceSimulator.SLACK) - ); + before(async () => { + slackServer = await getSlackServer(); + const availablePort = await getPort({ port: 9000 }); + slackServer.listen(availablePort); + slackSimulatorURL = `http://localhost:${availablePort}`; }); it('should return 403 when creating a slack action', async () => { @@ -44,5 +43,9 @@ export default function slackTest({ getService }: FtrProviderContext) { 'Action type .slack is disabled because your basic license does not support it. Please upgrade your license.', }); }); + + after(() => { + slackServer.close(); + }); }); } diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts index af1d413ff3c462..039f1d4dd3275d 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts @@ -4,25 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ +import http from 'http'; +import getPort from 'get-port'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { - getExternalServiceSimulatorPath, - ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; +import { getWebhookServer } from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // eslint-disable-next-line import/no-default-export export default function webhookTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - const kibanaServer = getService('kibanaServer'); describe('webhook action', () => { - let webhookSimulatorURL: string = ''; - + let webhookSimulatorURL: string = ''; + let webhookServer: http.Server; // need to wait for kibanaServer to settle ... - before(() => { - webhookSimulatorURL = kibanaServer.resolveUrl( - getExternalServiceSimulatorPath(ExternalServiceSimulator.WEBHOOK) - ); + before(async () => { + webhookServer = await getWebhookServer(); + const availablePort = await getPort({ port: 9000 }); + webhookServer.listen(availablePort); + webhookSimulatorURL = `http://localhost:${availablePort}`; }); it('should return 403 when creating a webhook action', async () => { @@ -47,5 +46,9 @@ export default function webhookTest({ getService }: FtrProviderContext) { 'Action type .webhook is disabled because your basic license does not support it. Please upgrade your license.', }); }); + + after(() => { + webhookServer.close(); + }); }); } diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts index cb1271494c294e..0f7acf5ead1a18 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import http from 'http'; import { Plugin, CoreSetup, IRouter } from 'kibana/server'; import { EncryptedSavedObjectsPluginStart } from '../../../../../../../plugins/encrypted_saved_objects/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../../../../../../plugins/features/server'; @@ -13,6 +14,8 @@ import { initPlugin as initPagerduty } from './pagerduty_simulation'; import { initPlugin as initServiceNow } from './servicenow_simulation'; import { initPlugin as initJira } from './jira_simulation'; import { initPlugin as initResilient } from './resilient_simulation'; +import { initPlugin as initSlack } from './slack_simulation'; +import { initPlugin as initWebhook } from './webhook_simulation'; export const NAME = 'actions-FTS-external-service-simulators'; @@ -39,6 +42,14 @@ export function getAllExternalServiceSimulatorPaths(): string[] { return allPaths; } +export async function getWebhookServer(): Promise { + return await initWebhook(); +} + +export async function getSlackServer(): Promise { + return await initSlack(); +} + interface FixtureSetupDeps { actions: ActionsPluginSetupContract; features: FeaturesPluginSetup; diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/slack_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/slack_simulation.ts new file mode 100644 index 00000000000000..5032112e702e25 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/slack_simulation.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import http from 'http'; + +export async function initPlugin() { + return http.createServer((request, response) => { + if (request.method === 'POST') { + let data = ''; + request.on('data', (chunk) => { + data += chunk; + }); + request.on('end', () => { + const body = JSON.parse(data); + const text = body && body.text; + + if (text == null) { + response.statusCode = 400; + response.end('bad request to slack simulator'); + return; + } + + switch (text) { + case 'success': { + response.statusCode = 200; + response.end('ok'); + return; + } + case 'no_text': + response.statusCode = 400; + response.end('no_text'); + return; + + case 'invalid_payload': + response.statusCode = 400; + response.end('invalid_payload'); + return; + + case 'invalid_token': + response.statusCode = 403; + response.end('invalid_token'); + return; + + case 'status_500': + response.statusCode = 500; + response.end('simulated slack 500 response'); + return; + + case 'rate_limit': + const res = { + retry_after: 1, + ok: false, + error: 'rate_limited', + }; + + response.writeHead(429, { 'Content-Type': 'application/json', 'Retry-After': '1' }); + response.write(JSON.stringify(res)); + response.end(); + return; + } + response.statusCode = 400; + response.end('unknown request to slack simulator'); + }); + } + }); +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/webhook_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/webhook_simulation.ts new file mode 100644 index 00000000000000..44d8ea0c2da20c --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/webhook_simulation.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import expect from '@kbn/expect'; +import http from 'http'; +import { fromNullable, map, filter, getOrElse } from 'fp-ts/lib/Option'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { constant } from 'fp-ts/lib/function'; + +export async function initPlugin() { + return http.createServer((request, response) => { + const credentials = pipe( + fromNullable(request.headers.authorization), + map((authorization) => authorization.split(/\s+/)), + filter((parts) => parts.length > 1), + map((parts) => Buffer.from(parts[1], 'base64').toString()), + filter((credentialsPart) => credentialsPart.indexOf(':') !== -1), + map((credentialsPart) => { + const [username, password] = credentialsPart.split(':'); + return { username, password }; + }), + getOrElse(constant({ username: '', password: '' })) + ); + + if (request.method === 'POST' || request.method === 'PUT') { + let data = ''; + request.on('data', (chunk) => { + data += chunk; + }); + request.on('end', () => { + switch (data) { + case 'success': + response.statusCode = 200; + response.end('OK'); + return; + case 'authenticate': + return validateAuthentication(credentials, response); + case 'success_post_method': + return validateRequestUsesMethod(request.method ?? '', 'post', response); + case 'success_put_method': + return validateRequestUsesMethod(request.method ?? '', 'put', response); + case 'failure': + response.statusCode = 500; + response.end('Error'); + return; + } + response.statusCode = 400; + response.end( + `unknown request to webhook simulator [${data ? `content: ${data}` : `no content`}]` + ); + return; + }); + } else { + request.on('end', () => { + response.statusCode = 400; + response.end('unknown request to webhook simulator [no content]'); + return; + }); + } + }); +} + +function validateAuthentication(credentials: any, res: any) { + try { + expect(credentials).to.eql({ + username: 'elastic', + password: 'changeme', + }); + res.statusCode = 200; + res.end('OK'); + } catch (ex) { + res.statusCode = 403; + res.end(`the validateAuthentication operation failed. ${ex.message}`); + } +} + +function validateRequestUsesMethod(requestMethod: string, method: string, res: any) { + try { + expect(requestMethod.toLowerCase()).to.eql(method); + res.statusCode = 200; + res.end('OK'); + } catch (ex) { + res.statusCode = 403; + res.end(`the validateAuthentication operation failed. ${ex.message}`); + } +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts deleted file mode 100644 index 43e6a73673556c..00000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts +++ /dev/null @@ -1,26 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import Hapi from 'hapi'; -import { - getExternalServiceSimulatorPath, - NAME, - ExternalServiceSimulator, -} from '../actions_simulators/server/plugin'; - -import { initPlugin as initWebhook } from './webhook_simulation'; -import { initPlugin as initSlack } from './slack_simulation'; - -// eslint-disable-next-line import/no-default-export -export default function (kibana: any) { - return new kibana.Plugin({ - require: ['xpack_main'], - name: `${NAME}-legacy`, - init: (server: Hapi.Server) => { - initWebhook(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.WEBHOOK)); - initSlack(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.SLACK)); - }, - }); -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json deleted file mode 100644 index 644cd77d3be753..00000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "actions-fixtures-legacy", - "version": "0.0.0", - "kibana": { - "version": "kibana" - } -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/slack_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/slack_simulation.ts deleted file mode 100644 index b914386b136ccc..00000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/slack_simulation.ts +++ /dev/null @@ -1,74 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import Joi from 'joi'; -import Hapi from 'hapi'; - -interface SlackRequest extends Hapi.Request { - payload: { - text: string; - }; -} -export function initPlugin(server: Hapi.Server, path: string) { - server.route({ - method: 'POST', - path, - options: { - auth: false, - validate: { - options: { abortEarly: false }, - payload: Joi.object().keys({ - text: Joi.string(), - }), - }, - }, - handler: slackHandler as Hapi.Lifecycle.Method, - }); -} -// Slack simulator: create a slack action pointing here, and you can get -// different responses based on the message posted. See the README.md for -// more info. - -function slackHandler(request: SlackRequest, h: any) { - const body = request.payload; - const text = body && body.text; - - if (text == null) { - return htmlResponse(h, 400, 'bad request to slack simulator'); - } - - switch (text) { - case 'success': - return htmlResponse(h, 200, 'ok'); - - case 'no_text': - return htmlResponse(h, 400, 'no_text'); - - case 'invalid_payload': - return htmlResponse(h, 400, 'invalid_payload'); - - case 'invalid_token': - return htmlResponse(h, 403, 'invalid_token'); - - case 'status_500': - return htmlResponse(h, 500, 'simulated slack 500 response'); - - case 'rate_limit': - const response = { - retry_after: 1, - ok: false, - error: 'rate_limited', - }; - - return h.response(response).type('application/json').header('retry-after', '1').code(429); - } - - return htmlResponse(h, 400, 'unknown request to slack simulator'); -} - -function htmlResponse(h: any, code: number, text: string) { - return h.response(text).type('text/html').code(code); -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/webhook_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/webhook_simulation.ts deleted file mode 100644 index 44e1aff162c922..00000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/webhook_simulation.ts +++ /dev/null @@ -1,112 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import expect from '@kbn/expect'; -import Joi from 'joi'; -import Hapi, { Util } from 'hapi'; -import { fromNullable, map, filter, getOrElse } from 'fp-ts/lib/Option'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { constant } from 'fp-ts/lib/function'; - -interface WebhookRequest extends Hapi.Request { - payload: string; -} - -export async function initPlugin(server: Hapi.Server, path: string) { - server.auth.scheme('identifyCredentialsIfPresent', function identifyCredentialsIfPresent( - s: Hapi.Server, - options?: Hapi.ServerAuthSchemeOptions - ) { - const scheme = { - async authenticate(request: Hapi.Request, h: Hapi.ResponseToolkit) { - const credentials = pipe( - fromNullable(request.headers.authorization), - map((authorization) => authorization.split(/\s+/)), - filter((parts) => parts.length > 1), - map((parts) => Buffer.from(parts[1], 'base64').toString()), - filter((credentialsPart) => credentialsPart.indexOf(':') !== -1), - map((credentialsPart) => { - const [username, password] = credentialsPart.split(':'); - return { username, password }; - }), - getOrElse(constant({ username: '', password: '' })) - ); - - return h.authenticated({ credentials }); - }, - }; - - return scheme; - }); - server.auth.strategy('simple', 'identifyCredentialsIfPresent'); - - server.route({ - method: ['POST', 'PUT'], - path, - options: { - auth: 'simple', - validate: { - options: { abortEarly: false }, - payload: Joi.string(), - }, - }, - handler: webhookHandler as Hapi.Lifecycle.Method, - }); -} - -function webhookHandler(request: WebhookRequest, h: any) { - const body = request.payload; - - switch (body) { - case 'success': - return htmlResponse(h, 200, `OK`); - case 'authenticate': - return validateAuthentication(request, h); - case 'success_post_method': - return validateRequestUsesMethod(request, h, 'post'); - case 'success_put_method': - return validateRequestUsesMethod(request, h, 'put'); - case 'failure': - return htmlResponse(h, 500, `Error`); - } - - return htmlResponse( - h, - 400, - `unknown request to webhook simulator [${body ? `content: ${body}` : `no content`}]` - ); -} - -function validateAuthentication(request: WebhookRequest, h: any) { - const { - auth: { credentials }, - } = request; - try { - expect(credentials).to.eql({ - username: 'elastic', - password: 'changeme', - }); - return htmlResponse(h, 200, `OK`); - } catch (ex) { - return htmlResponse(h, 403, `the validateAuthentication operation failed. ${ex.message}`); - } -} - -function validateRequestUsesMethod( - request: WebhookRequest, - h: any, - method: Util.HTTP_METHODS_PARTIAL -) { - try { - expect(request.method).to.eql(method); - return htmlResponse(h, 200, `OK`); - } catch (ex) { - return htmlResponse(h, 403, `the validateAuthentication operation failed. ${ex.message}`); - } -} - -function htmlResponse(h: any, code: number, text: string) { - return h.response(text).type('text/html').code(code); -} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts index f21bc8edeef1e4..c68bcaa0ad4e8d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts @@ -5,28 +5,27 @@ */ import expect from '@kbn/expect'; - +import http from 'http'; +import getPort from 'get-port'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { - getExternalServiceSimulatorPath, - ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; +import { getSlackServer } from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // eslint-disable-next-line import/no-default-export export default function slackTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - const kibanaServer = getService('kibanaServer'); describe('slack action', () => { let simulatedActionId = ''; - let slackSimulatorURL: string = ''; + let slackSimulatorURL: string = ''; + let slackServer: http.Server; // need to wait for kibanaServer to settle ... - before(() => { - slackSimulatorURL = kibanaServer.resolveUrl( - getExternalServiceSimulatorPath(ExternalServiceSimulator.SLACK) - ); + before(async () => { + slackServer = await getSlackServer(); + const availablePort = await getPort({ port: 9000 }); + slackServer.listen(availablePort); + slackSimulatorURL = `http://localhost:${availablePort}`; }); it('should return 200 when creating a slack action successfully', async () => { @@ -220,5 +219,9 @@ export default function slackTest({ getService }: FtrProviderContext) { expect(result.message).to.match(/error posting a slack message, retry later/); expect(result.retry).to.equal(true); }); + + after(() => { + slackServer.close(); + }); }); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts index 7eba753d7e98ba..8f17ab54184b5b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts @@ -4,12 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ +import http from 'http'; +import getPort from 'get-port'; import expect from '@kbn/expect'; import { URL, format as formatUrl } from 'url'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, + getWebhookServer, } from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; const defaultValues: Record = { @@ -30,11 +33,13 @@ export default function webhookTest({ getService }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); async function createWebhookAction( - urlWithCreds: string, - config: Record> = {} + webhookSimulatorURL: string, + config: Record> = {}, + kibanaUrlWithCreds: string ): Promise { - const { url: fullUrl, user, password } = extractCredentialsFromUrl(urlWithCreds); - const url = config.url && typeof config.url === 'object' ? parsePort(config.url) : fullUrl; + const { user, password } = extractCredentialsFromUrl(kibanaUrlWithCreds); + const url = + config.url && typeof config.url === 'object' ? parsePort(config.url) : webhookSimulatorURL; const composedConfig = { headers: { 'Content-Type': 'text/plain', @@ -61,11 +66,17 @@ export default function webhookTest({ getService }: FtrProviderContext) { } describe('webhook action', () => { - let webhookSimulatorURL: string = ''; - + let webhookSimulatorURL: string = ''; + let webhookServer: http.Server; + let kibanaURL: string = ''; // need to wait for kibanaServer to settle ... - before(() => { - webhookSimulatorURL = kibanaServer.resolveUrl( + before(async () => { + webhookServer = await getWebhookServer(); + const availablePort = await getPort({ port: 9000 }); + webhookServer.listen(availablePort); + webhookSimulatorURL = `http://localhost:${availablePort}`; + + kibanaURL = kibanaServer.resolveUrl( getExternalServiceSimulatorPath(ExternalServiceSimulator.WEBHOOK) ); }); @@ -117,7 +128,7 @@ export default function webhookTest({ getService }: FtrProviderContext) { }); it('should send authentication to the webhook target', async () => { - const webhookActionId = await createWebhookAction(webhookSimulatorURL); + const webhookActionId = await createWebhookAction(webhookSimulatorURL, {}, kibanaURL); const { body: result } = await supertest .post(`/api/actions/action/${webhookActionId}/_execute`) .set('kbn-xsrf', 'test') @@ -132,7 +143,11 @@ export default function webhookTest({ getService }: FtrProviderContext) { }); it('should support the POST method against webhook target', async () => { - const webhookActionId = await createWebhookAction(webhookSimulatorURL, { method: 'post' }); + const webhookActionId = await createWebhookAction( + webhookSimulatorURL, + { method: 'post' }, + kibanaURL + ); const { body: result } = await supertest .post(`/api/actions/action/${webhookActionId}/_execute`) .set('kbn-xsrf', 'test') @@ -147,7 +162,11 @@ export default function webhookTest({ getService }: FtrProviderContext) { }); it('should support the PUT method against webhook target', async () => { - const webhookActionId = await createWebhookAction(webhookSimulatorURL, { method: 'put' }); + const webhookActionId = await createWebhookAction( + webhookSimulatorURL, + { method: 'put' }, + kibanaURL + ); const { body: result } = await supertest .post(`/api/actions/action/${webhookActionId}/_execute`) .set('kbn-xsrf', 'test') @@ -183,7 +202,11 @@ export default function webhookTest({ getService }: FtrProviderContext) { }); it('should handle unreachable webhook targets', async () => { - const webhookActionId = await createWebhookAction('http://some.non.existent.com/endpoint'); + const webhookActionId = await createWebhookAction( + 'http://some.non.existent.com/endpoint', + {}, + kibanaURL + ); const { body: result } = await supertest .post(`/api/actions/action/${webhookActionId}/_execute`) .set('kbn-xsrf', 'test') @@ -199,7 +222,7 @@ export default function webhookTest({ getService }: FtrProviderContext) { }); it('should handle failing webhook targets', async () => { - const webhookActionId = await createWebhookAction(webhookSimulatorURL); + const webhookActionId = await createWebhookAction(webhookSimulatorURL, {}, kibanaURL); const { body: result } = await supertest .post(`/api/actions/action/${webhookActionId}/_execute`) .set('kbn-xsrf', 'test') @@ -214,6 +237,10 @@ export default function webhookTest({ getService }: FtrProviderContext) { expect(result.message).to.match(/error calling webhook, retry later/); expect(result.serviceMessage).to.eql('[500] Internal Server Error'); }); + + after(() => { + webhookServer.close(); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts index b3572978cee703..acfbad007d7220 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts @@ -4,24 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ +import http from 'http'; +import getPort from 'get-port'; import expect from '@kbn/expect'; import { URL, format as formatUrl } from 'url'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { - getExternalServiceSimulatorPath, - ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; +import { getWebhookServer } from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // eslint-disable-next-line import/no-default-export export default function webhookTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - const kibanaServer = getService('kibanaServer'); async function createWebhookAction( - urlWithCreds: string, + webhookSimulatorURL: string, config: Record> = {} ): Promise { - const url = formatUrl(new URL(urlWithCreds), { auth: false }); + const url = formatUrl(new URL(webhookSimulatorURL), { auth: false }); const composedConfig = { headers: { 'Content-Type': 'text/plain', @@ -45,13 +43,13 @@ export default function webhookTest({ getService }: FtrProviderContext) { } describe('webhook action', () => { - let webhookSimulatorURL: string = ''; - - // need to wait for kibanaServer to settle ... - before(() => { - webhookSimulatorURL = kibanaServer.resolveUrl( - getExternalServiceSimulatorPath(ExternalServiceSimulator.WEBHOOK) - ); + let webhookSimulatorURL: string = ''; + let webhookServer: http.Server; + before(async () => { + webhookServer = await getWebhookServer(); + const availablePort = await getPort({ port: 9000 }); + webhookServer.listen(availablePort); + webhookSimulatorURL = `http://localhost:${availablePort}`; }); it('webhook can be executed without username and password', async () => { @@ -68,5 +66,9 @@ export default function webhookTest({ getService }: FtrProviderContext) { expect(result.status).to.eql('ok'); }); + + after(() => { + webhookServer.close(); + }); }); } diff --git a/yarn.lock b/yarn.lock index deb9bbcef0c789..0512251751e8a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14122,7 +14122,7 @@ get-own-enumerable-property-symbols@^3.0.0: resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203" integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg== -get-port@4.2.0: +get-port@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==