From dc29fb7cb508a98aaa6606da718a8c57cdee74e2 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Wed, 22 Nov 2023 10:14:11 +0100 Subject: [PATCH 1/8] [Log Explorer] Update minimum height for JSON doc view (#171553) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📓 Summary Closes #171485 This fix guarantees the JSON doc view will always get a minimum space independently of the available space, to avoid the current scenario where a scrollable flyout does not reserve enough space for the JSON tab content tobe displayed (see recording in the related issue). https://github.com/elastic/kibana/assets/34506779/2c539047-32cd-4213-bc6f-3062de151426 --------- Co-authored-by: Marco Antonio Ghiani --- .../doc_viewer_source/get_height.test.tsx | 13 ++++++++++--- .../components/doc_viewer_source/get_height.tsx | 4 ++-- .../public/components/doc_viewer_source/source.tsx | 2 ++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx index fc8f7498f6efce..6c6ae2852e053f 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx @@ -12,13 +12,13 @@ import { getHeight } from './get_height'; describe('getHeight', () => { Object.defineProperty(window, 'innerHeight', { writable: true, configurable: true, value: 500 }); - const getMonacoMock = (lineCount: number) => { + const getMonacoMock = (lineCount: number, top: number = 200) => { return { getDomNode: jest.fn(() => { return { getBoundingClientRect: jest.fn(() => { return { - top: 200, + top, }; }), }; @@ -29,10 +29,17 @@ describe('getHeight', () => { } as unknown as monaco.editor.IStandaloneCodeEditor; }; test('when using document explorer, returning the available height in the flyout', () => { + const monacoMock = getMonacoMock(500, 0); + + const height = getHeight(monacoMock, true); + expect(height).toBe(475); + }); + + test('when using document explorer, returning the available height in the flyout has a minimun guarenteed height', () => { const monacoMock = getMonacoMock(500); const height = getHeight(monacoMock, true); - expect(height).toBe(275); + expect(height).toBe(400); }); test('when using classic table, its displayed inline without scrolling', () => { diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx index 0dcabc8ae951d8..dbab289018a637 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ import { monaco } from '@kbn/monaco'; -import { MARGIN_BOTTOM, MAX_LINES_CLASSIC_TABLE } from './source'; +import { MARGIN_BOTTOM, MAX_LINES_CLASSIC_TABLE, MIN_HEIGHT } from './source'; export function getHeight(editor: monaco.editor.IStandaloneCodeEditor, useDocExplorer: boolean) { const editorElement = editor?.getDomNode(); @@ -28,5 +28,5 @@ export function getHeight(editor: monaco.editor.IStandaloneCodeEditor, useDocExp lineCount > MAX_LINES_CLASSIC_TABLE ? MAX_LINES_CLASSIC_TABLE : lineCount; result = editor.getTopForLineNumber(displayedLineCount + 1) + lineHeight; } - return result > 0 ? result : 0; + return Math.max(result, MIN_HEIGHT); } diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx index 26c771e405be83..140fbd6e08cb0d 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx @@ -36,6 +36,8 @@ interface SourceViewerProps { export const MAX_LINES_CLASSIC_TABLE = 500; // Displayed margin of the code editor to the window bottom when rendered in the document explorer flyout export const MARGIN_BOTTOM = 25; +// Minimum height for the source content to guarantee minimum space when the flyout is scrollable. +export const MIN_HEIGHT = 400; export const DocViewerSource = ({ id, From 423e09465940312367d71b3be7a16f4c3dcad8c5 Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Wed, 22 Nov 2023 10:46:55 +0100 Subject: [PATCH 2/8] Disable rison parsing error logs in production (#171660) ## Summary Similar to https://github.com/elastic/kibana/pull/170827 Disable noisy 3rd party lib warning in production mode. --- src/setup_node_env/mute_libraries.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/setup_node_env/mute_libraries.js b/src/setup_node_env/mute_libraries.js index defb6347d80f72..e40ecfe84fa314 100644 --- a/src/setup_node_env/mute_libraries.js +++ b/src/setup_node_env/mute_libraries.js @@ -9,3 +9,11 @@ // disable moment deprecation warnings var moment = require('moment'); moment.suppressDeprecationWarnings = true; + +// disable rison-node parsing errors +// eslint-disable-next-line @kbn/eslint/module_migration +var rison = require('rison-node'); +rison.parser.prototype.error = function (message) { + this.message = message; + return undefined; +}; From f3851c5934400eb1218714a84a679beba01ed806 Mon Sep 17 00:00:00 2001 From: Wafaa Nasr Date: Wed, 22 Nov 2023 11:05:55 +0100 Subject: [PATCH 3/8] [Security Solution][API testing] Rename the commands to be consistent with the query and add the new ones (#171532) ## Summary Rename the commands to be consistent with the query and add the new ones --- .../security_solution/api_integration.yml | 137 ++++++++++++++++-- 1 file changed, 124 insertions(+), 13 deletions(-) diff --git a/.buildkite/pipelines/security_solution/api_integration.yml b/.buildkite/pipelines/security_solution/api_integration.yml index b4c6cece31c4b1..0fbc23bcab68a4 100644 --- a/.buildkite/pipelines/security_solution/api_integration.yml +++ b/.buildkite/pipelines/security_solution/api_integration.yml @@ -1,7 +1,7 @@ steps: - - label: Running exception_workflows:runner:serverless + - label: Running exception_workflows:qa:serverless command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_workflows:qa:serverless - key: exception_workflows:runner:serverless + key: exception_workflows:qa:serverless agents: queue: n2-4-spot timeout_in_minutes: 120 @@ -10,9 +10,9 @@ steps: - exit_status: '*' limit: 2 - - label: Running exception_operators_date_numeric_types:runner:serverless + - label: Running exception_operators_date_numeric_types:qa:serverless command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_date_numeric_types:qa:serverless - key: exception_operators_date_numeric_types:runner:serverless + key: exception_operators_date_numeric_types:qa:serverless agents: queue: n2-4-spot timeout_in_minutes: 120 @@ -21,9 +21,20 @@ steps: - exit_status: '*' limit: 2 - - label: Running exception_operators_keyword_text_long:runner:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_keyword_text_long:qa:serverless - key: exception_operators_keyword_text_long:runner:serverless + - label: Running exception_operators_keyword:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_keyword:qa:serverless + key: exception_operators_keyword:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '*' + limit: 2 + + - label: Running exception_operators_ips:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_ips:qa:serverless + key: exception_operators_ips:qa:serverless agents: queue: n2-4-spot timeout_in_minutes: 120 @@ -32,9 +43,9 @@ steps: - exit_status: '*' limit: 2 - - label: Running exception_operators_ips_text_array:runner:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_ips_text_array:qa:serverless - key: exception_operators_ips_text_array:runner:serverless + - label: Running exception_operators_long:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_long:qa:serverless + key: exception_operators_long:qa:serverless agents: queue: n2-4-spot timeout_in_minutes: 120 @@ -42,10 +53,22 @@ steps: automatic: - exit_status: '1' limit: 2 + - - label: Running rule_creation:runner:serverless + - label: Running exception_operators_text:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_text:qa:serverless + key: exception_operators_text:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running rule_creation:qa:serverless command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh rule_creation:qa:serverless - key: rule_creation:runner:serverless + key: rule_creation:qa:serverless agents: queue: n2-4-spot timeout_in_minutes: 120 @@ -64,4 +87,92 @@ steps: automatic: - exit_status: '1' limit: 2 - + + - label: Running entity_analytics:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh entity_analytics:qa:serverless + key: entity_analytics:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running prebuilt_rules_management:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh prebuilt_rules_management:qa:serverless + key: prebuilt_rules_management:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless + key: prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running prebuilt_rules_large_prebuilt_rules_package:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh prebuilt_rules_large_prebuilt_rules_package:qa:serverless + key: prebuilt_rules_large_prebuilt_rules_package:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running prebuilt_rules_update_prebuilt_rules_package:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh prebuilt_rules_update_prebuilt_rules_package:qa:serverless + key: prebuilt_rules_update_prebuilt_rules_package:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running rule_execution_logic:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh rule_execution_logic:qa:serverless + key: rule_execution_logic:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running user_roles:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh user_roles:qa:serverless + key: user_roles:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running telemetry:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh telemetry:qa:serverless + key: telemetry:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + \ No newline at end of file From edc1b47bbda889dbbebc612f89e90e3505d171ad Mon Sep 17 00:00:00 2001 From: Pete Hampton Date: Wed, 22 Nov 2023 10:41:14 +0000 Subject: [PATCH 4/8] Update codeowners for secsol FTR tests. (#171620) ## Summary Security Data Analytics would like to know when these files are updated. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 70affc4d4b4005..6a74ffd3281967 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1441,6 +1441,7 @@ x-pack/test/security_solution_api_integration/test_suites/detections_response/de ## Security Solution sub teams - security-telemetry (Data Engineering) x-pack/plugins/security_solution/server/usage/ @elastic/security-data-analytics x-pack/plugins/security_solution/server/lib/telemetry/ @elastic/security-data-analytics +x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry @elastic/security-data-analytics ## Security Solution sub teams - security-engineering-productivity /x-pack/test/security_solution_cypress/* @elastic/security-engineering-productivity From 668f8565cfb6f0f7caf113f036e1e132f83b9fb3 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Wed, 22 Nov 2023 14:16:24 +0100 Subject: [PATCH 5/8] [Cloud Security] skip Old Data FTR test suit until the fix is implemented (#171721) ## Summary The test suit seems to cause failures https://buildkite.com/elastic/kibana-pull-request/builds/177222#018bf17a-bded-4681-a408-7c2e19c137b7 https://buildkite.com/elastic/kibana-pull-request/builds/177814#018bf5a4-8b63-4110-8acf-c1d4891867db https://buildkite.com/elastic/kibana-pull-request/builds/177817#018bf5b3-6129-4ac0-a032-df5ca1ba3b72 Skipping until the fix in https://github.com/elastic/kibana/pull/171717/files is confirmed on the flaky test runner --- .../pages/findings_old_data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings_old_data.ts b/x-pack/test/cloud_security_posture_functional/pages/findings_old_data.ts index fc12d593333b26..a8cda10482e2ea 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/findings_old_data.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/findings_old_data.ts @@ -55,7 +55,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }, ]; - describe('Old Data', function () { + describe.skip('Old Data', function () { this.tags(['cloud_security_posture_findings']); let findings: typeof pageObjects.findings; From 0e2ef90df77e7cddfeb72b09f0817cf1a53875a3 Mon Sep 17 00:00:00 2001 From: Pete Hampton Date: Wed, 22 Nov 2023 14:59:15 +0000 Subject: [PATCH 6/8] Update diagnostic sending logic so it doesn't use EP alerts queue. (#171381) ## Summary Currently, the diagnostic task is enqueueing alerts onto the production queue. This is problematic and likely causes a lot of EP alert telemetry loss in busy clusters. There is also a 100/1m cap on the queue which is also a bottleneck for the diagnostic feed. I'm following up with a bigger PR to move this query to a [PIT](https://www.elastic.co/guide/en/elasticsearch/reference/current/point-in-time-api.html) query. ### Checklist Delete any items that are not applicable to this PR. - [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 --- .../security_solution/server/lib/telemetry/constants.ts | 2 ++ .../server/lib/telemetry/tasks/diagnostic.test.ts | 7 +------ .../server/lib/telemetry/tasks/diagnostic.ts | 9 +++++---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts index 1404f8dba94e95..50e0e0be47cdd5 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts @@ -9,6 +9,8 @@ export const TELEMETRY_CHANNEL_LISTS = 'security-lists-v2'; export const TELEMETRY_CHANNEL_ENDPOINT_META = 'endpoint-metadata'; +export const TELEMETRY_CHANNEL_ENDPOINT_ALERTS = 'alerts-endpoint'; + export const TELEMETRY_CHANNEL_DETECTION_ALERTS = 'alerts-detections'; export const TELEMETRY_CHANNEL_TIMELINE = 'alerts-timeline'; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.test.ts index a83326334c9d77..223e732f946e96 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.test.ts @@ -37,15 +37,10 @@ describe('diagnostics telemetry task test', () => { mockTelemetryEventsSender, testTaskExecutionPeriod ); - expect(mockTelemetryReceiver.fetchDiagnosticAlerts).toHaveBeenCalledWith( testTaskExecutionPeriod.last, testTaskExecutionPeriod.current ); - - expect(mockTelemetryEventsSender.queueTelemetryEvents).toHaveBeenCalledWith( - testDiagnosticsAlerts.hits.hits.flatMap((doc) => [doc._source]) - ); - expect(mockTelemetryEventsSender.sendOnDemand).toBeCalledTimes(1); + expect(mockTelemetryEventsSender.sendOnDemand).toBeCalledTimes(2); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.ts index 5c4604289eb514..290c5cfc44a6ef 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.ts @@ -11,7 +11,7 @@ import type { ITelemetryEventsSender } from '../sender'; import type { TelemetryEvent } from '../types'; import type { ITelemetryReceiver } from '../receiver'; import type { TaskExecutionPeriod } from '../task'; -import { TASK_METRICS_CHANNEL } from '../constants'; +import { TELEMETRY_CHANNEL_ENDPOINT_ALERTS, TASK_METRICS_CHANNEL } from '../constants'; export function createTelemetryDiagnosticsTaskConfig() { return { @@ -49,14 +49,15 @@ export function createTelemetryDiagnosticsTaskConfig() { return 0; } tlog(logger, `Received ${hits.length} diagnostic alerts`); - const diagAlerts: TelemetryEvent[] = hits.flatMap((h) => + const alerts: TelemetryEvent[] = hits.flatMap((h) => h._source != null ? [h._source] : [] ); - sender.queueTelemetryEvents(diagAlerts); + + await sender.sendOnDemand(TELEMETRY_CHANNEL_ENDPOINT_ALERTS, alerts); await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ createTaskMetric(taskName, true, startTime), ]); - return diagAlerts.length; + return alerts.length; } catch (err) { await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ createTaskMetric(taskName, false, startTime, err.message), From 66019dfe057734f4f45035e7df101822e1bcdcc5 Mon Sep 17 00:00:00 2001 From: Kurt Date: Wed, 22 Nov 2023 10:43:03 -0500 Subject: [PATCH 7/8] Adding user profiles tests for regular and serverless (#171554) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Adding functional tests for User Profiles and Dark Mode ## Flaky Test Runner for new tests https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4034 🟢 --- .buildkite/ftr_configs.yml | 1 + .../user_profile/user_profile.tsx | 12 +- .../functional/apps/user_profiles/config.ts | 17 ++ .../functional/apps/user_profiles/index.ts | 14 ++ .../apps/user_profiles/user_profiles.ts | 160 ++++++++++++++++++ x-pack/test/functional/page_objects/index.ts | 2 + .../page_objects/user_profile_page.ts | 99 +++++++++++ .../common/platform_security/index.ts | 1 + .../user_profiles/user_profiles.ts | 40 +++++ 9 files changed, 343 insertions(+), 3 deletions(-) create mode 100644 x-pack/test/functional/apps/user_profiles/config.ts create mode 100644 x-pack/test/functional/apps/user_profiles/index.ts create mode 100644 x-pack/test/functional/apps/user_profiles/user_profiles.ts create mode 100644 x-pack/test/functional/page_objects/user_profile_page.ts create mode 100644 x-pack/test_serverless/functional/test_suites/common/platform_security/user_profiles/user_profiles.ts diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index dc0eb465b77ddd..eab35b9896fbbe 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -318,6 +318,7 @@ enabled: - x-pack/test/functional/apps/transform/feature_controls/config.ts - x-pack/test/functional/apps/upgrade_assistant/config.ts - x-pack/test/functional/apps/uptime/config.ts + - x-pack/test/functional/apps/user_profiles/config.ts - x-pack/test/functional/apps/visualize/config.ts - x-pack/test/functional/apps/watcher/config.ts - x-pack/test/functional/config_security_basic.ts diff --git a/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx b/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx index 782a14700ad594..04ac8cc4fcfe9a 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx +++ b/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx @@ -138,7 +138,7 @@ const UserDetailsEditor: FunctionComponent = ({ user }) labelAppend={} fullWidth > - + = ({ user }) labelAppend={} fullWidth > - + ); @@ -189,6 +189,7 @@ const UserSettingsEditor: FunctionComponent = ({ = ({ user, data }) {formChanges.count > 0 ? ( - + ) : null} @@ -974,6 +979,7 @@ export const SaveChangesBottomBar: FunctionComponent = () => { 0 && !formik.isValid} color="success" diff --git a/x-pack/test/functional/apps/user_profiles/config.ts b/x-pack/test/functional/apps/user_profiles/config.ts new file mode 100644 index 00000000000000..d0d07ff2002816 --- /dev/null +++ b/x-pack/test/functional/apps/user_profiles/config.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. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/x-pack/test/functional/apps/user_profiles/index.ts b/x-pack/test/functional/apps/user_profiles/index.ts new file mode 100644 index 00000000000000..5932e2729bf4be --- /dev/null +++ b/x-pack/test/functional/apps/user_profiles/index.ts @@ -0,0 +1,14 @@ +/* + * 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 { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext) => { + describe('User Profiles page', function () { + loadTestFile(require.resolve('./user_profiles')); + }); +}; diff --git a/x-pack/test/functional/apps/user_profiles/user_profiles.ts b/x-pack/test/functional/apps/user_profiles/user_profiles.ts new file mode 100644 index 00000000000000..a9f2f7a519502e --- /dev/null +++ b/x-pack/test/functional/apps/user_profiles/user_profiles.ts @@ -0,0 +1,160 @@ +/* + * 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 { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getPageObjects }: FtrProviderContext) => { + const pageObjects = getPageObjects(['common', 'userProfiles', 'settings']); + + describe('User Profile Page', async () => { + before(async () => {}); + + describe('Details', async () => { + before(async () => { + await pageObjects.common.navigateToApp('security_account'); + }); + + it('should set the full name', async () => { + await pageObjects.userProfiles.setFullNameInputField('Test User 2'); + + await pageObjects.userProfiles.saveUserProfileChanges(); + + let toast = await pageObjects.common.closeToast(); + + expect(toast).to.be('Profile updated'); + + await pageObjects.userProfiles.setFullNameInputField('test user'); + + await pageObjects.userProfiles.saveUserProfileChanges(); + + toast = await pageObjects.common.closeToast(); + + expect(toast).to.be('Profile updated'); + }); + + it('should set the email', async () => { + await pageObjects.userProfiles.setEmailInputField('test@test.com'); + + await pageObjects.userProfiles.saveUserProfileChanges(); + + let toast = await pageObjects.common.closeToast(); + + expect(toast).to.be('Profile updated'); + + await pageObjects.userProfiles.setEmailInputField('', true); + + await pageObjects.userProfiles.saveUserProfileChanges(); + + toast = await pageObjects.common.closeToast(); + + expect(toast).to.be('Profile updated'); + }); + }); + + describe('Change Password', async () => { + before(async () => { + await pageObjects.common.navigateToApp('security_account'); + }); + + it('should set the current password and enter a new password, then submit', async () => { + const changePasswordButton = await pageObjects.userProfiles.getChangePasswordButton(); + await changePasswordButton.click(); + + await pageObjects.userProfiles.setCurrentPasswordField('changeme'); + await pageObjects.userProfiles.setNewPasswordField('changeme2'); + await pageObjects.userProfiles.setConfirmPasswordField('changeme2'); + + const submitButton = await pageObjects.userProfiles.getChangePasswordFormSubmitButton(); + await submitButton.click(); + + const initialToast = await pageObjects.common.closeToast(); + + expect(initialToast).to.be('Password successfully changed'); + + await changePasswordButton.click(); + + await pageObjects.userProfiles.setCurrentPasswordField('changeme2'); + await pageObjects.userProfiles.setNewPasswordField('changeme'); + await pageObjects.userProfiles.setConfirmPasswordField('changeme'); + + await submitButton.click(); + + const resetToast = await pageObjects.common.closeToast(); + + expect(resetToast).to.be('Password successfully changed'); + }); + }); + + describe('Theme', async () => { + it('should change theme based on the User Profile Theme control with default Adv. Settings value (light)', async () => { + await pageObjects.common.navigateToApp('security_account'); + + const themeKeyPadMenu = await pageObjects.userProfiles.getThemeKeypadMenu(); + expect(themeKeyPadMenu).not.to.be(null); + + await pageObjects.userProfiles.changeUserProfileTheme('Dark'); + const darkModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(darkModeTag).to.be('v8dark'); + + await pageObjects.userProfiles.changeUserProfileTheme('Light'); + const lightModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(lightModeTag).to.be('v8light'); + + await pageObjects.userProfiles.changeUserProfileTheme('Space default'); + const spaceDefaultModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(spaceDefaultModeTag).to.be('v8light'); + }); + + it('should change theme based on the User Profile Theme control with default Adv. Settings value set to dark', async () => { + await pageObjects.common.navigateToUrl('management', 'kibana/settings', { + basePath: '', + ensureCurrentUrl: false, + shouldLoginIfPrompted: false, + shouldUseHashForSubUrl: false, + }); + + let advancedSetting = await pageObjects.settings.getAdvancedSettingCheckbox( + 'theme:darkMode' + ); + expect(advancedSetting).to.be(null); + + await pageObjects.settings.toggleAdvancedSettingCheckbox('theme:darkMode', true); + advancedSetting = await pageObjects.settings.getAdvancedSettingCheckbox('theme:darkMode'); + expect(advancedSetting).to.be('true'); + + await pageObjects.common.navigateToApp('security_account'); + + let spaceDefaultModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(spaceDefaultModeTag).to.be('v8dark'); + + await pageObjects.userProfiles.changeUserProfileTheme('Light'); + const lightModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(lightModeTag).to.be('v8light'); + + await pageObjects.userProfiles.changeUserProfileTheme('Dark'); + const darkModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(darkModeTag).to.be('v8dark'); + + await pageObjects.userProfiles.changeUserProfileTheme('Space default'); + spaceDefaultModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(spaceDefaultModeTag).to.be('v8dark'); + + await pageObjects.common.navigateToUrl('management', 'kibana/settings', { + basePath: '', + ensureCurrentUrl: false, + shouldLoginIfPrompted: false, + shouldUseHashForSubUrl: false, + }); + + await pageObjects.settings.toggleAdvancedSettingCheckbox('theme:darkMode', false); + advancedSetting = await pageObjects.settings.getAdvancedSettingCheckbox('theme:darkMode'); + expect(advancedSetting).to.be(null); + }); + }); + }); +}; diff --git a/x-pack/test/functional/page_objects/index.ts b/x-pack/test/functional/page_objects/index.ts index a8ac0895ed255f..75f86f76459542 100644 --- a/x-pack/test/functional/page_objects/index.ts +++ b/x-pack/test/functional/page_objects/index.ts @@ -48,6 +48,7 @@ import { StatusPageObject } from './status_page'; import { TagManagementPageObject } from './tag_management_page'; import { UpgradeAssistantPageObject } from './upgrade_assistant_page'; import { UptimePageObject } from './uptime_page'; +import { UserProfilePageProvider } from './user_profile_page'; import { WatcherPageObject } from './watcher_page'; // just like services, PageObjects are defined as a map of @@ -95,5 +96,6 @@ export const pageObjects = { tagManagement: TagManagementPageObject, upgradeAssistant: UpgradeAssistantPageObject, uptime: UptimePageObject, + userProfiles: UserProfilePageProvider, watcher: WatcherPageObject, }; diff --git a/x-pack/test/functional/page_objects/user_profile_page.ts b/x-pack/test/functional/page_objects/user_profile_page.ts new file mode 100644 index 00000000000000..3380c10e20677e --- /dev/null +++ b/x-pack/test/functional/page_objects/user_profile_page.ts @@ -0,0 +1,99 @@ +/* + * 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 { FtrProviderContext } from '../ftr_provider_context'; + +export function UserProfilePageProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const find = getService('find'); + const browser = getService('browser'); + const retry = getService('retry'); + + const getThemeTag = async (): Promise => { + return await browser.execute('return __kbnThemeTag__'); + }; + + const getSaveProfileChangesButton = async () => { + return await testSubjects.find('saveProfileChangesButton'); + }; + + const getReloadWindowButton = async () => { + return await testSubjects.find('windowReloadButton'); + }; + + const getThemeKeypadButton = async (option: string) => { + option = option[0].toUpperCase() + option.substring(1).toLowerCase(); + return await testSubjects.find(`themeKeyPadItem${option}`); + }; + + const saveUserProfileChanges = async (): Promise => { + let saveProfileChangesButton; + await retry.try(async () => { + saveProfileChangesButton = await getSaveProfileChangesButton(); + expect(saveProfileChangesButton).not.to.be(null); + await saveProfileChangesButton.click(); + }); + }; + + const changeUserProfileTheme = async (theme: string): Promise => { + const themeModeButton = await getThemeKeypadButton(theme); + expect(themeModeButton).not.to.be(null); + await themeModeButton.click(); + + await saveUserProfileChanges(); + + let reloadWindowButton; + await retry.try(async () => { + reloadWindowButton = await getReloadWindowButton(); + expect(reloadWindowButton).not.to.be(null); + await reloadWindowButton.click(); + }); + }; + + return { + async getThemeKeypadMenu() { + return await find.byCssSelector('.euiKeyPadMenu'); + }, + + async setFullNameInputField(newFullName: string) { + return await testSubjects.setValue('userProfileFullName', newFullName); + }, + + async setEmailInputField(newEmailAddress: string, clearWithKeyboard: boolean = false) { + return await testSubjects.setValue('userProfileEmail', newEmailAddress, { + clearWithKeyboard, + }); + }, + + async getChangePasswordButton() { + return await testSubjects.find('openChangePasswordForm'); + }, + + async setCurrentPasswordField(currentPassword: string) { + return await testSubjects.setValue( + 'editUserChangePasswordCurrentPasswordInput', + currentPassword + ); + }, + + async setNewPasswordField(newPassword: string) { + return await testSubjects.setValue('editUserChangePasswordNewPasswordInput', newPassword); + }, + + async setConfirmPasswordField(newPassword: string) { + return await testSubjects.setValue('editUserChangePasswordConfirmPasswordInput', newPassword); + }, + + async getChangePasswordFormSubmitButton() { + return await testSubjects.find('changePasswordFormSubmitButton'); + }, + getThemeTag, + saveUserProfileChanges, + changeUserProfileTheme, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts b/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts index bbcd138e20160a..bbb66a98418682 100644 --- a/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts @@ -11,5 +11,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('Serverless Common UI - Platform Security', function () { loadTestFile(require.resolve('./api_keys')); loadTestFile(require.resolve('./navigation/avatar_menu')); + loadTestFile(require.resolve('./user_profiles/user_profiles')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/common/platform_security/user_profiles/user_profiles.ts b/x-pack/test_serverless/functional/test_suites/common/platform_security/user_profiles/user_profiles.ts new file mode 100644 index 00000000000000..57ef995a4f7a61 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/platform_security/user_profiles/user_profiles.ts @@ -0,0 +1,40 @@ +/* + * 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 { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getPageObjects }: FtrProviderContext) { + const pageObjects = getPageObjects(['svlCommonPage', 'common', 'userProfiles']); + + describe('User Profile Page', async () => { + before(async () => { + await pageObjects.svlCommonPage.login(); + }); + + describe('Theme', async () => { + it('should change theme based on the User Profile Theme control', async () => { + await pageObjects.common.navigateToApp('security_account'); + + const themeKeyPadMenu = await pageObjects.userProfiles.getThemeKeypadMenu(); + expect(themeKeyPadMenu).not.to.be(null); + + await pageObjects.userProfiles.changeUserProfileTheme('Dark'); + const darkModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(darkModeTag).to.be('v8dark'); + + await pageObjects.userProfiles.changeUserProfileTheme('Light'); + const lightModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(lightModeTag).to.be('v8light'); + + await pageObjects.userProfiles.changeUserProfileTheme('Space default'); + const spaceDefaultModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(spaceDefaultModeTag).to.be('v8light'); + }); + }); + }); +} From d5fc9b0314cc5a56fac46668728284a91ea9ee6a Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 22 Nov 2023 17:03:35 +0100 Subject: [PATCH 8/8] [Synthetics] Refactor supress API Key error (#171114) --- .../synthetics_service/synthetics_service.ts | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts index 1602a7d29f12fd..fd37aa678ce633 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts @@ -423,49 +423,48 @@ export class SyntheticsService { }; for await (const result of finder.find()) { - if (result.saved_objects.length === 0) { - return; - } - try { - if (!output) { - output = await this.getOutput(); + if (result.saved_objects.length > 0) { + try { if (!output) { - sendErrorTelemetryEvents(service.logger, service.server.telemetry, { - reason: 'API key is not valid.', - message: 'Failed to push configs. API key is not valid.', - type: 'invalidApiKey', - stackVersion: service.server.stackVersion, - }); - return; + output = await this.getOutput(); + if (!output) { + sendErrorTelemetryEvents(service.logger, service.server.telemetry, { + reason: 'API key is not valid.', + message: 'Failed to push configs. API key is not valid.', + type: 'invalidApiKey', + stackVersion: service.server.stackVersion, + }); + return; + } } - } - const monitors = result.saved_objects.filter(({ error }) => !error); - const formattedConfigs = this.normalizeConfigs(monitors, paramsBySpace); + const monitors = result.saved_objects.filter(({ error }) => !error); + const formattedConfigs = this.normalizeConfigs(monitors, paramsBySpace); - this.logger.debug( - `${formattedConfigs.length} monitors will be pushed to synthetics service.` - ); + this.logger.debug( + `${formattedConfigs.length} monitors will be pushed to synthetics service.` + ); - formattedConfigs.forEach((monitor) => { - monitor.locations.forEach((location) => { - if (location.isServiceManaged) { - bucketsByLocation[location.id]?.push(monitor); - } + formattedConfigs.forEach((monitor) => { + monitor.locations.forEach((location) => { + if (location.isServiceManaged) { + bucketsByLocation[location.id]?.push(monitor); + } + }); }); - }); - await syncAllLocations(PER_PAGE); - } catch (e) { - sendErrorTelemetryEvents(service.logger, service.server.telemetry, { - reason: 'Failed to push configs to service', - message: e?.message, - type: 'pushConfigsError', - code: e?.code, - status: e.status, - stackVersion: service.server.stackVersion, - }); - this.logger.error(e); + await syncAllLocations(PER_PAGE); + } catch (e) { + sendErrorTelemetryEvents(service.logger, service.server.telemetry, { + reason: 'Failed to push configs to service', + message: e?.message, + type: 'pushConfigsError', + code: e?.code, + status: e.status, + stackVersion: service.server.stackVersion, + }); + this.logger.error(e); + } } }