From a3d71f2534a56dd070982d6d8c60e56aa43ae2fa Mon Sep 17 00:00:00 2001 From: Ash <1849116+ashokaditya@users.noreply.github.com> Date: Wed, 1 Nov 2023 21:33:36 +0100 Subject: [PATCH 1/5] [Security Solution][Endpoint] Unskip flaky tests (document signing & response console - isolate) (#169539) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Split test to avoid long running times. Fixes https://github.com/elastic/kibana/issues/168296 https://github.com/elastic/kibana/issues/168390 **Flaky test runner** - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3754 x 150 (3 failures for document signing: 7, 101, 141) - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3809 x 50 (all pass for document_signing.cy.ts) - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3835 x 50 (2 fails for document signing and 1 fail for response console release due to timeout on response delay) - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3842 x 25 (all pass for document_singing.cy.ts and response_console_actions.cy.ts) - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3843 x 25 (3 fails for document_signing.cy.ts related to timeout for action response) - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3844 x 100 (all pass for release, 3 failures for document signing due to time out waiting for action response) - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3848 x 50 ( all pass, 1 unrelated failure related to `endpoints_list_response_console.cy·ts`) - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3849 x 50 (all pass) ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../response_actions/document_signing.cy.ts | 84 ++++++++++++++++++ .../response_console/execute.cy.ts | 2 +- .../response_console/file_operations.cy.ts | 2 +- .../response_console/isolation.cy.ts | 21 +++-- .../response_console/process_operations.cy.ts | 2 +- .../response_console_actions.cy.ts | 87 ------------------- .../cypress/support/response_actions.ts | 3 +- .../management/cypress/tasks/isolate.ts | 23 +++++ 8 files changed, 123 insertions(+), 101 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts delete mode 100644 x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console_actions.cy.ts diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts new file mode 100644 index 0000000000000..b806323726018 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts @@ -0,0 +1,84 @@ +/* + * 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 { PolicyData } from '../../../../../common/endpoint/types'; +import type { CreateAndEnrollEndpointHostResponse } from '../../../../../scripts/endpoint/common/endpoint_host_services'; +import { + openResponseConsoleFromEndpointList, + performCommandInputChecks, + submitCommand, + waitForEndpointListPageToBeLoaded, +} from '../../tasks/response_console'; +import type { IndexedFleetEndpointPolicyResponse } from '../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; +import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../tasks/fleet'; +import { checkEndpointListForOnlyUnIsolatedHosts } from '../../tasks/isolate'; + +import { login } from '../../tasks/login'; +import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; +import { createEndpointHost } from '../../tasks/create_endpoint_host'; +import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; + +describe('Document signing:', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { + let indexedPolicy: IndexedFleetEndpointPolicyResponse; + let policy: PolicyData; + let createdHost: CreateAndEnrollEndpointHostResponse; + + before(() => { + getEndpointIntegrationVersion().then((version) => + createAgentPolicyTask(version).then((data) => { + indexedPolicy = data; + policy = indexedPolicy.integrationPolicies[0]; + + return enableAllPolicyProtections(policy.id).then(() => { + // Create and enroll a new Endpoint host + return createEndpointHost(policy.policy_id).then((host) => { + createdHost = host as CreateAndEnrollEndpointHostResponse; + }); + }); + }) + ); + }); + + after(() => { + if (createdHost) { + cy.task('destroyEndpointHost', createdHost); + } + + if (indexedPolicy) { + cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy); + } + + if (createdHost) { + deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] }); + } + }); + + beforeEach(() => { + login(); + }); + + it('should fail if data tampered', () => { + waitForEndpointListPageToBeLoaded(createdHost.hostname); + checkEndpointListForOnlyUnIsolatedHosts(); + openResponseConsoleFromEndpointList(); + performCommandInputChecks('isolate'); + + // stop host so that we ensure tamper happens before endpoint processes the action + cy.task('stopEndpointHost', createdHost.hostname); + // get action doc before we submit command, so we know when the new action doc is indexed + cy.task('getLatestActionDoc').then((previousActionDoc) => { + submitCommand(); + cy.task('tamperActionDoc', previousActionDoc); + }); + cy.task('startEndpointHost', createdHost.hostname); + + const actionValidationErrorMsg = + 'Fleet action response error: Failed to validate action signature; check Endpoint logs for details'; + // wait for 3 minutes for the response to be indexed + cy.contains(actionValidationErrorMsg, { timeout: 180000 }).should('exist'); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts index 9e0fab431fe3a..dad573bb09c2b 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts @@ -26,7 +26,7 @@ describe('Response console', { tags: ['@ess', '@serverless'] }, () => { login(); }); - describe('Execute operations: execute', () => { + describe('Execute operations:', () => { const homeFilePath = process.env.CI || true ? '/home/vagrant' : `/home/ubuntu`; let indexedPolicy: IndexedFleetEndpointPolicyResponse; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/file_operations.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/file_operations.cy.ts index a2355647bf238..ccea07c117820 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/file_operations.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/file_operations.cy.ts @@ -26,7 +26,7 @@ describe('Response console', { tags: ['@ess', '@serverless'] }, () => { login(); }); - describe('File operations: get-file and upload', () => { + describe('File operations:', () => { const homeFilePath = process.env.CI || true ? '/home/vagrant' : `/home/ubuntu`; const fileContent = 'This is a test file for the get-file command.'; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/isolation.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/isolation.cy.ts index e41232e8fcf65..b748dca85f517 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/isolation.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/isolation.cy.ts @@ -19,6 +19,7 @@ import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../../t import { checkEndpointListForOnlyIsolatedHosts, checkEndpointListForOnlyUnIsolatedHosts, + isolateHostFromEndpointList, } from '../../../tasks/isolate'; import { login } from '../../../tasks/login'; @@ -31,7 +32,7 @@ describe('Response console', { tags: ['@ess', '@serverless'] }, () => { login(); }); - describe('Host Isolation: isolate and release an endpoint', () => { + describe('Host Isolation:', () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; let createdHost: CreateAndEnrollEndpointHostResponse; @@ -66,28 +67,30 @@ describe('Response console', { tags: ['@ess', '@serverless'] }, () => { } }); - it('should isolate host from response console', () => { - const command = 'isolate'; + it('should release an isolated host from response console', () => { + const command = 'release'; waitForEndpointListPageToBeLoaded(createdHost.hostname); - checkEndpointListForOnlyUnIsolatedHosts(); + // isolate the host first + isolateHostFromEndpointList(); + checkEndpointListForOnlyIsolatedHosts(); openResponseConsoleFromEndpointList(); performCommandInputChecks(command); submitCommand(); waitForCommandToBeExecuted(command); waitForEndpointListPageToBeLoaded(createdHost.hostname); - checkEndpointListForOnlyIsolatedHosts(); + checkEndpointListForOnlyUnIsolatedHosts(); }); - it('should release host from response console', () => { - const command = 'release'; + it('should isolate a host from response console', () => { + const command = 'isolate'; waitForEndpointListPageToBeLoaded(createdHost.hostname); - checkEndpointListForOnlyIsolatedHosts(); + checkEndpointListForOnlyUnIsolatedHosts(); openResponseConsoleFromEndpointList(); performCommandInputChecks(command); submitCommand(); waitForCommandToBeExecuted(command); waitForEndpointListPageToBeLoaded(createdHost.hostname); - checkEndpointListForOnlyUnIsolatedHosts(); + checkEndpointListForOnlyIsolatedHosts(); }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts index 09a8ecc3363ef..3faf7373f5569 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts @@ -28,7 +28,7 @@ describe('Response console', { tags: ['@ess', '@serverless'] }, () => { login(); }); - describe('Processes operations: list, kill and suspend process', () => { + describe('Processes operations:', () => { let cronPID: string; let newCronPID: string; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console_actions.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console_actions.cy.ts deleted file mode 100644 index d78513f62eaf3..0000000000000 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console_actions.cy.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { PolicyData } from '../../../../../common/endpoint/types'; -import type { CreateAndEnrollEndpointHostResponse } from '../../../../../scripts/endpoint/common/endpoint_host_services'; -import { - openResponseConsoleFromEndpointList, - performCommandInputChecks, - submitCommand, - waitForEndpointListPageToBeLoaded, -} from '../../tasks/response_console'; -import type { IndexedFleetEndpointPolicyResponse } from '../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; -import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../tasks/fleet'; -import { checkEndpointListForOnlyUnIsolatedHosts } from '../../tasks/isolate'; - -import { login } from '../../tasks/login'; -import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; -import { createEndpointHost } from '../../tasks/create_endpoint_host'; -import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; - -describe('Response console', { tags: ['@ess', '@serverless'] }, () => { - beforeEach(() => { - login(); - }); - - // TODO: open PR https://github.com/elastic/kibana/pull/169539 - // FLAKY: https://github.com/elastic/kibana/issues/168296 - describe.skip('document signing', () => { - let indexedPolicy: IndexedFleetEndpointPolicyResponse; - let policy: PolicyData; - let createdHost: CreateAndEnrollEndpointHostResponse; - - before(() => { - getEndpointIntegrationVersion().then((version) => - createAgentPolicyTask(version).then((data) => { - indexedPolicy = data; - policy = indexedPolicy.integrationPolicies[0]; - - return enableAllPolicyProtections(policy.id).then(() => { - // Create and enroll a new Endpoint host - return createEndpointHost(policy.policy_id).then((host) => { - createdHost = host as CreateAndEnrollEndpointHostResponse; - }); - }); - }) - ); - }); - - after(() => { - if (createdHost) { - cy.task('destroyEndpointHost', createdHost); - } - - if (indexedPolicy) { - cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy); - } - - if (createdHost) { - deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] }); - } - }); - - it('should fail if data tampered', () => { - waitForEndpointListPageToBeLoaded(createdHost.hostname); - checkEndpointListForOnlyUnIsolatedHosts(); - openResponseConsoleFromEndpointList(); - performCommandInputChecks('isolate'); - - // stop host so that we ensure tamper happens before endpoint processes the action - cy.task('stopEndpointHost', createdHost.hostname); - // get action doc before we submit command so we know when the new action doc is indexed - cy.task('getLatestActionDoc').then((previousActionDoc) => { - submitCommand(); - cy.task('tamperActionDoc', previousActionDoc); - }); - cy.task('startEndpointHost', createdHost.hostname); - - const actionValidationErrorMsg = - 'Fleet action response error: Failed to validate action signature; check Endpoint logs for details'; - cy.contains(actionValidationErrorMsg, { timeout: 120000 }).should('exist'); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/management/cypress/support/response_actions.ts b/x-pack/plugins/security_solution/public/management/cypress/support/response_actions.ts index b22e50c660d83..baaf0e12c10e2 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/support/response_actions.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/support/response_actions.ts @@ -48,10 +48,9 @@ export const responseActionTasks = ( const signed = get(newActionDoc, '_source.signed'); const signedDataBuffer = Buffer.from(signed.data, 'base64'); const signedDataJson = JSON.parse(signedDataBuffer.toString()); - const tamperedAgentsList = [...signedDataJson.agents, 'anotheragent']; const tamperedData = { ...signedDataJson, - agents: tamperedAgentsList, + comment: 'tampered data', }; const tamperedDataString = Buffer.from(JSON.stringify(tamperedData), 'utf8').toString( 'base64' diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/isolate.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/isolate.ts index e13bb832adce5..10aec51af291d 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/isolate.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/isolate.ts @@ -41,6 +41,29 @@ export const isolateHostWithComment = (comment: string, hostname: string): void cy.getByTestSubj('host_isolation_comment').type(comment); }; +export const isolateHostFromEndpointList = (index: number = 0): void => { + // open the action menu and click isolate action + cy.getByTestSubj('endpointTableRowActions').eq(index).click(); + cy.getByTestSubj('isolateLink').click(); + // isolation form, click confirm button + cy.getByTestSubj('hostIsolateConfirmButton').click(); + // return to endpoint details + cy.getByTestSubj('hostIsolateSuccessCompleteButton').click(); + // close details flyout + cy.getByTestSubj('euiFlyoutCloseButton').click(); + + // ensure the host is isolated, wait for 3 minutes for the host to be isolated + cy.wait(18000); + + cy.getByTestSubj('endpointListTable').within(() => { + cy.get('tbody tr') + .eq(index) + .within(() => { + cy.get('td').eq(1).should('contain.text', 'Isolated'); + }); + }); +}; + export const releaseHostWithComment = (comment: string, hostname: string): void => { cy.contains(`${hostname} is currently isolated.`); cy.getByTestSubj('endpointHostIsolationForm'); From aab346e4d972a456b74308f93d99456f78d0d2b8 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Wed, 1 Nov 2023 17:28:01 -0400 Subject: [PATCH 2/5] fix(slo): remove react query cache for slo list page (#170318) --- .../__storybook_mocks__/use_fetch_slo_list.ts | 1 - .../public/hooks/slo/use_fetch_slo_list.ts | 105 ++++++++---------- 2 files changed, 46 insertions(+), 60 deletions(-) diff --git a/x-pack/plugins/observability/public/hooks/slo/__storybook_mocks__/use_fetch_slo_list.ts b/x-pack/plugins/observability/public/hooks/slo/__storybook_mocks__/use_fetch_slo_list.ts index 4e7d1889e5bb0..78d0c0b8c2488 100644 --- a/x-pack/plugins/observability/public/hooks/slo/__storybook_mocks__/use_fetch_slo_list.ts +++ b/x-pack/plugins/observability/public/hooks/slo/__storybook_mocks__/use_fetch_slo_list.ts @@ -16,6 +16,5 @@ export const useFetchSloList = (): UseFetchSloListResponse => { isError: false, isSuccess: true, data: sloList, - refetch: function () {} as UseFetchSloListResponse['refetch'], }; }; diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts index f97c2398b8efc..8f7a9e21b20cc 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts @@ -5,16 +5,10 @@ * 2.0. */ -import { useState } from 'react'; -import { - QueryObserverResult, - RefetchOptions, - RefetchQueryFilters, - useQuery, - useQueryClient, -} from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; import { FindSLOResponse } from '@kbn/slo-schema'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useState } from 'react'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; @@ -34,9 +28,6 @@ export interface UseFetchSloListResponse { isSuccess: boolean; isError: boolean; data: FindSLOResponse | undefined; - refetch: ( - options?: (RefetchOptions & RefetchQueryFilters) | undefined - ) => Promise>; } const SHORT_REFETCH_INTERVAL = 1000 * 5; // 5 seconds @@ -56,56 +47,53 @@ export function useFetchSloList({ const queryClient = useQueryClient(); const [stateRefetchInterval, setStateRefetchInterval] = useState(SHORT_REFETCH_INTERVAL); - const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data, refetch } = useQuery( - { - queryKey: sloKeys.list({ kqlQuery, page, sortBy, sortDirection }), - queryFn: async ({ signal }) => { - const response = await http.get(`/api/observability/slos`, { - query: { - ...(kqlQuery && { kqlQuery }), - ...(sortBy && { sortBy }), - ...(sortDirection && { sortDirection }), - ...(page && { page }), - }, - signal, - }); + const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ + queryKey: sloKeys.list({ kqlQuery, page, sortBy, sortDirection }), + queryFn: async ({ signal }) => { + const response = await http.get(`/api/observability/slos`, { + query: { + ...(kqlQuery && { kqlQuery }), + ...(sortBy && { sortBy }), + ...(sortDirection && { sortDirection }), + ...(page && { page }), + }, + signal, + }); - return response; - }, - keepPreviousData: true, - refetchOnWindowFocus: false, - refetchInterval: shouldRefetch ? stateRefetchInterval : undefined, - staleTime: 1000, - retry: (failureCount, error) => { - if (String(error) === 'Error: Forbidden') { - return false; - } - return failureCount < 4; - }, - onSuccess: ({ results }: FindSLOResponse) => { - queryClient.invalidateQueries({ queryKey: sloKeys.historicalSummaries(), exact: false }); - queryClient.invalidateQueries({ queryKey: sloKeys.activeAlerts(), exact: false }); - queryClient.invalidateQueries({ queryKey: sloKeys.rules(), exact: false }); + return response; + }, + cacheTime: 0, + refetchOnWindowFocus: false, + refetchInterval: shouldRefetch ? stateRefetchInterval : undefined, + retry: (failureCount, error) => { + if (String(error) === 'Error: Forbidden') { + return false; + } + return failureCount < 4; + }, + onSuccess: ({ results }: FindSLOResponse) => { + queryClient.invalidateQueries({ queryKey: sloKeys.historicalSummaries(), exact: false }); + queryClient.invalidateQueries({ queryKey: sloKeys.activeAlerts(), exact: false }); + queryClient.invalidateQueries({ queryKey: sloKeys.rules(), exact: false }); - if (!shouldRefetch) { - return; - } + if (!shouldRefetch) { + return; + } - if (results.find((slo) => slo.summary.status === 'NO_DATA' || !slo.summary)) { - setStateRefetchInterval(SHORT_REFETCH_INTERVAL); - } else { - setStateRefetchInterval(LONG_REFETCH_INTERVAL); - } - }, - onError: (error: Error) => { - toasts.addError(error, { - title: i18n.translate('xpack.observability.slo.list.errorNotification', { - defaultMessage: 'Something went wrong while fetching SLOs', - }), - }); - }, - } - ); + if (results.find((slo) => slo.summary.status === 'NO_DATA' || !slo.summary)) { + setStateRefetchInterval(SHORT_REFETCH_INTERVAL); + } else { + setStateRefetchInterval(LONG_REFETCH_INTERVAL); + } + }, + onError: (error: Error) => { + toasts.addError(error, { + title: i18n.translate('xpack.observability.slo.list.errorNotification', { + defaultMessage: 'Something went wrong while fetching SLOs', + }), + }); + }, + }); return { data, @@ -114,6 +102,5 @@ export function useFetchSloList({ isRefetching, isSuccess, isError, - refetch, }; } From c84a62d3428f584aea8abbd012a76194e71503c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Wed, 1 Nov 2023 23:05:15 +0100 Subject: [PATCH 3/5] Use cleanup rule and alert state everywhere (#170235) Followup from https://github.com/elastic/kibana/pull/170111 --- .../alerts/helpers/alerting_api_helper.ts | 25 ++++++++++++++----- .../helpers/cleanup_rule_and_alert_state.ts | 10 +++++--- .../service_group_count.spec.ts | 10 +++----- .../tests/services/service_alerts.spec.ts | 18 ++++--------- .../transactions_groups_alerts.spec.ts | 19 +++++--------- 5 files changed, 39 insertions(+), 43 deletions(-) diff --git a/x-pack/test/apm_api_integration/tests/alerts/helpers/alerting_api_helper.ts b/x-pack/test/apm_api_integration/tests/alerts/helpers/alerting_api_helper.ts index f7eb20824b24c..42fca92b47540 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/helpers/alerting_api_helper.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/helpers/alerting_api_helper.ts @@ -199,6 +199,7 @@ export async function createIndexConnector({ }, connector_type_id: '.index', }); + return body.id as string; } @@ -228,19 +229,31 @@ export function getIndexAction({ }; } -export async function deleteActionConnector({ +export async function deleteAllActionConnectors({ supertest, es, - actionId, }: { supertest: SuperTest; es: Client; +}): Promise { + const res = await supertest.get(`/api/actions/connectors`); + + const body = res.body as Array<{ id: string; connector_type_id: string; name: string }>; + return Promise.all( + body.map(({ id }) => { + return deleteActionConnector({ supertest, actionId: id }); + }) + ); +} + +async function deleteActionConnector({ + supertest, + actionId, +}: { + supertest: SuperTest; actionId: string; }) { - return Promise.all([ - await supertest.delete(`/api/actions/connector/${actionId}`).set('kbn-xsrf', 'foo'), - await deleteActionConnectorIndex(es), - ]); + return supertest.delete(`/api/actions/connector/${actionId}`).set('kbn-xsrf', 'foo'); } export async function deleteActionConnectorIndex(es: Client) { diff --git a/x-pack/test/apm_api_integration/tests/alerts/helpers/cleanup_rule_and_alert_state.ts b/x-pack/test/apm_api_integration/tests/alerts/helpers/cleanup_rule_and_alert_state.ts index 144446a28b3d7..ae97266ee084c 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/helpers/cleanup_rule_and_alert_state.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/helpers/cleanup_rule_and_alert_state.ts @@ -13,6 +13,7 @@ import { deleteApmRules, deleteApmAlerts, deleteActionConnectorIndex, + deleteAllActionConnectors, } from './alerting_api_helper'; export async function cleanupRuleAndAlertState({ @@ -26,10 +27,11 @@ export async function cleanupRuleAndAlertState({ }) { try { await Promise.all([ - await deleteActionConnectorIndex(es), - await deleteApmRules(supertest), - await deleteApmAlerts(es), - await clearKibanaApmEventLog(es), + deleteApmRules(supertest), + deleteApmAlerts(es), + clearKibanaApmEventLog(es), + deleteActionConnectorIndex(es), + deleteAllActionConnectors({ supertest, es }), ]); } catch (e) { logger.error(`An error occured while cleaning up the state: ${e}`); diff --git a/x-pack/test/apm_api_integration/tests/service_groups/service_group_count/service_group_count.spec.ts b/x-pack/test/apm_api_integration/tests/service_groups/service_group_count/service_group_count.spec.ts index dc909ffebd024..cf46d4771d6cb 100644 --- a/x-pack/test/apm_api_integration/tests/service_groups/service_group_count/service_group_count.spec.ts +++ b/x-pack/test/apm_api_integration/tests/service_groups/service_group_count/service_group_count.spec.ts @@ -8,11 +8,8 @@ import { AggregationType } from '@kbn/apm-plugin/common/rules/apm_rule_types'; import { ApmRuleType } from '@kbn/rule-data-utils'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; -import { - createApmRule, - deleteRuleById, - deleteApmAlerts, -} from '../../alerts/helpers/alerting_api_helper'; +import { createApmRule } from '../../alerts/helpers/alerting_api_helper'; +import { cleanupRuleAndAlertState } from '../../alerts/helpers/cleanup_rule_and_alert_state'; import { waitForActiveApmAlert } from '../../alerts/helpers/wait_for_active_apm_alerts'; import { createServiceGroupApi, @@ -93,8 +90,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - await deleteRuleById({ supertest, ruleId }); - await deleteApmAlerts(es); + await cleanupRuleAndAlertState({ es, supertest, logger: log }); }); it('returns the correct number of alerts', async () => { diff --git a/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts b/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts index 4ba8ae48bd00d..acef21aab3317 100644 --- a/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts @@ -9,15 +9,10 @@ import { AggregationType } from '@kbn/apm-plugin/common/rules/apm_rule_types'; import { ApmRuleType } from '@kbn/rule-data-utils'; import { apm, timerange } from '@kbn/apm-synthtrace-client'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - createApmRule, - deleteApmAlerts, - runRuleSoon, - deleteRuleById, - ApmAlertFields, -} from '../alerts/helpers/alerting_api_helper'; +import { createApmRule, runRuleSoon, ApmAlertFields } from '../alerts/helpers/alerting_api_helper'; import { waitForActiveRule } from '../alerts/helpers/wait_for_active_rule'; import { waitForAlertsForRule } from '../alerts/helpers/wait_for_alerts_for_rule'; +import { cleanupRuleAndAlertState } from '../alerts/helpers/cleanup_rule_and_alert_state'; export default function ServiceAlerts({ getService }: FtrProviderContext) { const registry = getService('registry'); @@ -29,6 +24,7 @@ export default function ServiceAlerts({ getService }: FtrProviderContext) { const start = Date.now() - dayInMs; const end = Date.now() + dayInMs; const goService = 'synth-go'; + const logger = getService('log'); async function getServiceAlerts({ serviceName, @@ -131,8 +127,7 @@ export default function ServiceAlerts({ getService }: FtrProviderContext) { }); after(async () => { - await deleteRuleById({ supertest, ruleId }); - await deleteApmAlerts(es); + await cleanupRuleAndAlertState({ es, supertest, logger }); }); it('checks if rule is active', async () => { @@ -141,10 +136,7 @@ export default function ServiceAlerts({ getService }: FtrProviderContext) { }); it('should successfully run the rule', async () => { - const response = await runRuleSoon({ - ruleId, - supertest, - }); + const response = await runRuleSoon({ ruleId, supertest }); expect(response.status).to.be(204); }); diff --git a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_alerts.spec.ts b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_alerts.spec.ts index 752ed822a8c99..0cb9f194dfa51 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_alerts.spec.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_alerts.spec.ts @@ -14,15 +14,10 @@ import { apm, timerange } from '@kbn/apm-synthtrace-client'; import { AggregationType } from '@kbn/apm-plugin/common/rules/apm_rule_types'; import { ApmRuleType } from '@kbn/rule-data-utils'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - createApmRule, - runRuleSoon, - deleteApmAlerts, - deleteRuleById, - ApmAlertFields, -} from '../alerts/helpers/alerting_api_helper'; +import { createApmRule, runRuleSoon, ApmAlertFields } from '../alerts/helpers/alerting_api_helper'; import { waitForActiveRule } from '../alerts/helpers/wait_for_active_rule'; import { waitForAlertsForRule } from '../alerts/helpers/wait_for_alerts_for_rule'; +import { cleanupRuleAndAlertState } from '../alerts/helpers/cleanup_rule_and_alert_state'; type TransactionsGroupsMainStatistics = APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics'>; @@ -37,6 +32,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const dayInMs = 24 * 60 * 60 * 1000; const start = Date.now() - dayInMs; const end = Date.now() + dayInMs; + const logger = getService('log'); async function getTransactionGroups(overrides?: { path?: { @@ -171,8 +167,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - await deleteRuleById({ supertest, ruleId }); - await deleteApmAlerts(es); + await cleanupRuleAndAlertState({ es, supertest, logger }); }); it('checks if rule is active', async () => { @@ -245,8 +240,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - await deleteRuleById({ supertest, ruleId }); - await deleteApmAlerts(es); + await cleanupRuleAndAlertState({ es, supertest, logger }); }); it('checks if rule is active', async () => { @@ -320,8 +314,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - await deleteRuleById({ supertest, ruleId }); - await deleteApmAlerts(es); + await cleanupRuleAndAlertState({ es, supertest, logger }); }); it('checks if rule is active', async () => { From 18dc8feb5b32ebdbcff2599b400f27b0ced7ab8c Mon Sep 17 00:00:00 2001 From: Panagiota Mitsopoulou Date: Wed, 1 Nov 2023 23:17:09 +0100 Subject: [PATCH 4/5] [SLO][Embeddable] Fix Kibana reporting screenshot issue (#169929) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves https://github.com/elastic/kibana/issues/169716 ## 🍒 Summary The reporting plugin waits for a renderComplete signal when the embeddable has finished loading any data and is correctly rendered so the headless Chromium can take a screenshot. This PR calls the RenderCompleteDispatcher on the SLO Overview embeddable when all the child components have finished loading. https://elastic.slack.com/archives/CFFQ7RP9B/p1614267987040400 ## How to test - Add an SLO panel to the dashboard - click on share -> PDF reports > Generate PDF on the top right navigation bar - No Timeout error should appear on the generated PDF Screenshot 2023-10-26 at 15 05 05 --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../slo/overview/handle_explicit_input.tsx | 2 +- .../embeddable/slo/overview/slo_configuration.tsx | 1 - .../embeddable/slo/overview/slo_embeddable.tsx | 12 ++++++++++++ .../embeddable/slo/overview/slo_overview.tsx | 15 ++++++++++++++- .../public/embeddable/slo/overview/types.ts | 1 + 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/handle_explicit_input.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/handle_explicit_input.tsx index 0c36b4e915c6c..72e460e6f1890 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/handle_explicit_input.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/handle_explicit_input.tsx @@ -11,7 +11,7 @@ import { toMountPoint } from '@kbn/react-kibana-mount'; import type { CoreStart } from '@kbn/core/public'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import type { EmbeddableSloProps, SloEmbeddableInput } from './types'; +import type { SloEmbeddableInput, EmbeddableSloProps } from './types'; import { ObservabilityPublicPluginsStart } from '../../..'; import { SloConfiguration } from './slo_configuration'; diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx index cf83690800318..c7fcb63be7a3a 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx @@ -20,7 +20,6 @@ import { import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { SloSelector } from './slo_selector'; - import type { EmbeddableSloProps } from './types'; interface SloConfigurationProps { diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx index faadbcb637646..ec5709ce45f98 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx @@ -50,8 +50,19 @@ export class SLOEmbeddable extends AbstractEmbeddable this.onRenderComplete()} sloId={sloId} sloInstanceId={sloInstanceId} lastReloadRequestTime={this.input.lastReloadRequestTime} diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx index 9ee756c0235b8..873c37f89eca2 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx @@ -20,7 +20,12 @@ import { paths } from '../../../../common/locators/paths'; import { EmbeddableSloProps } from './types'; -export function SloOverview({ sloId, sloInstanceId, lastReloadRequestTime }: EmbeddableSloProps) { +export function SloOverview({ + sloId, + sloInstanceId, + lastReloadRequestTime, + onRenderComplete, +}: EmbeddableSloProps) { const { uiSettings, application: { navigateToUrl }, @@ -39,6 +44,13 @@ export function SloOverview({ sloId, sloInstanceId, lastReloadRequestTime }: Emb useEffect(() => { refetch(); }, [lastReloadRequestTime, refetch]); + useEffect(() => { + if (!onRenderComplete) return; + + if (!isLoading) { + onRenderComplete(); + } + }, [isLoading, onRenderComplete]); const percentFormat = uiSettings.get('format:percent:defaultPattern'); const isSloNotFound = !isLoading && slo === undefined; @@ -97,6 +109,7 @@ export function SloOverview({ sloId, sloInstanceId, lastReloadRequestTime }: Emb ); } + const TargetCopy = i18n.translate('xpack.observability.sloEmbeddable.overview.sloTargetLabel', { defaultMessage: 'Target', }); diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts b/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts index ea125ffa8a9d5..a6f55069dc47e 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts @@ -10,6 +10,7 @@ export interface EmbeddableSloProps { sloId: string | undefined; sloInstanceId: string | undefined; lastReloadRequestTime?: number | undefined; + onRenderComplete?: () => void; } export type SloEmbeddableInput = EmbeddableInput & EmbeddableSloProps; From 0879f2ef2bb07fe6c1aa8a58b31bcdc555f1a192 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 1 Nov 2023 19:28:10 -0400 Subject: [PATCH 5/5] skip failing test suite (#151854) --- .../test/security_solution_endpoint_api_int/apis/metadata.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts index 48109e13257ca..17cc5906d7ba8 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts @@ -46,7 +46,8 @@ export default function ({ getService }: FtrProviderContext) { const endpointTestResources = getService('endpointTestResources'); const log = getService('log'); - describe('test metadata apis', () => { + // Failing: See https://github.com/elastic/kibana/issues/151854 + describe.skip('test metadata apis', () => { describe('list endpoints GET route', () => { const numberOfHostsInFixture = 2; let agent1Timestamp: number;