diff --git a/x-pack/test/alerting_api_integration/common/config.ts b/x-pack/test/alerting_api_integration/common/config.ts index 42fa8e414adea..33b7962a18f22 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -85,6 +85,126 @@ const enabledActionTypes = [ 'test.connector-with-hooks', ]; +export const getPreConfiguredActions = ( + tlsWebhookServers: Awaited> +) => + JSON.stringify({ + 'my-test-email': { + actionTypeId: '.email', + name: 'TestEmail#xyz', + config: { + from: 'me@test.com', + service: '__json', + }, + secrets: { + user: 'user', + password: 'password', + }, + }, + 'notification-email': { + actionTypeId: '.email', + name: 'Notification Email Connector', + config: { + from: 'me@test.com', + service: '__json', + }, + secrets: { + user: 'user', + password: 'password', + }, + }, + 'my-slack1': { + actionTypeId: '.slack', + name: 'Slack#xyz', + secrets: { + webhookUrl: 'https://hooks.slack.com/services/abcd/efgh/ijklmnopqrstuvwxyz', + }, + }, + 'my-deprecated-servicenow': { + actionTypeId: '.servicenow', + name: 'ServiceNow#xyz', + config: { + apiUrl: 'https://ven04334.service-now.com', + usesTableApi: true, + }, + secrets: { + username: 'elastic_integration', + password: 'somepassword', + }, + }, + 'my-deprecated-servicenow-default': { + actionTypeId: '.servicenow', + name: 'ServiceNow#xyz', + config: { + apiUrl: 'https://ven04334.service-now.com', + }, + secrets: { + username: 'elastic_integration', + password: 'somepassword', + }, + }, + 'custom-system-abc-connector': { + actionTypeId: 'system-abc-action-type', + name: 'SystemABC', + config: { + xyzConfig1: 'value1', + xyzConfig2: 'value2', + listOfThings: ['a', 'b', 'c', 'd'], + }, + secrets: { + xyzSecret1: 'credential1', + xyzSecret2: 'credential2', + }, + }, + 'preconfigured-es-index-action': { + actionTypeId: '.index', + name: 'preconfigured_es_index_action', + config: { + index: 'functional-test-actions-index-preconfigured', + refresh: true, + executionTimeField: 'timestamp', + }, + }, + 'preconfigured.test.index-record': { + actionTypeId: 'test.index-record', + name: 'Test:_Preconfigured_Index_Record', + config: { + unencrypted: 'ignored-but-required', + }, + secrets: { + encrypted: 'this-is-also-ignored-and-also-required', + }, + }, + 'custom.ssl.noCustom': { + actionTypeId: '.webhook', + name: `${tlsWebhookServers.noCustom}`, + config: { + url: tlsWebhookServers.noCustom, + }, + }, + 'custom.ssl.rejectUnauthorizedFalse': { + actionTypeId: '.webhook', + name: `${tlsWebhookServers.rejectUnauthorizedFalse}`, + config: { + url: tlsWebhookServers.rejectUnauthorizedFalse, + }, + }, + 'custom.ssl.rejectUnauthorizedTrue': { + actionTypeId: '.webhook', + name: `${tlsWebhookServers.rejectUnauthorizedTrue}`, + config: { + url: tlsWebhookServers.rejectUnauthorizedTrue, + }, + }, + 'custom.ssl.caFile': { + actionTypeId: '.webhook', + name: `${tlsWebhookServers.caFile}`, + config: { + url: tlsWebhookServers.caFile, + }, + }, + }); + export function createTestConfig(name: string, options: CreateTestConfigOptions) { const { license = 'trial', @@ -237,122 +357,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) 'actions:test.excluded', ])}`, `--xpack.actions.preconfiguredAlertHistoryEsIndex=${preconfiguredAlertHistoryEsIndex}`, - `--xpack.actions.preconfigured=${JSON.stringify({ - 'my-test-email': { - actionTypeId: '.email', - name: 'TestEmail#xyz', - config: { - from: 'me@test.com', - service: '__json', - }, - secrets: { - user: 'user', - password: 'password', - }, - }, - 'notification-email': { - actionTypeId: '.email', - name: 'Notification Email Connector', - config: { - from: 'me@test.com', - service: '__json', - }, - secrets: { - user: 'user', - password: 'password', - }, - }, - 'my-slack1': { - actionTypeId: '.slack', - name: 'Slack#xyz', - secrets: { - webhookUrl: 'https://hooks.slack.com/services/abcd/efgh/ijklmnopqrstuvwxyz', - }, - }, - 'my-deprecated-servicenow': { - actionTypeId: '.servicenow', - name: 'ServiceNow#xyz', - config: { - apiUrl: 'https://ven04334.service-now.com', - usesTableApi: true, - }, - secrets: { - username: 'elastic_integration', - password: 'somepassword', - }, - }, - 'my-deprecated-servicenow-default': { - actionTypeId: '.servicenow', - name: 'ServiceNow#xyz', - config: { - apiUrl: 'https://ven04334.service-now.com', - }, - secrets: { - username: 'elastic_integration', - password: 'somepassword', - }, - }, - 'custom-system-abc-connector': { - actionTypeId: 'system-abc-action-type', - name: 'SystemABC', - config: { - xyzConfig1: 'value1', - xyzConfig2: 'value2', - listOfThings: ['a', 'b', 'c', 'd'], - }, - secrets: { - xyzSecret1: 'credential1', - xyzSecret2: 'credential2', - }, - }, - 'preconfigured-es-index-action': { - actionTypeId: '.index', - name: 'preconfigured_es_index_action', - config: { - index: 'functional-test-actions-index-preconfigured', - refresh: true, - executionTimeField: 'timestamp', - }, - }, - 'preconfigured.test.index-record': { - actionTypeId: 'test.index-record', - name: 'Test:_Preconfigured_Index_Record', - config: { - unencrypted: 'ignored-but-required', - }, - secrets: { - encrypted: 'this-is-also-ignored-and-also-required', - }, - }, - 'custom.ssl.noCustom': { - actionTypeId: '.webhook', - name: `${tlsWebhookServers.noCustom}`, - config: { - url: tlsWebhookServers.noCustom, - }, - }, - 'custom.ssl.rejectUnauthorizedFalse': { - actionTypeId: '.webhook', - name: `${tlsWebhookServers.rejectUnauthorizedFalse}`, - config: { - url: tlsWebhookServers.rejectUnauthorizedFalse, - }, - }, - 'custom.ssl.rejectUnauthorizedTrue': { - actionTypeId: '.webhook', - name: `${tlsWebhookServers.rejectUnauthorizedTrue}`, - config: { - url: tlsWebhookServers.rejectUnauthorizedTrue, - }, - }, - 'custom.ssl.caFile': { - actionTypeId: '.webhook', - name: `${tlsWebhookServers.caFile}`, - config: { - url: tlsWebhookServers.caFile, - }, - }, - })}`, + `--xpack.actions.preconfigured=${getPreConfiguredActions(tlsWebhookServers)}`, ...disabledPlugins .filter((k) => k !== 'security') .map((key) => `--xpack.${key}.enabled=false`), diff --git a/x-pack/test/alerting_api_integration/observability/index.ts b/x-pack/test/alerting_api_integration/observability/index.ts index 8763332d504e0..616a5bcc61c91 100644 --- a/x-pack/test/alerting_api_integration/observability/index.ts +++ b/x-pack/test/alerting_api_integration/observability/index.ts @@ -12,9 +12,5 @@ export default function ({ loadTestFile }: any) { loadTestFile(require.resolve('./metric_threshold_rule')); loadTestFile(require.resolve('./custom_threshold_rule_data_view')); }); - describe('Synthetics', () => { - loadTestFile(require.resolve('./synthetics/synthetics_default_rule')); - loadTestFile(require.resolve('./synthetics/custom_status_rule')); - }); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/index.ts index 98807f9ff5e79..0386448ecfce8 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/index.ts @@ -12,5 +12,10 @@ export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) loadTestFile(require.resolve('./burn_rate_rule')); loadTestFile(require.resolve('./custom_threshold')); loadTestFile(require.resolve('./es_query')); + + describe('Synthetics Alerting', () => { + loadTestFile(require.resolve('./synthetics/synthetics_default_rule')); + loadTestFile(require.resolve('./synthetics/custom_status_rule')); + }); }); } diff --git a/x-pack/test/alerting_api_integration/observability/synthetics/custom_status_rule.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/custom_status_rule.ts similarity index 85% rename from x-pack/test/alerting_api_integration/observability/synthetics/custom_status_rule.ts rename to x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/custom_status_rule.ts index 32f84f30d6555..e4f36ef65f8ce 100644 --- a/x-pack/test/alerting_api_integration/observability/synthetics/custom_status_rule.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/custom_status_rule.ts @@ -8,37 +8,67 @@ import expect from '@kbn/expect'; import moment from 'moment'; import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants'; import type { SyntheticsMonitorStatusRuleParams as StatusRuleParams } from '@kbn/response-ops-rule-params/synthetics_monitor_status'; -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { SyntheticsRuleHelper, SYNTHETICS_ALERT_ACTION_INDEX } from './synthetics_rule_helper'; -import { waitForDocumentInIndex } from '../helpers/alerting_wait_for_helpers'; - -// eslint-disable-next-line import/no-default-export -export default function ({ getService }: FtrProviderContext) { +import { waitForDocumentInIndex } from '../../../../../../alerting_api_integration/observability/helpers/alerting_wait_for_helpers'; +import { RoleCredentials, SupertestWithRoleScopeType } from '../../../../services'; +import { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; +import { + SyntheticsRuleHelper, + SYNTHETICS_ALERT_ACTION_INDEX, + SYNTHETICS_DOCS_INDEX, +} from './synthetics_rule_helper'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const server = getService('kibanaServer'); const retryService = getService('retry'); - const ruleHelper = new SyntheticsRuleHelper(getService); + let ruleHelper: SyntheticsRuleHelper; const logger = getService('log'); const esClient = getService('es'); const esDeleteAllIndices = getService('esDeleteAllIndices'); - const supertest = getService('supertest'); + const roleScopedSupertest = getService('roleScopedSupertest'); + let supertestEditorWithApiKey: SupertestWithRoleScopeType; + let supertestAdminWithCookieHeader: SupertestWithRoleScopeType; + let adminRoleAuthc: RoleCredentials; + const samlAuth = getService('samlAuth'); // Failing: See https://github.com/elastic/kibana/issues/202337 describe.skip('SyntheticsCustomStatusRule', () => { const SYNTHETICS_RULE_ALERT_INDEX = '.alerts-observability.uptime.alerts-default'; before(async () => { + [supertestEditorWithApiKey, supertestAdminWithCookieHeader, adminRoleAuthc] = + await Promise.all([ + roleScopedSupertest.getSupertestWithRoleScope('editor', { + withInternalHeaders: true, + }), + roleScopedSupertest.getSupertestWithRoleScope('admin', { + withInternalHeaders: true, + useCookieHeader: true, + }), + samlAuth.createM2mApiKeyWithRoleScope('admin'), + ]); + + ruleHelper = new SyntheticsRuleHelper(getService, supertestEditorWithApiKey, adminRoleAuthc); await server.savedObjects.cleanStandardList(); await esDeleteAllIndices([SYNTHETICS_ALERT_ACTION_INDEX]); await ruleHelper.createIndexAction(); - await supertest + await esClient.deleteByQuery({ + index: SYNTHETICS_RULE_ALERT_INDEX, + query: { match_all: {} }, + }); + await supertestAdminWithCookieHeader .put(SYNTHETICS_API_URLS.SYNTHETICS_ENABLEMENT) - .set('kbn-xsrf', 'true') .expect(200); }); after(async () => { + await supertestEditorWithApiKey.destroy(); + await samlAuth.invalidateM2mApiKeyWithRoleScope(adminRoleAuthc); + await supertestAdminWithCookieHeader.destroy(); await server.savedObjects.cleanStandardList(); await esDeleteAllIndices([SYNTHETICS_ALERT_ACTION_INDEX]); + await esClient.indices.deleteDataStream({ + name: SYNTHETICS_DOCS_INDEX, + }); await esClient.deleteByQuery({ index: SYNTHETICS_RULE_ALERT_INDEX, query: { match_all: {} }, @@ -132,7 +162,7 @@ export default function ({ getService }: FtrProviderContext) { expect(downResponse.hits.hits[0]._source).property('locationNames', 'Dev Service'); expect(downResponse.hits.hits[0]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); expect(downResponse.hits.hits[0]._source).property('locationId', 'dev'); }); @@ -159,30 +189,32 @@ export default function ({ getService }: FtrProviderContext) { indexName: SYNTHETICS_ALERT_ACTION_INDEX, retryService, logger, - docCountTarget: 2, filters: [ { term: { 'monitor.id': monitor.id }, }, + { + term: { status: 'recovered' }, + }, ], }); - expect(recoveredResponse.hits.hits[1]._source).property( + expect(recoveredResponse.hits.hits[0]._source).property( 'reason', `Monitor "${monitor.name}" from Dev Service is recovered. Alert when 5 out of the last 5 checks are down from at least 1 location.` ); - expect(recoveredResponse.hits.hits[1]._source).property('locationNames', 'Dev Service'); - expect(recoveredResponse.hits.hits[1]._source).property( + expect(recoveredResponse.hits.hits[0]._source).property('locationNames', 'Dev Service'); + expect(recoveredResponse.hits.hits[0]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); - expect(recoveredResponse.hits.hits[1]._source).property('locationId', 'dev'); - expect(recoveredResponse.hits.hits[1]._source).property( + expect(recoveredResponse.hits.hits[0]._source).property('locationId', 'dev'); + expect(recoveredResponse.hits.hits[0]._source).property( 'recoveryReason', `the monitor is now up again. It ran successfully at ${moment(docs[0]['@timestamp']) .tz('UTC') .format('MMM D, YYYY @ HH:mm:ss.SSS')}` ); - expect(recoveredResponse.hits.hits[1]._source).property('recoveryStatus', 'is now up'); + expect(recoveredResponse.hits.hits[0]._source).property('recoveryStatus', 'is now up'); }); }); @@ -271,7 +303,7 @@ export default function ({ getService }: FtrProviderContext) { ); expect(hit).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=${hit?.locationId}` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=${hit?.locationId}` ); }); }); @@ -352,7 +384,7 @@ export default function ({ getService }: FtrProviderContext) { expect(downResponse.hits.hits[0]._source).property('locationNames', 'Dev Service'); expect(downResponse.hits.hits[0]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); expect(downResponse.hits.hits[0]._source).property('locationId', 'dev'); }); @@ -380,28 +412,30 @@ export default function ({ getService }: FtrProviderContext) { indexName: SYNTHETICS_ALERT_ACTION_INDEX, retryService, logger, - docCountTarget: 2, filters: [ { term: { 'monitor.id': monitor.id }, }, + { + term: { status: 'recovered' }, + }, ], }); - expect(recoveredResponse.hits.hits[1]._source).property( + expect(recoveredResponse.hits.hits[0]._source).property( 'reason', `Monitor "${monitor.name}" from Dev Service is recovered. Alert when 5 out of the last 5 checks are down from at least 1 location.` ); - expect(recoveredResponse.hits.hits[1]._source).property('locationNames', 'Dev Service'); - expect(recoveredResponse.hits.hits[1]._source).property( + expect(recoveredResponse.hits.hits[0]._source).property('locationNames', 'Dev Service'); + expect(recoveredResponse.hits.hits[0]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); - expect(recoveredResponse.hits.hits[1]._source).property('locationId', 'dev'); - expect(recoveredResponse.hits.hits[1]._source).property( + expect(recoveredResponse.hits.hits[0]._source).property('locationId', 'dev'); + expect(recoveredResponse.hits.hits[0]._source).property( 'recoveryReason', 'the alert condition is no longer met' ); - expect(recoveredResponse.hits.hits[1]._source).property('recoveryStatus', 'has recovered'); + expect(recoveredResponse.hits.hits[0]._source).property('recoveryStatus', 'has recovered'); }); }); @@ -536,7 +570,7 @@ export default function ({ getService }: FtrProviderContext) { ); expect(downResponse.hits.hits[0]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); expect(downResponse.hits.hits[0]._source).property('locationId', 'dev and dev2'); }); @@ -575,7 +609,6 @@ export default function ({ getService }: FtrProviderContext) { indexName: SYNTHETICS_ALERT_ACTION_INDEX, retryService, logger, - docCountTarget: 2, filters: [ { term: { 'monitor.id': monitor.id }, @@ -592,7 +625,7 @@ export default function ({ getService }: FtrProviderContext) { ); expect(recoveryResponse.hits.hits[1]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); expect(recoveryResponse.hits.hits[1]._source).property('locationId', 'dev and dev2'); }); @@ -641,7 +674,7 @@ export default function ({ getService }: FtrProviderContext) { ); expect(downResponse.hits.hits[2]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); expect(downResponse.hits.hits[2]._source).property('locationId', 'dev and dev2'); }); @@ -685,7 +718,7 @@ export default function ({ getService }: FtrProviderContext) { ); expect(recoveryResponse.hits.hits[3]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); expect(recoveryResponse.hits.hits[3]._source).property('locationId', 'dev and dev2'); expect(recoveryResponse.hits.hits[3]._source).property( @@ -767,7 +800,7 @@ export default function ({ getService }: FtrProviderContext) { expect(downResponse.hits.hits[0]._source).property('locationNames', 'Dev Service'); expect(downResponse.hits.hits[0]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); expect(downResponse.hits.hits[0]._source).property('locationId', 'dev'); }); @@ -799,24 +832,26 @@ export default function ({ getService }: FtrProviderContext) { { term: { 'monitor.id': monitor.id }, }, + { + term: { status: 'recovered' }, + }, ], - docCountTarget: 2, }); - expect(recoveryResponse.hits.hits[1]._source).property( + expect(recoveryResponse.hits.hits[0]._source).property( 'reason', `Monitor "${monitor.name}" from Dev Service is recovered. Alert when 5 checks are down within the last 5 minutes from at least 1 location.` ); - expect(recoveryResponse.hits.hits[1]._source).property( + expect(recoveryResponse.hits.hits[0]._source).property( 'recoveryReason', 'the alert condition is no longer met' ); - expect(recoveryResponse.hits.hits[1]._source).property('recoveryStatus', 'has recovered'); - expect(recoveryResponse.hits.hits[1]._source).property('locationNames', 'Dev Service'); - expect(recoveryResponse.hits.hits[1]._source).property( + expect(recoveryResponse.hits.hits[0]._source).property('recoveryStatus', 'has recovered'); + expect(recoveryResponse.hits.hits[0]._source).property('locationNames', 'Dev Service'); + expect(recoveryResponse.hits.hits[0]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); - expect(recoveryResponse.hits.hits[1]._source).property('locationId', 'dev'); + expect(recoveryResponse.hits.hits[0]._source).property('locationId', 'dev'); }); }); @@ -904,7 +939,7 @@ export default function ({ getService }: FtrProviderContext) { ); expect(downResponse.hits.hits[0]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); expect(downResponse.hits.hits[0]._source).property('locationId', 'dev and dev2'); }); @@ -937,7 +972,7 @@ export default function ({ getService }: FtrProviderContext) { ); expect(alertAction.hits.hits[0]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); expect(alertAction.hits.hits[0]._source).property('locationId', 'dev and dev2'); }); @@ -969,28 +1004,30 @@ export default function ({ getService }: FtrProviderContext) { { term: { 'monitor.id': monitor.id }, }, + { + term: { status: 'recovered' }, + }, ], - docCountTarget: 2, }); - expect(recoveryAction.hits.hits[1]._source).property( + expect(recoveryAction.hits.hits[0]._source).property( 'reason', `Monitor "${monitor.name}" from Dev Service and Dev Service 2 is recovered. Alert when 5 checks are down within the last 5 minutes from at least 2 locations.` ); - expect(recoveryAction.hits.hits[1]._source).property( + expect(recoveryAction.hits.hits[0]._source).property( 'recoveryReason', 'the alert condition is no longer met' ); - expect(recoveryAction.hits.hits[1]._source).property('recoveryStatus', 'has recovered'); - expect(recoveryAction.hits.hits[1]._source).property( + expect(recoveryAction.hits.hits[0]._source).property('recoveryStatus', 'has recovered'); + expect(recoveryAction.hits.hits[0]._source).property( 'locationNames', 'Dev Service and Dev Service 2' ); - expect(recoveryAction.hits.hits[1]._source).property( + expect(recoveryAction.hits.hits[0]._source).property( 'linkMessage', - `- Link: https://localhost:5601/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` + `- Link: http://localhost:5620/app/synthetics/monitor/${monitor.id}/errors/Test%20private%20location-18524a3d9a7-0?locationId=dev` ); - expect(recoveryAction.hits.hits[1]._source).property('locationId', 'dev and dev2'); + expect(recoveryAction.hits.hits[0]._source).property('locationId', 'dev and dev2'); }); }); diff --git a/x-pack/test/alerting_api_integration/observability/synthetics/data.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/data.ts similarity index 100% rename from x-pack/test/alerting_api_integration/observability/synthetics/data.ts rename to x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/data.ts diff --git a/x-pack/test/alerting_api_integration/observability/synthetics/synthetics_default_rule.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/synthetics_default_rule.ts similarity index 85% rename from x-pack/test/alerting_api_integration/observability/synthetics/synthetics_default_rule.ts rename to x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/synthetics_default_rule.ts index deebaca217d91..89941e568394c 100644 --- a/x-pack/test/alerting_api_integration/observability/synthetics/synthetics_default_rule.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/synthetics_default_rule.ts @@ -9,12 +9,13 @@ import expect from '@kbn/expect'; import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants'; import type { SanitizedRule } from '@kbn/alerting-plugin/common'; import { omit } from 'lodash'; -import type { FtrProviderContext } from '../../common/ftr_provider_context'; +import { SupertestWithRoleScopeType } from '../../../../services'; +import { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; import { statusRule, tlsRule } from './data'; -// eslint-disable-next-line import/no-default-export -export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const roleScopedSupertest = getService('roleScopedSupertest'); + let supertestEditorWithApiKey: SupertestWithRoleScopeType; const server = getService('kibanaServer'); const testActions = [ @@ -27,15 +28,19 @@ export default function ({ getService }: FtrProviderContext) { describe('SyntheticsDefaultRules', () => { before(async () => { + supertestEditorWithApiKey = await roleScopedSupertest.getSupertestWithRoleScope('editor', { + withInternalHeaders: true, + }); await server.savedObjects.cleanStandardList(); }); after(async () => { + await supertestEditorWithApiKey.destroy(); await server.savedObjects.cleanStandardList(); }); it('creates rule when settings are configured', async () => { - await supertest + await supertestEditorWithApiKey .put(SYNTHETICS_API_URLS.DYNAMIC_SETTINGS) .set('kbn-xsrf', 'true') .send({ @@ -46,7 +51,7 @@ export default function ({ getService }: FtrProviderContext) { }) .expect(200); - const response = await supertest + const response = await supertestEditorWithApiKey .post(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) .set('kbn-xsrf', 'true') .send(); @@ -74,7 +79,7 @@ export default function ({ getService }: FtrProviderContext) { }); it('updates rules when settings are updated', async () => { - await supertest + await supertestEditorWithApiKey .put(SYNTHETICS_API_URLS.DYNAMIC_SETTINGS) .set('kbn-xsrf', 'true') .send({ @@ -85,7 +90,7 @@ export default function ({ getService }: FtrProviderContext) { }) .expect(200); - const response = await supertest + const response = await supertestEditorWithApiKey .put(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) .set('kbn-xsrf', 'true') .send(); diff --git a/x-pack/test/alerting_api_integration/observability/synthetics/synthetics_rule_helper.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/synthetics_rule_helper.ts similarity index 81% rename from x-pack/test/alerting_api_integration/observability/synthetics/synthetics_rule_helper.ts rename to x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/synthetics_rule_helper.ts index 5935f73459ef8..22d7132c0c171 100644 --- a/x-pack/test/alerting_api_integration/observability/synthetics/synthetics_rule_helper.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/synthetics_rule_helper.ts @@ -9,35 +9,41 @@ import type { SyntheticsMonitorStatusRuleParams as StatusRuleParams } from '@kbn import type { Client } from '@elastic/elasticsearch'; import type { ToolingLog } from '@kbn/tooling-log'; import { makeDownSummary, makeUpSummary } from '@kbn/observability-synthetics-test-data'; -import type { RetryService } from '@kbn/ftr-common-functional-services'; +import type { RetryService, RoleCredentials } from '@kbn/ftr-common-functional-services'; import type { EncryptedSyntheticsSavedMonitor } from '@kbn/synthetics-plugin/common/runtime_types'; import moment from 'moment'; import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import type { Agent as SuperTestAgent } from 'supertest'; import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants'; import expect from '@kbn/expect'; -import { PrivateLocationTestService } from '@kbn/test-suites-xpack-observability/api_integration/apis/synthetics/services/private_location_test_service'; -import { waitForAlertInIndex } from '../helpers/alerting_wait_for_helpers'; -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { createIndexConnector, createRule } from '../helpers/alerting_api_helper'; +import { SupertestWithRoleScope } from '../../../../services/role_scoped_supertest'; +import { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; +import { AlertingApiProvider } from '../../../../services/alerting_api'; export const SYNTHETICS_ALERT_ACTION_INDEX = 'alert-action-synthetics'; +export const SYNTHETICS_DOCS_INDEX = 'synthetics-http-default'; + export class SyntheticsRuleHelper { - supertest: SuperTestAgent; + supertestEditorWithApiKey: SupertestWithRoleScope; + adminRoleAuthc: RoleCredentials; logger: ToolingLog; esClient: Client; retryService: RetryService; - locService: PrivateLocationTestService; alertActionIndex: string; actionId: string | null = null; + alertingApi: ReturnType; - constructor(getService: FtrProviderContext['getService']) { + constructor( + getService: DeploymentAgnosticFtrProviderContext['getService'], + supertestEditorWithApiKey: SupertestWithRoleScope, + adminRoleAuthc: RoleCredentials + ) { this.esClient = getService('es'); - this.supertest = getService('supertest'); + this.supertestEditorWithApiKey = supertestEditorWithApiKey; + this.adminRoleAuthc = adminRoleAuthc; this.logger = getService('log'); this.retryService = getService('retry'); - this.locService = new PrivateLocationTestService(getService); this.alertActionIndex = SYNTHETICS_ALERT_ACTION_INDEX; + this.alertingApi = getService('alertingApi'); } async createIndexAction() { @@ -53,11 +59,10 @@ export class SyntheticsRuleHelper { }, }, }); - const actionId = await createIndexConnector({ - supertest: this.supertest, + const actionId = await this.alertingApi.createIndexConnector({ + roleAuthc: this.adminRoleAuthc, name: 'Index Connector: Synthetics API test', indexName: this.alertActionIndex, - logger: this.logger, }); this.actionId = actionId; } @@ -73,15 +78,13 @@ export class SyntheticsRuleHelper { if (this.actionId === null) { throw new Error('Index action not created. Call createIndexAction() first'); } - return await createRule({ + return this.alertingApi.createRule({ + roleAuthc: this.adminRoleAuthc, params, name: name ?? 'Custom status rule', ruleTypeId: 'xpack.synthetics.alerts.monitorStatus', consumer: 'alerts', - supertest: this.supertest, - esClient: this.esClient, - logger: this.logger, - schedule: { interval: '15s' }, + schedule: { interval: '5s' }, actions: [ { group: 'recovered', @@ -142,9 +145,8 @@ export class SyntheticsRuleHelper { url: 'http://www.google.com', schedule: 1, }; - const res = await this.supertest + const res = await this.supertestEditorWithApiKey .post(SYNTHETICS_API_URLS.SYNTHETICS_MONITORS + '?internal=true') - .set('kbn-xsrf', 'true') .send(testData); expect(res.status).to.eql(200, JSON.stringify(res.body)); @@ -153,18 +155,16 @@ export class SyntheticsRuleHelper { } async deleteMonitor(monitorId: string) { - const res = await this.supertest + const res = await this.supertestEditorWithApiKey .delete(SYNTHETICS_API_URLS.SYNTHETICS_MONITORS + '/' + monitorId) - .set('kbn-xsrf', 'true') .send(); expect(res.status).to.eql(200); } async updateTestMonitor(monitorId: string, updates: Record) { - const result = await this.supertest + const result = await this.supertestEditorWithApiKey .put(SYNTHETICS_API_URLS.SYNTHETICS_MONITORS + `/${monitorId}`) - .set('kbn-xsrf', 'true') .send(updates); expect(result.status).to.eql(200, JSON.stringify(result.body)); @@ -179,14 +179,10 @@ export class SyntheticsRuleHelper { ruleId: string; filters?: QueryDslQueryContainer[]; }) { - return await waitForAlertInIndex({ + return this.alertingApi.waitForAlertInIndex({ ruleId, filters, - esClient: this.esClient, - retryService: this.retryService, - logger: this.logger, - indexName: '.internal.alerts-observability.uptime.alerts-default*', - retryDelay: 1000, + indexName: '.alerts-observability.uptime.alerts-default*', }); } @@ -251,8 +247,6 @@ export class SyntheticsRuleHelper { '@timestamp': timestamp, }; - const index = 'synthetics-http-default'; - const commonData = { timestamp, location, @@ -277,7 +271,7 @@ export class SyntheticsRuleHelper { `created synthetics summary, status: ${status}, monitor: "${monitor.name}", location: "${location?.label}"` ); await this.esClient.index({ - index, + index: SYNTHETICS_DOCS_INDEX, document, refresh: true, }); diff --git a/x-pack/test/api_integration/deployment_agnostic/default_configs/serverless.config.base.ts b/x-pack/test/api_integration/deployment_agnostic/default_configs/serverless.config.base.ts index ff940e711674c..af608fda01415 100644 --- a/x-pack/test/api_integration/deployment_agnostic/default_configs/serverless.config.base.ts +++ b/x-pack/test/api_integration/deployment_agnostic/default_configs/serverless.config.base.ts @@ -14,6 +14,8 @@ import { import { ScoutTestRunConfigCategory } from '@kbn/scout-info'; import { ServerlessProjectType } from '@kbn/es'; import path from 'path'; +import { getPreConfiguredActions } from '../../../alerting_api_integration/common/config'; +import { getTlsWebhookServerUrls } from '../../../alerting_api_integration/common/lib/get_tls_webhook_servers'; import { DeploymentAgnosticCommonServices, services } from '../services'; interface CreateTestConfigOptions { @@ -70,6 +72,7 @@ export function createServerlessTestConfig { @@ -56,6 +58,7 @@ export function createStatefulTestConfig({ indexName, ruleId, + filters = [], }: { indexName: string; ruleId: string; + filters?: QueryDslQueryContainer[]; }): Promise>> { if (!ruleId) { throw new Error(`'ruleId' is undefined`); @@ -1014,11 +1021,16 @@ export function AlertingApiProvider({ getService }: DeploymentAgnosticFtrProvide return await retry.tryForTime(retryTimeout, async () => { const response = await es.search({ index: indexName, - body: { - query: { - term: { - 'kibana.alert.rule.uuid': ruleId, - }, + query: { + bool: { + filter: [ + { + term: { + 'kibana.alert.rule.uuid': ruleId, + }, + }, + ...filters, + ], }, }, }); @@ -1076,7 +1088,8 @@ export function AlertingApiProvider({ getService }: DeploymentAgnosticFtrProvide | ApmRuleParamsType['apm.anomaly'] | ApmRuleParamsType['apm.error_rate'] | ApmRuleParamsType['apm.transaction_duration'] - | ApmRuleParamsType['apm.transaction_error_rate']; + | ApmRuleParamsType['apm.transaction_error_rate'] + | StatusRuleParams; actions?: any[]; tags?: any[]; schedule?: { interval: string };