From 1a2f1d29de0f55db4c017d5b6d380e95ff2a965d Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Wed, 2 Jul 2025 13:50:05 +0200 Subject: [PATCH 1/2] [ska] copying helpers back to remove circular deps --- .github/CODEOWNERS | 3 + .../test/accessibility/apps/group1/uptime.ts | 2 +- .../alerting/synthetics/alert_on_no_data.ts | 2 +- .../alerting/synthetics/custom_status_rule.ts | 2 +- .../apm/constants/archives_metadata.ts | 2 +- .../apm/data_view/static.spec.ts | 2 +- .../observability_overview.spec.ts | 2 +- .../service_groups/save_service_group.spec.ts | 4 +- .../apm/service_maps/service_maps.spec.ts | 2 +- .../observability/apm/services/agent.spec.ts | 2 +- .../service_infra_metrics.spec.ts | 2 +- .../settings/agent_keys/agent_keys.spec.ts | 2 +- ...actions_groups_detailed_statistics.spec.ts | 2 +- .../common/apm_api_supertest.ts | 131 ++ .../fixtures/es_archiver/archives_metadata.ts | 21 + .../utils/create_and_run_apm_ml_jobs.ts | 76 + .../common/utils/expect_to_reject.ts | 17 + x-pack/test/apm_api_integration/utils.ts | 13 + .../observability/alerting_api_helper.ts | 86 + .../alerting_wait_for_helpers.ts | 156 ++ .../utils/observability/refresh_index.ts | 36 + .../test/common/utils/observability/retry.ts | 92 + .../utils/uptime/fixtures/monitor_charts.json | 89 + .../fixtures/monitor_latest_status.json | 57 + .../utils/uptime/fixtures/monitor_status.json | 154 ++ .../uptime/fixtures/monitor_status_all.json | 1802 +++++++++++++++++ .../fixtures/monitors_with_location.json | 720 +++++++ .../utils/uptime/fixtures/ping_histogram.json | 161 ++ .../fixtures/ping_histogram_by_filter.json | 161 ++ .../uptime/fixtures/ping_histogram_by_id.json | 161 ++ .../utils/uptime/helper/expect_fixture_eql.ts | 46 + .../common/utils/uptime/helper/make_checks.ts | 175 ++ .../common/utils/uptime/helper/make_ping.ts | 126 ++ .../common/utils/uptime/helper/make_tls.ts | 68 + .../infra/metrics_source_configuration.ts | 4 +- .../functional/apps/uptime/certificates.ts | 4 +- .../apps/uptime/missing_mappings.ts | 2 +- .../test/functional/apps/uptime/settings.ts | 2 +- x-pack/test/tsconfig.json | 8 +- 39 files changed, 4375 insertions(+), 22 deletions(-) create mode 100644 x-pack/test/apm_api_integration/common/apm_api_supertest.ts create mode 100644 x-pack/test/apm_api_integration/common/fixtures/es_archiver/archives_metadata.ts create mode 100644 x-pack/test/apm_api_integration/common/utils/create_and_run_apm_ml_jobs.ts create mode 100644 x-pack/test/apm_api_integration/common/utils/expect_to_reject.ts create mode 100644 x-pack/test/apm_api_integration/utils.ts create mode 100644 x-pack/test/common/utils/observability/alerting_api_helper.ts create mode 100644 x-pack/test/common/utils/observability/alerting_wait_for_helpers.ts create mode 100644 x-pack/test/common/utils/observability/refresh_index.ts create mode 100644 x-pack/test/common/utils/observability/retry.ts create mode 100644 x-pack/test/common/utils/uptime/fixtures/monitor_charts.json create mode 100644 x-pack/test/common/utils/uptime/fixtures/monitor_latest_status.json create mode 100644 x-pack/test/common/utils/uptime/fixtures/monitor_status.json create mode 100644 x-pack/test/common/utils/uptime/fixtures/monitor_status_all.json create mode 100644 x-pack/test/common/utils/uptime/fixtures/monitors_with_location.json create mode 100644 x-pack/test/common/utils/uptime/fixtures/ping_histogram.json create mode 100644 x-pack/test/common/utils/uptime/fixtures/ping_histogram_by_filter.json create mode 100644 x-pack/test/common/utils/uptime/fixtures/ping_histogram_by_id.json create mode 100644 x-pack/test/common/utils/uptime/helper/expect_fixture_eql.ts create mode 100644 x-pack/test/common/utils/uptime/helper/make_checks.ts create mode 100644 x-pack/test/common/utils/uptime/helper/make_ping.ts create mode 100644 x-pack/test/common/utils/uptime/helper/make_tls.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5f2edeb27069b..0f5d63a333f2c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1885,6 +1885,9 @@ x-pack/platform/plugins/shared/ml/server/models/data_recognizer/modules/security /x-pack/solutions/security/test/api_integration/ftr_provider_context.d.ts @elastic/appex-qa /x-pack/solutions/security/test/api_integration/services/index.ts @elastic/appex-qa /x-pack/solutions/security/test/alerting_api_integration/ftr_provider_context.d.ts @elastic/appex-qa +/x-pack/test/apm_api_integration @elastic/appex-qa # temporarily due to SKA tests relocation +/x-pack/test/common/utils/observability @elastic/appex-qa # temporarily due to SKA tests relocation +/x-pack/test/common/utils/uptime @elastic/appex-qa # temporarily due to SKA tests relocation # Core /src/platform/test/api_integration/fixtures/kbn_archiver/management/saved_objects/relationships.json @elastic/kibana-core @elastic/kibana-data-discovery diff --git a/x-pack/test/accessibility/apps/group1/uptime.ts b/x-pack/test/accessibility/apps/group1/uptime.ts index b366808d860f8..b06e90291f5f5 100644 --- a/x-pack/test/accessibility/apps/group1/uptime.ts +++ b/x-pack/test/accessibility/apps/group1/uptime.ts @@ -6,7 +6,7 @@ */ import moment from 'moment'; -import { makeChecks } from '@kbn/test-suites-xpack-observability/api_integration/apis/uptime/rest/helper/make_checks'; +import { makeChecks } from '../../../common/utils/uptime/helper/make_checks'; import { FtrProviderContext } from '../../ftr_provider_context'; const A11Y_TEST_MONITOR_ID = 'a11yTestMonitor'; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/alert_on_no_data.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/alert_on_no_data.ts index fee162f1e2ebf..93aa6e2945a36 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/alert_on_no_data.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/alert_on_no_data.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import moment from 'moment'; import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants'; -import { waitForDocumentInIndex } from '@kbn/test-suites-xpack-observability/alerting_api_integration/observability/helpers/alerting_wait_for_helpers'; +import { waitForDocumentInIndex } from '../../../../../../common/utils/observability/alerting_wait_for_helpers'; import { RoleCredentials, SupertestWithRoleScopeType } from '../../../../services'; import { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; import { diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/custom_status_rule.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/custom_status_rule.ts index 088262b77d202..413780df0ee95 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/custom_status_rule.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/synthetics/custom_status_rule.ts @@ -8,7 +8,7 @@ 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 { waitForDocumentInIndex } from '@kbn/test-suites-xpack-observability/alerting_api_integration/observability/helpers/alerting_wait_for_helpers'; +import { waitForDocumentInIndex } from '../../../../../../common/utils/observability/alerting_wait_for_helpers'; import { RoleCredentials, SupertestWithRoleScopeType } from '../../../../services'; import { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; import { diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/constants/archives_metadata.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/constants/archives_metadata.ts index a53a1fcbf0632..37a5dc2aa9a6f 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/constants/archives_metadata.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/constants/archives_metadata.ts @@ -5,6 +5,6 @@ * 2.0. */ -import archivesMetadata from '@kbn/test-suites-xpack-observability/apm_api_integration/common/fixtures/es_archiver/archives_metadata'; +import archivesMetadata from '../../../../../../apm_api_integration/common/fixtures/es_archiver/archives_metadata'; export default archivesMetadata; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/data_view/static.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/data_view/static.spec.ts index 4682b1805232b..ee025c5b92f17 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/data_view/static.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/data_view/static.spec.ts @@ -15,7 +15,7 @@ import { getStaticDataViewId } from '@kbn/apm-data-view'; import { SupertestReturnType, ApmApiError, -} from '@kbn/test-suites-xpack-observability/apm_api_integration/common/apm_api_supertest'; +} from '../../../../../../apm_api_integration/common/apm_api_supertest'; import { SupertestWithRoleScope } from '../../../../services/role_scoped_supertest'; import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/observability_overview/observability_overview.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/observability_overview/observability_overview.spec.ts index e5249af8c582d..796ef08f70250 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/observability_overview/observability_overview.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/observability_overview/observability_overview.spec.ts @@ -10,7 +10,7 @@ import { meanBy, sumBy } from 'lodash'; import { ApmDocumentType } from '@kbn/apm-plugin/common/document_type'; import { RollupInterval } from '@kbn/apm-plugin/common/rollup'; import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; -import { roundNumber } from '@kbn/test-suites-xpack-observability/apm_api_integration/utils'; +import { roundNumber } from '../../../../../../apm_api_integration/utils'; import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_groups/save_service_group.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_groups/save_service_group.spec.ts index 5dbe8b0ac88ba..1c5b617cfc486 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_groups/save_service_group.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_groups/save_service_group.spec.ts @@ -5,8 +5,8 @@ * 2.0. */ import expect from '@kbn/expect'; -import { ApmApiError } from '@kbn/test-suites-xpack-observability/apm_api_integration/common/apm_api_supertest'; -import { expectToReject } from '@kbn/test-suites-xpack-observability/apm_api_integration/common/utils/expect_to_reject'; +import { ApmApiError } from '../../../../../../apm_api_integration/common/apm_api_supertest'; +import { expectToReject } from '../../../../../../apm_api_integration/common/utils/expect_to_reject'; import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; import { createServiceGroupApi, diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_maps/service_maps.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_maps/service_maps.spec.ts index efa29aaf675fd..630c494f39036 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_maps/service_maps.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_maps/service_maps.spec.ts @@ -10,7 +10,7 @@ import expect from 'expect'; import { serviceMap, timerange, apm, ApmFields } from '@kbn/apm-synthtrace-client'; import { Readable } from 'node:stream'; import { compact } from 'lodash'; -import type { SupertestReturnType } from '@kbn/test-suites-xpack-observability/apm_api_integration/common/apm_api_supertest'; +import type { SupertestReturnType } from '../../../../../../apm_api_integration/common/apm_api_supertest'; import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; import { extractExitSpansConnections, diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/agent.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/agent.spec.ts index e61cc62060c38..22953fced1fee 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/agent.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/agent.spec.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import archives_metadata from '@kbn/test-suites-xpack-observability/apm_api_integration/common/fixtures/es_archiver/archives_metadata'; +import archives_metadata from '../../../../../../apm_api_integration/common/fixtures/es_archiver/archives_metadata'; import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; import { ARCHIVER_ROUTES } from '../constants/archiver'; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/service_details/service_infra_metrics.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/service_details/service_infra_metrics.spec.ts index e7c7beb523858..92a8412961749 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/service_details/service_infra_metrics.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/services/service_details/service_infra_metrics.spec.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; import { ENVIRONMENT_ALL } from '@kbn/apm-plugin/common/environment_filter_values'; -import archives_metadata from '@kbn/test-suites-xpack-observability/apm_api_integration/common/fixtures/es_archiver/archives_metadata'; +import archives_metadata from '../../../../../../../apm_api_integration/common/fixtures/es_archiver/archives_metadata'; import type { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; import { ARCHIVER_ROUTES } from '../../constants/archiver'; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts index 8c6d48f7e3dc5..6f95caa79f99d 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/settings/agent_keys/agent_keys.spec.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; import { PrivilegeType, ClusterPrivilegeType } from '@kbn/apm-plugin/common/privilege_type'; -import { expectToReject } from '@kbn/test-suites-xpack-observability/apm_api_integration/common/utils/expect_to_reject'; +import { expectToReject } from '../../../../../../../apm_api_integration/common/utils/expect_to_reject'; import type { RoleCredentials } from '../../../../../services'; import type { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; import type { ApmApiError } from '../../../../../services/apm_api'; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/transactions_groups_detailed_statistics.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/transactions_groups_detailed_statistics.spec.ts index dcf5d286af8be..bc0ea9e1f501d 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/transactions_groups_detailed_statistics.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/transactions_groups_detailed_statistics.spec.ts @@ -13,7 +13,7 @@ import { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_ import { RollupInterval } from '@kbn/apm-plugin/common/rollup'; import { ApmDocumentType, ApmTransactionDocumentType } from '@kbn/apm-plugin/common/document_type'; import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; -import { roundNumber } from '@kbn/test-suites-xpack-observability/apm_api_integration/utils'; +import { roundNumber } from '../../../../../../apm_api_integration/utils'; import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; type TransactionsGroupsDetailedStatistics = diff --git a/x-pack/test/apm_api_integration/common/apm_api_supertest.ts b/x-pack/test/apm_api_integration/common/apm_api_supertest.ts new file mode 100644 index 0000000000000..84b7f2bd978c7 --- /dev/null +++ b/x-pack/test/apm_api_integration/common/apm_api_supertest.ts @@ -0,0 +1,131 @@ +/* + * 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 { format } from 'url'; +import supertest from 'supertest'; +import request from 'superagent'; +import type { + APIReturnType, + APIClientRequestParamsOf, +} from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; +import type { APIEndpoint } from '@kbn/apm-plugin/server'; +import type { + APIEndpoint as SourcesAPIEndpoint, + APIReturnType as SourcesAPIReturnType, + APIClientRequestParamsOf as SourcesAPIClientRequestParamsOf, +} from '@kbn/apm-sources-access-plugin/server'; +import { formatRequest } from '@kbn/server-route-repository'; + +type CombinedAPIRequest = + TEndpoint extends APIEndpoint + ? APIReturnType + : TEndpoint extends SourcesAPIEndpoint + ? SourcesAPIReturnType + : never; + +type CombinedOptions = + TEndpoint extends APIEndpoint + ? Options + : TEndpoint extends SourcesAPIEndpoint + ? SourceOptions + : never; + +type Options = { + type?: 'form-data'; + endpoint: TEndpoint; + spaceId?: string; +} & APIClientRequestParamsOf & { + params?: { query?: { _inspect?: boolean } }; + }; + +type SourceOptions = { + type?: 'form-data'; + endpoint: TEndpoint; + spaceId?: string; +} & SourcesAPIClientRequestParamsOf; + +export function createApmApiClient(st: supertest.Agent) { + return async ( + options: CombinedOptions + ): Promise> => { + const { endpoint, type } = options; + + const params = 'params' in options ? (options.params as Record) : {}; + + const { method, pathname, version } = formatRequest(endpoint, params.path); + const pathnameWithSpaceId = options.spaceId ? `/s/${options.spaceId}${pathname}` : pathname; + const url = format({ pathname: pathnameWithSpaceId, query: params?.query }); + + // eslint-disable-next-line no-console + console.debug(`Calling APM API: ${method.toUpperCase()} ${url}`); + + const headers: Record = { + 'kbn-xsrf': 'foo', + 'x-elastic-internal-origin': 'foo', + }; + + if (version) { + headers['Elastic-Api-Version'] = version; + } + + let res: request.Response; + if (type === 'form-data') { + const fields: Array<[string, any]> = Object.entries(params.body); + const formDataRequest = st[method](url) + .set(headers) + .set('Content-type', 'multipart/form-data'); + + for (const field of fields) { + void formDataRequest.field(field[0], field[1]); + } + + res = await formDataRequest; + } else if (params.body) { + res = await st[method](url).send(params.body).set(headers); + } else { + res = await st[method](url).set(headers); + } + + // supertest doesn't throw on http errors + if (res?.status !== 200) { + throw new ApmApiError(res, endpoint); + } + + return res; + }; +} + +type ApiErrorResponse = Omit & { + body: { + statusCode: number; + error: string; + message: string; + attributes: object; + }; +}; + +export type ApmApiSupertest = ReturnType; + +export class ApmApiError extends Error { + res: ApiErrorResponse; + + constructor(res: request.Response, endpoint: string) { + super( + `Unhandled ApmApiError. +Status: "${res.status}" +Endpoint: "${endpoint}" +Body: ${JSON.stringify(res.body)}` + ); + + this.res = res; + } +} + +export interface SupertestReturnType { + status: number; + body: CombinedAPIRequest; +} diff --git a/x-pack/test/apm_api_integration/common/fixtures/es_archiver/archives_metadata.ts b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/archives_metadata.ts new file mode 100644 index 0000000000000..9988657f13897 --- /dev/null +++ b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/archives_metadata.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export default { + '8.0.0': { + start: '2020-08-26T11:00:43.849Z', + end: '2020-08-26T12:00:43.849Z', + }, + 'apm_8.0.0': { + start: '2021-08-03T06:50:15.910Z', + end: '2021-08-03T07:20:15.910Z', + }, + infra_metrics_and_apm: { + start: '2019-06-29T02:48:39.386555Z', + end: '2022-06-29T06:46:26Z', + }, +}; diff --git a/x-pack/test/apm_api_integration/common/utils/create_and_run_apm_ml_jobs.ts b/x-pack/test/apm_api_integration/common/utils/create_and_run_apm_ml_jobs.ts new file mode 100644 index 0000000000000..cfeb766a5a94a --- /dev/null +++ b/x-pack/test/apm_api_integration/common/utils/create_and_run_apm_ml_jobs.ts @@ -0,0 +1,76 @@ +/* + * 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 job from '@kbn/ml-plugin/server/models/data_recognizer/modules/apm_transaction/ml/apm_tx_metrics.json'; +import datafeed from '@kbn/ml-plugin/server/models/data_recognizer/modules/apm_transaction/ml/datafeed_apm_tx_metrics.json'; +import { ToolingLog } from '@kbn/tooling-log'; +import { MlApi } from '@kbn/test-suites-xpack-platform/api_integration/services/ml/api'; + +export async function createAndRunApmMlJobs({ + es, + ml, + environments, + logger, +}: { + es: Client; + ml: MlApi; + environments: string[]; + logger: ToolingLog; +}) { + // Creating multiple ml jobs in parallel is causing this tests to be flaky + // https://github.com/elastic/elasticsearch/issues/36271 + for (const environment of environments) { + await createAndRunApmMlJob({ es, environment, ml, logger }); + } +} + +async function createAndRunApmMlJob({ + es, + ml, + environment, + logger, +}: { + es: Client; + ml: MlApi; + environment: string; + logger: ToolingLog; +}) { + const jobId = `apm-tx-metrics-${environment}`; + await ml.createAndRunAnomalyDetectionLookbackJob( + // @ts-expect-error not entire job config + { + ...job, + job_id: jobId, + allow_lazy_open: false, + custom_settings: { + job_tags: { + apm_ml_version: '3', + environment, + }, + }, + }, + { + ...datafeed, + indices_options: { allow_no_indices: true }, + job_id: jobId, + indices: ['metrics-apm*', 'apm-*'], + datafeed_id: `apm-tx-metrics-${environment}-datafeed`, + query: { + bool: { + filter: [...datafeed.query.bool.filter, { term: { 'service.environment': environment } }], + }, + }, + } + ); + + logger.info(`Created ml job ${jobId}`); + + await es.cluster.health({ index: '.ml-*', wait_for_status: 'yellow' }); + + logger.info(`Finished waiting for cluster to be healthy`); +} diff --git a/x-pack/test/apm_api_integration/common/utils/expect_to_reject.ts b/x-pack/test/apm_api_integration/common/utils/expect_to_reject.ts new file mode 100644 index 0000000000000..ae352c31d71a2 --- /dev/null +++ b/x-pack/test/apm_api_integration/common/utils/expect_to_reject.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export async function expectToReject(fn: () => Promise): Promise { + let res: any; + try { + res = await fn(); + } catch (e) { + return e; + } + + throw new Error(`expectToReject resolved: "${JSON.stringify(res)}"`); +} diff --git a/x-pack/test/apm_api_integration/utils.ts b/x-pack/test/apm_api_integration/utils.ts new file mode 100644 index 0000000000000..8f5ff9822e22d --- /dev/null +++ b/x-pack/test/apm_api_integration/utils.ts @@ -0,0 +1,13 @@ +/* + * 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 { isFiniteNumber } from '@kbn/apm-plugin/common/utils/is_finite_number'; +import { Maybe } from '@kbn/apm-plugin/typings/common'; + +export function roundNumber(num: Maybe) { + return isFiniteNumber(num) ? Number(num.toPrecision(4)) : null; +} diff --git a/x-pack/test/common/utils/observability/alerting_api_helper.ts b/x-pack/test/common/utils/observability/alerting_api_helper.ts new file mode 100644 index 0000000000000..8abad71ffca0d --- /dev/null +++ b/x-pack/test/common/utils/observability/alerting_api_helper.ts @@ -0,0 +1,86 @@ +/* + * 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 type { Client } from '@elastic/elasticsearch'; +import type { Agent as SuperTestAgent } from 'supertest'; +import expect from '@kbn/expect'; +import type { ToolingLog } from '@kbn/tooling-log'; +import type { ThresholdParams } from '@kbn/observability-plugin/common/custom_threshold_rule/types'; +import { refreshSavedObjectIndices } from './refresh_index'; + +export async function createIndexConnector({ + supertest, + name, + indexName, + logger, +}: { + supertest: SuperTestAgent; + name: string; + indexName: string; + logger: ToolingLog; +}) { + const { body } = await supertest + .post(`/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + name, + config: { + index: indexName, + refresh: true, + }, + connector_type_id: '.index', + }) + .expect(200); + + logger.debug(`Created index connector id: ${body.id}`); + return body.id as string; +} + +export async function createRule({ + supertest, + name, + ruleTypeId, + params, + actions = [], + tags = [], + schedule, + consumer, + logger, + esClient, +}: { + supertest: SuperTestAgent; + ruleTypeId: string; + name: string; + params: Params; + actions?: any[]; + tags?: any[]; + schedule?: { interval: string }; + consumer: string; + logger: ToolingLog; + esClient: Client; +}) { + const { body, status } = await supertest + .post(`/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send({ + params, + consumer, + schedule: schedule || { + interval: '5m', + }, + tags, + name, + rule_type_id: ruleTypeId, + actions, + }); + + expect(status).to.eql(200, JSON.stringify(body)); + + await refreshSavedObjectIndices(esClient); + logger.debug(`Created rule id: ${body.id}`); + return body; +} diff --git a/x-pack/test/common/utils/observability/alerting_wait_for_helpers.ts b/x-pack/test/common/utils/observability/alerting_wait_for_helpers.ts new file mode 100644 index 0000000000000..ab2dca9154ff1 --- /dev/null +++ b/x-pack/test/common/utils/observability/alerting_wait_for_helpers.ts @@ -0,0 +1,156 @@ +/* + * 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 type { ToolingLog } from '@kbn/tooling-log'; + +import type SuperTest from 'supertest'; +import type { Client } from '@elastic/elasticsearch'; +import type { AggregationsAggregate, SearchResponse } from '@elastic/elasticsearch/lib/api/types'; +import type { RetryService } from '@kbn/ftr-common-functional-services'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { retry } from './retry'; + +const TIMEOUT = 70_000; +const RETRIES = 120; +const RETRY_DELAY = 500; + +export async function waitForRuleStatus({ + id, + expectedStatus, + supertest, + retryService, + logger, +}: { + id: string; + expectedStatus: string; + supertest: SuperTest.Agent; + retryService: RetryService; + logger: ToolingLog; +}): Promise> { + const ruleResponse = await retry>({ + testFn: async () => { + const response = await supertest.get(`/api/alerting/rule/${id}`); + const { execution_status: executionStatus } = response.body || {}; + const { status } = executionStatus || {}; + if (status !== expectedStatus) { + throw new Error(`waitForStatus(${expectedStatus}): got ${status}`); + } + return executionStatus; + }, + utilityName: 'fetching rule', + logger, + retryService, + timeout: TIMEOUT, + retries: RETRIES, + retryDelay: RETRY_DELAY, + }); + + return ruleResponse; +} + +export async function waitForDocumentInIndex({ + esClient, + indexName, + docCountTarget = 1, + retryService, + logger, + timeout = TIMEOUT, + retries = RETRIES, + retryDelay = RETRY_DELAY, + filters, +}: { + esClient: Client; + indexName: string; + docCountTarget?: number; + retryService: RetryService; + logger: ToolingLog; + timeout?: number; + retries?: number; + retryDelay?: number; + filters?: QueryDslQueryContainer[]; +}): Promise>> { + return await retry>>({ + testFn: async () => { + const response = await esClient.search({ + index: indexName, + rest_total_hits_as_int: true, + ignore_unavailable: true, + ...(filters + ? { + query: { + bool: { + filter: filters, + }, + }, + } + : undefined), + }); + if (!response.hits.total || (response.hits.total as number) < docCountTarget) { + logger.debug(`Document count is ${response.hits.total}, should be ${docCountTarget}`); + throw new Error( + `Number of hits does not match expectation (total: ${response.hits.total}, target: ${docCountTarget})` + ); + } + logger.debug(`Returned document: ${JSON.stringify(response.hits.hits[0])}`); + return response; + }, + utilityName: `waiting for documents in ${indexName} index`, + logger, + retryService, + timeout, + retries, + retryDelay, + }); +} + +export async function waitForAlertInIndex({ + esClient, + indexName, + ruleId, + retryService, + logger, + filters = [], + retryDelay, +}: { + esClient: Client; + indexName: string; + ruleId: string; + retryService: RetryService; + logger: ToolingLog; + filters?: QueryDslQueryContainer[]; + retryDelay?: number; +}): Promise>> { + return await retry>>({ + testFn: async () => { + const response = await esClient.search({ + index: indexName, + query: { + bool: { + filter: [ + { + term: { + 'kibana.alert.rule.uuid': ruleId, + }, + }, + ...filters, + ], + }, + }, + }); + if (response.hits.hits.length === 0) { + throw new Error(`No hits found for the ruleId: ${ruleId}`); + } + return response; + }, + utilityName: `waiting for alerting document in the alerting index (${indexName})`, + logger, + retryService, + timeout: TIMEOUT, + retries: RETRIES, + retryDelay: retryDelay ?? RETRY_DELAY, + }); +} diff --git a/x-pack/test/common/utils/observability/refresh_index.ts b/x-pack/test/common/utils/observability/refresh_index.ts new file mode 100644 index 0000000000000..2933779ea8969 --- /dev/null +++ b/x-pack/test/common/utils/observability/refresh_index.ts @@ -0,0 +1,36 @@ +/* + * 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 type { Client } from '@elastic/elasticsearch'; +import { ALL_SAVED_OBJECT_INDICES } from '@kbn/core-saved-objects-server'; + +/** + * Copied from x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/refresh_index.ts + * + * Refresh an index, making changes available to search. + * Reusable utility which refreshes all saved object indices, to make them available for search, especially + * useful when needing to perform a search on an index that has just been written to. + * + * An example of this when installing the prebuilt detection rules SO of type 'security-rule': + * the savedObjectsClient does this with a call with explicit `refresh: false`. + * So, despite of the fact that the endpoint waits until the prebuilt rule will be + * successfully indexed, it doesn't wait until they become "visible" for subsequent read + * operations. + * + * Additionally, this method clears the cache for all saved object indices. This helps in cases in which + * saved object is read, then written to, and then read again, and the second read returns stale data. + * @param es The Elasticsearch client + */ +export const refreshSavedObjectIndices = async (es: Client) => { + // Refresh indices to prevent a race condition between a write and subsequent read operation. To + // fix it deterministically we have to refresh saved object indices and wait until it's done. + await es.indices.refresh({ index: ALL_SAVED_OBJECT_INDICES, ignore_unavailable: true }); + + // Additionally, we need to clear the cache to ensure that the next read operation will + // not return stale data. + await es.indices.clearCache({ index: ALL_SAVED_OBJECT_INDICES, ignore_unavailable: true }); +}; diff --git a/x-pack/test/common/utils/observability/retry.ts b/x-pack/test/common/utils/observability/retry.ts new file mode 100644 index 0000000000000..74755064cdf01 --- /dev/null +++ b/x-pack/test/common/utils/observability/retry.ts @@ -0,0 +1,92 @@ +/* + * 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 type { RetryService } from '@kbn/ftr-common-functional-services'; +import type { ToolingLog } from '@kbn/tooling-log'; + +/** + * Copied from x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/retry.ts + * + * Retry wrapper for async supertests, with a maximum number of retries. + * You can pass in a function that executes a supertest test, and make assertions + * on the response. If the test fails, it will retry the test the number of retries + * that are passed in. + * + * Example usage: + * ```ts + const fleetResponse = await retry({ + testFn: async () => { + const testResponse = await supertest + .post(`/api/fleet/epm/packages/security_detection_engine`) + .set('kbn-xsrf', 'xxxx') + .set('elastic-api-version', '2023-10-31') + .type('application/json') + .send({ force: true }) + .expect(200); + expect((testResponse.body as InstallPackageResponse).items).toBeDefined(); + expect((testResponse.body as InstallPackageResponse).items.length).toBeGreaterThan(0); + + return testResponse.body; + }, + retryService, + retries: MAX_RETRIES, + timeout: ATTEMPT_TIMEOUT, + }); + * ``` + * @param test The function containing a test to run + * @param retryService The retry service to use + * @param retries The maximum number of retries + * @param timeout The timeout for each retry + * @param retryDelay The delay between each retry + * @returns The response from the test + */ +export const retry = async ({ + testFn, + retryService, + utilityName, + retries = 3, + timeout = 30000, + retryDelay = 200, + logger, +}: { + testFn: () => Promise; + utilityName: string; + retryService: RetryService; + retries?: number; + timeout?: number; + retryDelay?: number; + logger: ToolingLog; +}): Promise => { + let retryAttempt = 0; + const response = await retryService.tryForTime( + timeout, + async () => { + if (retryAttempt > retries) { + // Log error message if we reached the maximum number of retries + // but don't throw an error, return it to break the retry loop. + const errorMessage = `Reached maximum number of retries for test ${utilityName}: ${ + retryAttempt - 1 + }/${retries}`; + logger.error(errorMessage); + return new Error(errorMessage); + } + + retryAttempt = retryAttempt + 1; + + return await testFn(); + }, + undefined, + retryDelay + ); + + // Now throw the error in order to fail the test. + if (response instanceof Error) { + throw response; + } + + return response; +}; diff --git a/x-pack/test/common/utils/uptime/fixtures/monitor_charts.json b/x-pack/test/common/utils/uptime/fixtures/monitor_charts.json new file mode 100644 index 0000000000000..e96b3b3b562b9 --- /dev/null +++ b/x-pack/test/common/utils/uptime/fixtures/monitor_charts.json @@ -0,0 +1,89 @@ +{ + "locationDurationLines": [ + { + "name": "mpls", + "line": [ + { + "x": 1568172664000, + "y": 16274 + }, + { + "x": 1568172694000, + "y": 16713 + }, + { + "x": 1568172724000, + "y": 34756 + }, + { + "x": 1568172754000, + "y": 22205 + }, + { + "x": 1568172784000, + "y": 6071 + }, + { + "x": 1568172814000, + "y": 15681 + }, + { + "x": 1568172844000, + "y": 1669 + }, + { + "x": 1568172874000, + "y": 956 + }, + { + "x": 1568172904000, + "y": 1435 + }, + { + "x": 1568172934000, + "y": 32906 + }, + { + "x": 1568172964000, + "y": 892 + }, + { + "x": 1568172994000, + "y": 1514 + }, + { + "x": 1568173024000, + "y": 2367 + }, + { + "x": 1568173054000, + "y": 3389 + }, + { + "x": 1568173084000, + "y": 362 + }, + { + "x": 1568173114000, + "y": 3066 + }, + { + "x": 1568173144000, + "y": 44513 + }, + { + "x": 1568173174000, + "y": 6417 + }, + { + "x": 1568173204000, + "y": 1416 + }, + { + "x": 1568173234000, + "y": 24627 + } + ] + } + ] +} \ No newline at end of file diff --git a/x-pack/test/common/utils/uptime/fixtures/monitor_latest_status.json b/x-pack/test/common/utils/uptime/fixtures/monitor_latest_status.json new file mode 100644 index 0000000000000..a97ee98123885 --- /dev/null +++ b/x-pack/test/common/utils/uptime/fixtures/monitor_latest_status.json @@ -0,0 +1,57 @@ +{ + "observer": { + "geo": { + "name": "mpls", + "location": "37.926868, -78.024902" + }, + "hostname": "avc-x1x" + }, + "@timestamp": "2019-09-11T03:40:34.371Z", + "http": { + "rtt": { + "response_header": { + "us": 262 + }, + "total": { + "us": 20331 + }, + "write_request": { + "us": 82 + }, + "content": { + "us": 57 + }, + "validate": { + "us": 319 + } + }, + "response": { + "status_code": 200, + "body": { + "bytes": 3, + "hash": "27badc983df1780b60c2b3fa9d3a19a00e46aac798451f0febdca52920faaddf" + } + } + }, + "monitor": { + "duration": { + "us": 24627 + }, + "ip": "127.0.0.1", + "name": "", + "check_group": "d76f0762-d445-11e9-88e3-3e80641b9c71", + "id": "0002-up", + "type": "http", + "status": "up" + }, + "url": { + "path": "/pattern", + "scheme": "http", + "port": 5678, + "domain": "localhost", + "query": "r=200x1", + "full": "http://localhost:5678/pattern?r=200x1" + }, + "docId": "h5toHm0B0I9WX_CznN_V", + "timestamp": "2019-09-11T03:40:34.371Z" +} \ No newline at end of file diff --git a/x-pack/test/common/utils/uptime/fixtures/monitor_status.json b/x-pack/test/common/utils/uptime/fixtures/monitor_status.json new file mode 100644 index 0000000000000..10108b5a04c92 --- /dev/null +++ b/x-pack/test/common/utils/uptime/fixtures/monitor_status.json @@ -0,0 +1,154 @@ +{ + "monitorStatus": [ + { + "timestamp": "2019-01-28T18:43:16.078Z", + "monitor": { + "status": "up", + "duration": { + "us": 3328 + } + }, + "observer": null, + "tls": null, + "url": { + "full": "tcp://localhost:9200" + } + }, + { + "timestamp": "2019-01-28T18:43:13.074Z", + "monitor": { + "status": "up", + "duration": { + "us": 299586 + } + }, + "observer": null, + "tls": null, + "url": { + "full": "http://www.reddit.com/" + } + }, + { + "timestamp": "2019-01-28T18:43:13.074Z", + "monitor": { + "status": "up", + "duration": { + "us": 850870 + } + }, + "observer": null, + "tls": { + "certificate_not_valid_after": "2019-10-12T00:32:18.000Z" + }, + "url": { + "full": "https://www.elastic.co" + } + }, + { + "timestamp": "2019-01-28T18:43:15.077Z", + "monitor": { + "status": "down", + "duration": { + "us": 3331 + } + }, + "observer": null, + "tls": null, + "url": { + "full": "http://localhost:12349/" + } + }, + { + "timestamp": "2019-01-28T18:43:15.077Z", + "monitor": { + "status": "up", + "duration": { + "us": 132169 + } + }, + "observer": null, + "tls": { + "certificate_not_valid_after": "2019-03-13T08:16:00.000Z" + }, + "url": { + "full": "https://www.google.com/" + } + }, + { + "timestamp": "2019-01-28T18:43:15.077Z", + "monitor": { + "status": "up", + "duration": { + "us": 247244 + } + }, + "observer": null, + "tls": { + "certificate_not_valid_after": "2020-06-03T12:00:00.000Z" + }, + "url": { + "full": "https://www.github.com/" + } + }, + { + "timestamp": "2019-01-28T18:43:15.077Z", + "monitor": { + "status": "up", + "duration": { + "us": 118727 + } + }, + "observer": null, + "tls": null, + "url": { + "full": "http://www.google.com/" + } + }, + { + "timestamp": "2019-01-28T18:43:07.078Z", + "monitor": { + "status": "down", + "duration": { + "us": 4751074 + } + }, + "observer": null, + "tls": null, + "url": { + "full": "http://www.example.com/" + } + }, + { + "timestamp": "2019-01-28T18:42:55.074Z", + "monitor": { + "status": "up", + "duration": { + "us": 1164812 + } + }, + "observer": null, + "tls": { + "certificate_not_valid_after": "2019-11-22T07:59:59.000Z" + }, + "url": { + "full": "https://www.wikipedia.org/" + } + }, + { + "timestamp": "2019-01-28T18:42:55.074Z", + "monitor": { + "status": "up", + "duration": { + "us": 2059606 + } + }, + "observer": null, + "tls": { + "certificate_not_valid_after": "2019-03-13T08:16:00.000Z" + }, + "url": { + "full": "https://news.google.com/" + } + } + ] +} \ No newline at end of file diff --git a/x-pack/test/common/utils/uptime/fixtures/monitor_status_all.json b/x-pack/test/common/utils/uptime/fixtures/monitor_status_all.json new file mode 100644 index 0000000000000..9b91ce3f1e03c --- /dev/null +++ b/x-pack/test/common/utils/uptime/fixtures/monitor_status_all.json @@ -0,0 +1,1802 @@ +[ + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 15167 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x5,500x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 35534 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 24627 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 2569 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 35258 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 19044 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 14876 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 1254 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 1926 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 35620 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "down", + "duration": { + "us": 37926 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=400x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 37168 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 19470 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 18192 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 33904 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 1544 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x5,500x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 35587 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 34550 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 36410 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 24177 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "down", + "duration": { + "us": 14900 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=400x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 15123 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 34525 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 35289 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 13614 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 33974 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 33311 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 36139 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 35573 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 35594 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "down", + "duration": { + "us": 17146 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x5,500x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.374Z", + "monitor": { + "status": "up", + "duration": { + "us": 21874 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.375Z", + "monitor": { + "status": "up", + "duration": { + "us": 15065 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 3874 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 35060 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 1637 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 3426 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 18348 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 34355 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 18338 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "down", + "duration": { + "us": 18106 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=400x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 13666 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 17255 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 36248 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 35652 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 16290 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x5,500x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.374Z", + "monitor": { + "status": "up", + "duration": { + "us": 16135 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.390Z", + "monitor": { + "status": "up", + "duration": { + "us": 365 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.386Z", + "monitor": { + "status": "up", + "duration": { + "us": 4784 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.405Z", + "monitor": { + "status": "up", + "duration": { + "us": 602 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.386Z", + "monitor": { + "status": "down", + "duration": { + "us": 4258 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=400x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 35234 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 19965 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 2120 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 35140 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 37103 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 36842 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 1426 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 1526 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 18682 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 13605 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x5,500x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 18194 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 22666 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 17770 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 35698 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 17587 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.374Z", + "monitor": { + "status": "up", + "duration": { + "us": 36584 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.374Z", + "monitor": { + "status": "up", + "duration": { + "us": 15499 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.374Z", + "monitor": { + "status": "up", + "duration": { + "us": 15464 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.375Z", + "monitor": { + "status": "up", + "duration": { + "us": 15183 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.375Z", + "monitor": { + "status": "down", + "duration": { + "us": 15117 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=400x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.375Z", + "monitor": { + "status": "up", + "duration": { + "us": 14875 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.376Z", + "monitor": { + "status": "up", + "duration": { + "us": 14580 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.406Z", + "monitor": { + "status": "up", + "duration": { + "us": 441 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.410Z", + "monitor": { + "status": "up", + "duration": { + "us": 413 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.406Z", + "monitor": { + "status": "up", + "duration": { + "us": 304 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x5,500x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.387Z", + "monitor": { + "status": "up", + "duration": { + "us": 2808 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.389Z", + "monitor": { + "status": "up", + "duration": { + "us": 870 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 24419 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "up", + "duration": { + "us": 35454 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.371Z", + "monitor": { + "status": "down", + "duration": { + "us": 36171 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=400x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 36785 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.372Z", + "monitor": { + "status": "up", + "duration": { + "us": 35312 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 13442 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 3148 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 33506 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 35830 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 34600 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 33693 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.373Z", + "monitor": { + "status": "up", + "duration": { + "us": 33833 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.374Z", + "monitor": { + "status": "up", + "duration": { + "us": 21736 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x5,500x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.374Z", + "monitor": { + "status": "up", + "duration": { + "us": 15428 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.375Z", + "monitor": { + "status": "up", + "duration": { + "us": 15308 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.375Z", + "monitor": { + "status": "up", + "duration": { + "us": 15013 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.375Z", + "monitor": { + "status": "up", + "duration": { + "us": 14911 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.375Z", + "monitor": { + "status": "up", + "duration": { + "us": 14801 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.376Z", + "monitor": { + "status": "up", + "duration": { + "us": 14679 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.405Z", + "monitor": { + "status": "up", + "duration": { + "us": 487 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.406Z", + "monitor": { + "status": "up", + "duration": { + "us": 558 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + }, + { + "timestamp": "2019-09-11T03:40:34.406Z", + "monitor": { + "status": "up", + "duration": { + "us": 482 + } + }, + "observer": { + "geo": { + "name": "mpls" + } + }, + "tls": null, + "url": { + "full": "http://localhost:5678/pattern?r=200x1" + } + } +] \ No newline at end of file diff --git a/x-pack/test/common/utils/uptime/fixtures/monitors_with_location.json b/x-pack/test/common/utils/uptime/fixtures/monitors_with_location.json new file mode 100644 index 0000000000000..7f82c41c9ca40 --- /dev/null +++ b/x-pack/test/common/utils/uptime/fixtures/monitors_with_location.json @@ -0,0 +1,720 @@ +{ + "monitorStatus": { + "monitors": [ + { + "id": { + "key": "auto-http-0X21EE76EAC459873F", + "url": "http://localhost:12349/test-page" + }, + "ping": { + "timestamp": "2019-06-03T14:14:27.737Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 1621 + }, + "id": "auto-http-0X21EE76EAC459873F", + "ip": "127.0.0.1", + "name": "test-page", + "status": "down" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "localhost", + "full": "http://localhost:12349/test-page" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": null + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": 47 + } + ] + }, + { + "id": { + "key": "auto-http-0X2AF1D7DB9C490053", + "url": "http://35.245.22.113:12349/" + }, + "ping": { + "timestamp": "2019-06-03T14:14:06.733Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 16003323 + }, + "id": "auto-http-0X2AF1D7DB9C490053", + "ip": "35.245.22.113", + "name": "prod-site", + "status": "down" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "35.245.22.113", + "full": "http://35.245.22.113:12349/" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": null + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": 2 + } + ] + }, + { + "id": { + "key": "auto-http-0X3F1F767F45156CB3", + "url": "http://localhost:9200" + }, + "ping": { + "timestamp": "2019-06-03T14:14:20.727Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 2965 + }, + "id": "auto-http-0X3F1F767F45156CB3", + "ip": "127.0.0.1", + "name": "", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "localhost", + "full": "http://localhost:9200" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 4 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + }, + { + "id": { + "key": "auto-http-0X3F1F767F45156CB3", + "url": "http://localhost:9200" + }, + "ping": { + "timestamp": "2019-06-03T14:14:25.054Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 3010 + }, + "id": "auto-http-0X3F1F767F45156CB3", + "ip": "127.0.0.1", + "name": "", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "us-east-1" + } + }, + "url": { + "domain": "localhost", + "full": "http://localhost:9200" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 4 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + }, + { + "id": { + "key": "auto-http-0X55511C5F7D2442BF", + "url": "http://35.245.22.113:12349/test-page" + }, + "ping": { + "timestamp": "2019-06-03T14:14:06.733Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 16003395 + }, + "id": "auto-http-0X55511C5F7D2442BF", + "ip": "35.245.22.113", + "name": "prod-site-page", + "status": "down" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "35.245.22.113", + "full": "http://35.245.22.113:12349/test-page" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": null + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": 2 + } + ] + }, + { + "id": { + "key": "auto-http-0X7BD0BBBE9FCA62B3", + "url": "https://www.elastic.co/" + }, + "ping": { + "timestamp": "2019-06-03T14:14:21.734Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 1166542 + }, + "id": "auto-http-0X7BD0BBBE9FCA62B3", + "ip": "151.101.202.217", + "name": "elastic-website", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "www.elastic.co", + "full": "https://www.elastic.co/" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 4 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + }, + { + "id": { + "key": "auto-http-0X89BB0F9A6C81D178", + "url": "http://localhost:12349/" + }, + "ping": { + "timestamp": "2019-06-03T14:14:27.737Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 1668 + }, + "id": "auto-http-0X89BB0F9A6C81D178", + "ip": "127.0.0.1", + "name": "my-new-test-site-name", + "status": "down" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "localhost", + "full": "http://localhost:12349/" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": null + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": 46 + } + ] + }, + { + "id": { + "key": "auto-icmp-0X5E0870F7B7178EFD", + "url": "icmp://0.0.0.0" + }, + "ping": { + "timestamp": "2019-06-03T14:14:25.003Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 83 + }, + "id": "auto-icmp-0X5E0870F7B7178EFD", + "ip": "0.0.0.0", + "name": "anothericmp", + "status": "down" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "0.0.0.0", + "full": "icmp://0.0.0.0" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": null + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": 9 + } + ] + }, + { + "id": { + "key": "auto-icmp-0XC841A2D2853DF259", + "url": "icmp://8.8.8.8" + }, + "ping": { + "timestamp": "2019-06-03T14:14:25.003Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 14216 + }, + "id": "auto-icmp-0XC841A2D2853DF259", + "ip": "8.8.8.8", + "name": "icmptest", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "8.8.8.8", + "full": "icmp://8.8.8.8" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 9 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + }, + { + "id": { + "key": "auto-tcp-0X43965CDA26D0025F", + "url": "tcp://news.google.com:80" + }, + "ping": { + "timestamp": "2019-06-03T14:14:26.734Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 15977 + }, + "id": "auto-tcp-0X43965CDA26D0025F", + "ip": "172.217.7.174", + "name": "", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "news.google.com", + "full": "tcp://news.google.com:80" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 9 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + }, + { + "id": { + "key": "auto-tcp-0X709158D957AE02A5", + "url": "tcp://www.google.com:80" + }, + "ping": { + "timestamp": "2019-06-03T14:14:26.737Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 17621 + }, + "id": "auto-tcp-0X709158D957AE02A5", + "ip": "172.217.7.228", + "name": "", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "www.google.com", + "full": "tcp://www.google.com:80" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 9 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + }, + { + "id": { + "key": "auto-tcp-0X7BAA5C23EED7A602", + "url": "tcp://localhost:9200" + }, + "ping": { + "timestamp": "2019-06-03T14:14:26.737Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 3086 + }, + "id": "auto-tcp-0X7BAA5C23EED7A602", + "ip": "127.0.0.1", + "name": "", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "localhost", + "full": "tcp://localhost:9200" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 10 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + }, + { + "id": { + "key": "auto-tcp-0X7D120A181386F6FF", + "url": "tcp://www.reddit.com:80" + }, + "ping": { + "timestamp": "2019-06-03T14:14:26.736Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 42310 + }, + "id": "auto-tcp-0X7D120A181386F6FF", + "ip": "151.101.201.140", + "name": "", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "www.reddit.com", + "full": "tcp://www.reddit.com:80" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 9 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + }, + { + "id": { + "key": "auto-tcp-0X9B871DF976CE3FF6", + "url": "tcp://www.twitter.com:80" + }, + "ping": { + "timestamp": "2019-06-03T14:14:26.736Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 26996 + }, + "id": "auto-tcp-0X9B871DF976CE3FF6", + "ip": "104.244.42.65", + "name": "", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "www.twitter.com", + "full": "tcp://www.twitter.com:80" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 9 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + }, + { + "id": { + "key": "auto-tcp-0XB5135CCF01B9181", + "url": "tcp://www.amazon.com:80" + }, + "ping": { + "timestamp": "2019-06-03T14:14:26.736Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 22589 + }, + "id": "auto-tcp-0XB5135CCF01B9181", + "ip": "184.24.104.59", + "name": "", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "www.amazon.com", + "full": "tcp://www.amazon.com:80" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 9 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + }, + { + "id": { + "key": "auto-tcp-0XCEFD11A886FD7BFB", + "url": "tcp://www.facebook.com:80" + }, + "ping": { + "timestamp": "2019-06-03T14:14:26.734Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 15957 + }, + "id": "auto-tcp-0XCEFD11A886FD7BFB", + "ip": "31.13.66.35", + "name": "", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "www.facebook.com", + "full": "tcp://www.facebook.com:80" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 9 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + }, + { + "id": { + "key": "auto-tcp-0XD9E69ACFD41A759C", + "url": "tcp://www.netflix.com:80" + }, + "ping": { + "timestamp": "2019-06-03T14:14:26.734Z", + "container": null, + "kubernetes": null, + "monitor": { + "duration": { + "us": 20475 + }, + "id": "auto-tcp-0XD9E69ACFD41A759C", + "ip": "34.194.103.209", + "name": "", + "status": "up" + }, + "observer": { + "geo": { + "location": "39.9526, 75.1652", + "name": "europe-west-1" + } + }, + "url": { + "domain": "www.netflix.com", + "full": "tcp://www.netflix.com:80" + } + }, + "upSeries": [ + { + "x": 1559571053760, + "y": 9 + } + ], + "downSeries": [ + { + "x": 1559571053760, + "y": null + } + ] + } + ] + } +} diff --git a/x-pack/test/common/utils/uptime/fixtures/ping_histogram.json b/x-pack/test/common/utils/uptime/fixtures/ping_histogram.json new file mode 100644 index 0000000000000..22f1fc168ae66 --- /dev/null +++ b/x-pack/test/common/utils/uptime/fixtures/ping_histogram.json @@ -0,0 +1,161 @@ +{ + "histogram": [ + { + "x": 1568172657286, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172680087, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172702888, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172725689, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568172748490, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172771291, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172794092, + "downCount": 8, + "upCount": 92, + "y": 1 + }, + { + "x": 1568172816893, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568172839694, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172862495, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172885296, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172908097, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568172930898, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172953699, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172976500, + "downCount": 8, + "upCount": 92, + "y": 1 + }, + { + "x": 1568172999301, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568173022102, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173044903, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173067704, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173090505, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568173113306, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173136107, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173158908, + "downCount": 8, + "upCount": 92, + "y": 1 + }, + { + "x": 1568173181709, + "downCount": 7, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173204510, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568173227311, + "downCount": 7, + "upCount": 93, + "y": 1 + } + ], + "minInterval": 22801 +} \ No newline at end of file diff --git a/x-pack/test/common/utils/uptime/fixtures/ping_histogram_by_filter.json b/x-pack/test/common/utils/uptime/fixtures/ping_histogram_by_filter.json new file mode 100644 index 0000000000000..f03827c909347 --- /dev/null +++ b/x-pack/test/common/utils/uptime/fixtures/ping_histogram_by_filter.json @@ -0,0 +1,161 @@ +{ + "histogram": [ + { + "x": 1568172657286, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172680087, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172702888, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172725689, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568172748490, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172771291, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172794092, + "downCount": 0, + "upCount": 92, + "y": 1 + }, + { + "x": 1568172816893, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568172839694, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172862495, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172885296, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172908097, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568172930898, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172953699, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568172976500, + "downCount": 0, + "upCount": 92, + "y": 1 + }, + { + "x": 1568172999301, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568173022102, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173044903, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173067704, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173090505, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568173113306, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173136107, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173158908, + "downCount": 0, + "upCount": 92, + "y": 1 + }, + { + "x": 1568173181709, + "downCount": 0, + "upCount": 93, + "y": 1 + }, + { + "x": 1568173204510, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568173227311, + "downCount": 0, + "upCount": 93, + "y": 1 + } + ], + "minInterval": 22801 +} \ No newline at end of file diff --git a/x-pack/test/common/utils/uptime/fixtures/ping_histogram_by_id.json b/x-pack/test/common/utils/uptime/fixtures/ping_histogram_by_id.json new file mode 100644 index 0000000000000..fbff31ebe03b6 --- /dev/null +++ b/x-pack/test/common/utils/uptime/fixtures/ping_histogram_by_id.json @@ -0,0 +1,161 @@ +{ + "histogram": [ + { + "x": 1568172657286, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172680087, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172702888, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172725689, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568172748490, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172771291, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172794092, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172816893, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568172839694, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172862495, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172885296, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172908097, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568172930898, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172953699, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172976500, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568172999301, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568173022102, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568173044903, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568173067704, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568173090505, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568173113306, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568173136107, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568173158908, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568173181709, + "downCount": 0, + "upCount": 1, + "y": 1 + }, + { + "x": 1568173204510, + "downCount": 0, + "upCount": 0, + "y": 1 + }, + { + "x": 1568173227311, + "downCount": 0, + "upCount": 1, + "y": 1 + } + ], + "minInterval": 22801 +} \ No newline at end of file diff --git a/x-pack/test/common/utils/uptime/helper/expect_fixture_eql.ts b/x-pack/test/common/utils/uptime/helper/expect_fixture_eql.ts new file mode 100644 index 0000000000000..c82ec536fd1ae --- /dev/null +++ b/x-pack/test/common/utils/uptime/helper/expect_fixture_eql.ts @@ -0,0 +1,46 @@ +/* + * 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 expect from '@kbn/expect'; +import fs from 'fs'; +import { join } from 'path'; +import { cloneDeep, isEqual } from 'lodash'; + +const fixturesDir = join(__dirname, '..', 'fixtures'); + +const excludeFieldsFrom = (from: any, excluder?: (d: any) => any): any => { + const clone = cloneDeep(from); + if (excluder) { + excluder(clone); + } + return clone; +}; + +export const expectFixtureEql = (data: T, fixtureName: string, excluder?: (d: T) => void) => { + expect(data).not.to.eql(null); + expect(data).not.to.eql(undefined); + + const fixturePath = join(fixturesDir, `${fixtureName}.json`); + + excluder = excluder || ((d) => d); + const dataExcluded = excludeFieldsFrom(data, excluder); + expect(dataExcluded).not.to.be(undefined); + const fixtureExists = () => fs.existsSync(dataExcluded); + const fixtureChanged = () => + !isEqual( + dataExcluded, + excludeFieldsFrom(JSON.parse(fs.readFileSync(fixturePath, 'utf8')), excluder) + ); + if (process.env.UPDATE_UPTIME_FIXTURES && (!fixtureExists() || fixtureChanged())) { + // Check if the data has changed. We can't simply write it because the order of attributes + // can change leading to different bytes on disk, which we don't care about + fs.writeFileSync(fixturePath, JSON.stringify(dataExcluded, null, 2)); + } + const fileContents = fs.readFileSync(fixturePath, 'utf8'); + const fixture = JSON.parse(fileContents); + expect(dataExcluded).to.eql(excludeFieldsFrom(fixture, excluder)); +}; diff --git a/x-pack/test/common/utils/uptime/helper/make_checks.ts b/x-pack/test/common/utils/uptime/helper/make_checks.ts new file mode 100644 index 0000000000000..9b5d1f2df1ce6 --- /dev/null +++ b/x-pack/test/common/utils/uptime/helper/make_checks.ts @@ -0,0 +1,175 @@ +/* + * 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 { v4 as uuidv4 } from 'uuid'; +import { merge, flattenDeep } from 'lodash'; +import type { Client } from '@elastic/elasticsearch'; +import { makePing } from './make_ping'; +import { TlsProps } from './make_tls'; + +interface CheckProps { + es: Client; + monitorId?: string; + numIps?: number; + fields?: { [key: string]: any }; + mogrify?: (doc: any) => any; + refresh?: boolean; + tls?: boolean | TlsProps; + customIndex?: string; +} + +const getRandomMonitorId = () => { + return 'monitor-' + Math.random().toString(36).substring(7); +}; +export const makeCheck = async ({ + es, + monitorId = getRandomMonitorId(), + numIps = 1, + fields = {}, + mogrify = (d) => d, + refresh = true, + tls = false, + customIndex, +}: CheckProps): Promise<{ monitorId: string; docs: any }> => { + const cgFields = { + monitor: { + check_group: fields.monitor?.check_group || uuidv4(), + }, + }; + + const docs = []; + const summary = { + up: 0, + down: 0, + }; + for (let i = 0; i < numIps; i++) { + const pingFields = merge(fields, cgFields, { + monitor: { + ip: `127.0.0.${i}`, + }, + }); + if (i === numIps - 1 && fields.summary !== null) { + pingFields.summary = summary; + } + const doc = await makePing(es, monitorId, pingFields, mogrify, false, tls as any, customIndex); + docs.push(doc); + // @ts-ignore + summary[doc.monitor.status]++; + } + + if (refresh) { + await es.indices.refresh(); + } + + return { monitorId, docs }; +}; + +export const makeChecks = async ( + es: Client, + monitorId: string, + numChecks: number = 1, + numIps: number = 1, + every: number = 10000, // number of millis between checks + fields: { [key: string]: any } = {}, + mogrify: (doc: any) => any = (d) => d, + refresh: boolean = true, + customIndex?: string +) => { + const checks = []; + const oldestTime = new Date().getTime() - numChecks * every; + let newestTime = oldestTime; + for (let li = 0; li < numChecks; li++) { + const checkDate = new Date(newestTime + every); + newestTime = checkDate.getTime() + every; + fields = merge(fields, { + '@timestamp': checkDate.toISOString(), + monitor: { + timespan: { + gte: checkDate.toISOString(), + lt: new Date(newestTime).toISOString(), + }, + }, + }); + const { docs } = await makeCheck({ + es, + monitorId, + numIps, + fields, + mogrify, + refresh: false, + customIndex, + }); + checks.push(docs); + } + + if (refresh) { + await es.indices.refresh(); + } + + return checks; +}; + +export const makeChecksWithStatus = async ( + es: Client, + monitorId: string, + numChecks: number, + numIps: number, + every: number, + fields: { [key: string]: any } = {}, + status: 'up' | 'down', + mogrify: (doc: any) => any = (d) => d, + refresh: boolean = true, + customIndex?: string +) => { + const oppositeStatus = status === 'up' ? 'down' : 'up'; + + return await makeChecks( + es, + monitorId, + numChecks, + numIps, + every, + fields, + (d) => { + d.monitor.status = status; + if (d.summary) { + d.summary[status] += d.summary[oppositeStatus]; + d.summary[oppositeStatus] = 0; + d.summary.final_attempt = true; + } + + return mogrify(d); + }, + refresh, + customIndex + ); +}; + +// Helper for processing a list of checks to find the time picker bounds. +export const getChecksDateRange = (checks: any[]) => { + // Flatten 2d arrays + const flattened = flattenDeep(checks); + + let startTime = 1 / 0; + let endTime = -1 / 0; + flattened.forEach((c) => { + const ts = Date.parse(c['@timestamp']); + + if (ts < startTime) { + startTime = ts; + } + + if (ts > endTime) { + endTime = ts; + } + }); + + return { + start: new Date(startTime).toISOString(), + end: new Date(endTime).toISOString(), + }; +}; diff --git a/x-pack/test/common/utils/uptime/helper/make_ping.ts b/x-pack/test/common/utils/uptime/helper/make_ping.ts new file mode 100644 index 0000000000000..009f9a69cd31f --- /dev/null +++ b/x-pack/test/common/utils/uptime/helper/make_ping.ts @@ -0,0 +1,126 @@ +/* + * 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 { v4 as uuidv4 } from 'uuid'; +import { merge } from 'lodash'; +import type { Client } from '@elastic/elasticsearch'; +import { makeTls, TlsProps } from './make_tls'; + +const DEFAULT_INDEX_NAME = 'heartbeat-8-generated-test'; + +export const makePing = async ( + es: Client, + monitorId: string, + fields: { [key: string]: any }, + mogrify: (doc: any) => any, + refresh: boolean = true, + tls: boolean | TlsProps = false, + customIndex?: string +) => { + const timestamp = new Date(); + const baseDoc: any = { + tcp: { + rtt: { + connect: { + us: 14687, + }, + }, + }, + observer: { + geo: { + name: 'mpls', + location: '37.926868, -78.024902', + }, + hostname: 'avc-x1e', + }, + agent: { + hostname: 'avc-x1e', + id: '10730a1a-4cb7-45ce-8524-80c4820476ab', + type: 'heartbeat', + ephemeral_id: '0d9a8dc6-f604-49e3-86a0-d8f9d6f2cbad', + version: '8.0.0', + }, + '@timestamp': timestamp.toISOString(), + resolve: { + rtt: { + us: 350, + }, + ip: '127.0.0.1', + }, + ecs: { + version: '1.1.0', + }, + host: { + name: 'avc-x1e', + }, + http: { + rtt: { + response_header: { + us: 19349, + }, + total: { + us: 48954, + }, + write_request: { + us: 33, + }, + content: { + us: 51, + }, + validate: { + us: 19400, + }, + }, + response: { + status_code: 200, + body: { + bytes: 3, + hash: '27badc983df1780b60c2b3fa9d3a19a00e46aac798451f0febdca52920faaddf', + }, + }, + }, + monitor: { + duration: { + us: 49347, + }, + ip: '127.0.0.1', + id: monitorId, + check_group: uuidv4(), + type: 'http', + status: 'up', + timespan: { + gte: timestamp.toISOString(), + lt: new Date(timestamp.getTime() + 5000).toISOString, + }, + }, + event: { + dataset: 'uptime', + }, + url: { + path: '/pattern', + scheme: 'http', + port: 5678, + domain: 'localhost', + query: 'r=200x5,500x1', + full: 'http://localhost:5678/pattern?r=200x5,500x1', + }, + }; + + if (tls) { + baseDoc.tls = makeTls(tls as any); + } + + const document = mogrify(merge(baseDoc, fields)); + + await es.index({ + index: customIndex || DEFAULT_INDEX_NAME, + refresh, + document, + }); + + return document; +}; diff --git a/x-pack/test/common/utils/uptime/helper/make_tls.ts b/x-pack/test/common/utils/uptime/helper/make_tls.ts new file mode 100644 index 0000000000000..e654a2754e51d --- /dev/null +++ b/x-pack/test/common/utils/uptime/helper/make_tls.ts @@ -0,0 +1,68 @@ +/* + * 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 crypto from 'crypto'; + +export interface TlsProps { + valid?: boolean; + commonName?: string; + expiry?: string; + sha256?: string; +} + +type Props = TlsProps & boolean; + +// Note This is just a mock sha256 value, this doesn't actually generate actually sha 256 val +export const getSha256 = () => { + return crypto.randomBytes(64).toString('hex').toUpperCase(); +}; + +export const makeTls = ({ valid = true, commonName = '*.elastic.co', expiry, sha256 }: Props) => { + const expiryDate = + expiry ?? + moment() + .add(valid ? 2 : -2, 'months') + .toISOString(); + + return { + version: '1.3', + cipher: 'TLS-AES-128-GCM-SHA256', + certificate_not_valid_before: '2020-03-01T00:00:00.000Z', + certificate_not_valid_after: expiryDate, + server: { + x509: { + not_before: '2020-03-01T00:00:00.000Z', + not_after: expiryDate, + issuer: { + distinguished_name: + 'CN=DigiCert SHA2 High Assurance Server CA,OU=www.digicert.com,O=DigiCert Inc,C=US', + common_name: 'DigiCert SHA2 High Assurance Server CA', + }, + subject: { + common_name: commonName, + distinguished_name: 'CN=*.facebook.com,O=Facebook Inc.,L=Menlo Park,ST=California,C=US', + }, + serial_number: '10043199409725537507026285099403602396', + signature_algorithm: 'SHA256-RSA', + public_key_algorithm: 'ECDSA', + public_key_curve: 'P-256', + }, + hash: { + sha256: sha256 ?? '1a48f1db13c3bd1482ba1073441e74a1bb1308dc445c88749e0dc4f1889a88a4', + sha1: '23291c758d925b9f4bb3584de3763317e94c6ce9', + }, + }, + established: true, + rtt: { + handshake: { + us: 33103, + }, + }, + version_protocol: 'tls', + }; +}; diff --git a/x-pack/test/functional/apps/infra/metrics_source_configuration.ts b/x-pack/test/functional/apps/infra/metrics_source_configuration.ts index a8b2bd8c69df2..435200a90173d 100644 --- a/x-pack/test/functional/apps/infra/metrics_source_configuration.ts +++ b/x-pack/test/functional/apps/infra/metrics_source_configuration.ts @@ -11,11 +11,11 @@ import { Aggregators, MetricThresholdParams } from '@kbn/infra-plugin/common/ale import { COMPARATORS } from '@kbn/alerting-comparators'; import { InfraRuleType } from '@kbn/rule-data-utils'; -import { createRule } from '@kbn/test-suites-xpack-observability/alerting_api_integration/observability/helpers/alerting_api_helper'; +import { createRule } from '../../../common/utils/observability/alerting_api_helper'; import { waitForDocumentInIndex, waitForRuleStatus, -} from '@kbn/test-suites-xpack-observability/alerting_api_integration/observability/helpers/alerting_wait_for_helpers'; +} from '../../../common/utils/observability/alerting_wait_for_helpers'; import { FtrProviderContext } from '../../ftr_provider_context'; import { DATES } from './constants'; diff --git a/x-pack/test/functional/apps/uptime/certificates.ts b/x-pack/test/functional/apps/uptime/certificates.ts index a256c2f9e32d8..d9ba11c2c3a20 100644 --- a/x-pack/test/functional/apps/uptime/certificates.ts +++ b/x-pack/test/functional/apps/uptime/certificates.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { makeCheck } from '@kbn/test-suites-xpack-observability/api_integration/apis/uptime/rest/helper/make_checks'; -import { getSha256 } from '@kbn/test-suites-xpack-observability/api_integration/apis/uptime/rest/helper/make_tls'; +import { makeCheck } from '../../../common/utils/uptime/helper/make_checks'; +import { getSha256 } from '../../../common/utils/uptime/helper/make_tls'; import { FtrProviderContext } from '../../ftr_provider_context'; import { UPTIME_HEARTBEAT_DATA } from './overview'; diff --git a/x-pack/test/functional/apps/uptime/missing_mappings.ts b/x-pack/test/functional/apps/uptime/missing_mappings.ts index 483e4619937d7..e9ec7e01d7046 100644 --- a/x-pack/test/functional/apps/uptime/missing_mappings.ts +++ b/x-pack/test/functional/apps/uptime/missing_mappings.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { makeCheck } from '@kbn/test-suites-xpack-observability/api_integration/apis/uptime/rest/helper/make_checks'; +import { makeCheck } from '../../../common/utils/uptime/helper/make_checks'; import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { diff --git a/x-pack/test/functional/apps/uptime/settings.ts b/x-pack/test/functional/apps/uptime/settings.ts index baf27dbae550a..154b5eeeb1975 100644 --- a/x-pack/test/functional/apps/uptime/settings.ts +++ b/x-pack/test/functional/apps/uptime/settings.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { DynamicSettings } from '@kbn/uptime-plugin/common/runtime_types'; import { DYNAMIC_SETTINGS_DEFAULTS } from '@kbn/uptime-plugin/common/constants'; -import { makeChecks } from '@kbn/test-suites-xpack-observability/api_integration/apis/uptime/rest/helper/make_checks'; +import { makeChecks } from '../../../common/utils/uptime/helper/make_checks'; import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index a8c418c02ac36..53abbaffdb646 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -2,7 +2,10 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "target/types", - "types": ["node", "@kbn/ambient-ftr-types"], + "types": [ + "node", + "@kbn/ambient-ftr-types" + ], // there is still a decent amount of JS in this plugin and we are taking // advantage of the fact that TS doesn't know the types of that code and // gives us `any`. Once that code is converted to .ts we can remove this @@ -149,11 +152,10 @@ "@kbn/embeddable-alerts-table-plugin", "@kbn/lock-manager", "@kbn/alerts-ui-shared", - "@kbn/test-suites-xpack-observability", "@kbn/test-suites-xpack-platform", "@kbn/core-chrome-browser", "@kbn/event-log-plugin", "@kbn/management-settings-ids", "@kbn/intercepts-plugin", ] -} +} \ No newline at end of file From e77a980ea64ced2986efd497a3a6ebfc320e7b9d Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 2 Jul 2025 12:14:39 +0000 Subject: [PATCH 2/2] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- x-pack/test/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 53abbaffdb646..4095f9a7b5d9c 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -158,4 +158,4 @@ "@kbn/management-settings-ids", "@kbn/intercepts-plugin", ] -} \ No newline at end of file +}