mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Synthetics] Enable throttling in synthetics app (#154378)
## Summary Enable throttling config in synthetics app !! <img width="1773" alt="image" src="https://user-images.githubusercontent.com/3505601/229875799-d87b0ad6-c318-4a17-9012-c56666841b5c.png"> --------- Co-authored-by: Dominique Clarke <dominique.clarke@elastic.co>
This commit is contained in:
parent
54f9f11339
commit
2fbfb33bed
47 changed files with 1481 additions and 274 deletions
|
@ -138,7 +138,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
|
|||
"slo": "aefffabdb35d15a6c388634af2cee1fa59ede83c",
|
||||
"space": "7fc578a1f9f7708cb07479f03953d664ad9f1dae",
|
||||
"spaces-usage-stats": "084bd0f080f94fb5735d7f3cf12f13ec92f36bad",
|
||||
"synthetics-monitor": "7136a2669a65323c56da849f26c369cdeeb3b381",
|
||||
"synthetics-monitor": "fa988678e5d6791c75515fa1acdbbb3b2d1f916d",
|
||||
"synthetics-param": "9776c9b571d35f0d0397e8915e035ea1dc026db7",
|
||||
"synthetics-privates-locations": "7d032fc788905e32152029ae7ab3d6038c48ae44",
|
||||
"tag": "87f21f07df9cc37001b15a26e413c18f50d1fbfe",
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
BrowserAdvancedFields,
|
||||
BrowserSimpleFields,
|
||||
|
@ -22,6 +23,7 @@ import {
|
|||
SourceType,
|
||||
TCPAdvancedFields,
|
||||
TCPSimpleFields,
|
||||
ThrottlingConfig,
|
||||
TLSFields,
|
||||
TLSVersion,
|
||||
VerificationMode,
|
||||
|
@ -30,6 +32,86 @@ import { ConfigKey } from './monitor_management';
|
|||
|
||||
export const DEFAULT_NAMESPACE_STRING = 'default';
|
||||
|
||||
export enum PROFILE_VALUES_ENUM {
|
||||
DEFAULT = 'default',
|
||||
CABLE = 'cable',
|
||||
DSL = 'dsl',
|
||||
THREE_G = '3g',
|
||||
FOUR_G = '4g',
|
||||
LTE = 'lte',
|
||||
FIBRE = 'fibre',
|
||||
NO_THROTTLING = 'no-throttling',
|
||||
CUSTOM = 'custom',
|
||||
}
|
||||
|
||||
export const CUSTOM_LABEL = i18n.translate('xpack.synthetics.connectionProfile.custom', {
|
||||
defaultMessage: 'Custom',
|
||||
});
|
||||
|
||||
export const PROFILE_VALUES: ThrottlingConfig[] = [
|
||||
{
|
||||
value: { download: '5', upload: '3', latency: '20' },
|
||||
id: PROFILE_VALUES_ENUM.DEFAULT,
|
||||
label: i18n.translate('xpack.synthetics.connectionProfile.default', {
|
||||
defaultMessage: 'Default',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: { download: '5', upload: '1', latency: '28' },
|
||||
id: PROFILE_VALUES_ENUM.CABLE,
|
||||
label: i18n.translate('xpack.synthetics.connectionProfile.cable', {
|
||||
defaultMessage: 'Cable',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: { download: '1.5', upload: '0.384', latency: '50' },
|
||||
id: PROFILE_VALUES_ENUM.DSL,
|
||||
label: i18n.translate('xpack.synthetics.connectionProfile.dsl', {
|
||||
defaultMessage: 'DSL',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: { download: '1.6', upload: '0.768', latency: '300' },
|
||||
id: PROFILE_VALUES_ENUM.THREE_G,
|
||||
label: i18n.translate('xpack.synthetics.connectionProfile.threeG', {
|
||||
defaultMessage: '3G',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: { download: '9', upload: '0.75', latency: '170' },
|
||||
id: PROFILE_VALUES_ENUM.FOUR_G,
|
||||
label: i18n.translate('xpack.synthetics.connectionProfile.fourG', {
|
||||
defaultMessage: '4G',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: { download: '12', upload: '0.75', latency: '70' },
|
||||
id: PROFILE_VALUES_ENUM.LTE,
|
||||
label: i18n.translate('xpack.synthetics.connectionProfile.lte', {
|
||||
defaultMessage: 'LTE',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: { download: '20', upload: '5', latency: '4' },
|
||||
id: PROFILE_VALUES_ENUM.FIBRE,
|
||||
label: i18n.translate('xpack.synthetics.connectionProfile.fibre', {
|
||||
defaultMessage: 'Fibre',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: null,
|
||||
id: PROFILE_VALUES_ENUM.NO_THROTTLING,
|
||||
label: i18n.translate('xpack.synthetics.connectionProfile.noThrottling', {
|
||||
defaultMessage: 'No throttling',
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
export const PROFILES_MAP = PROFILE_VALUES.reduce((acc, profile) => {
|
||||
acc[profile.id] = profile;
|
||||
return acc;
|
||||
}, {} as { [key: string]: ThrottlingConfig });
|
||||
|
||||
export const ALLOWED_SCHEDULES_IN_MINUTES = [
|
||||
'1',
|
||||
'3',
|
||||
|
@ -71,11 +153,7 @@ export const DEFAULT_BROWSER_ADVANCED_FIELDS: BrowserAdvancedFields = {
|
|||
[ConfigKey.JOURNEY_FILTERS_MATCH]: '',
|
||||
[ConfigKey.JOURNEY_FILTERS_TAGS]: [],
|
||||
[ConfigKey.IGNORE_HTTPS_ERRORS]: false,
|
||||
[ConfigKey.IS_THROTTLING_ENABLED]: true,
|
||||
[ConfigKey.DOWNLOAD_SPEED]: '5',
|
||||
[ConfigKey.UPLOAD_SPEED]: '3',
|
||||
[ConfigKey.LATENCY]: '20',
|
||||
[ConfigKey.THROTTLING_CONFIG]: '5d/3u/20l',
|
||||
[ConfigKey.THROTTLING_CONFIG]: PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT],
|
||||
};
|
||||
|
||||
export const DEFAULT_BROWSER_SIMPLE_FIELDS: BrowserSimpleFields = {
|
||||
|
|
|
@ -65,11 +65,7 @@ export enum ConfigKey {
|
|||
TLS_VERSION = 'ssl.supported_protocols',
|
||||
TAGS = 'tags',
|
||||
TIMEOUT = 'timeout',
|
||||
THROTTLING_CONFIG = 'throttling.config',
|
||||
IS_THROTTLING_ENABLED = 'throttling.is_enabled',
|
||||
DOWNLOAD_SPEED = 'throttling.download_speed',
|
||||
UPLOAD_SPEED = 'throttling.upload_speed',
|
||||
LATENCY = 'throttling.latency',
|
||||
THROTTLING_CONFIG = 'throttling',
|
||||
URLS = 'urls',
|
||||
USERNAME = 'username',
|
||||
WAIT = 'wait',
|
||||
|
@ -106,4 +102,10 @@ export enum LegacyConfigKey {
|
|||
ZIP_URL_TLS_KEY_PASSPHRASE = 'source.zip_url.ssl.key_passphrase',
|
||||
ZIP_URL_TLS_VERIFICATION_MODE = 'source.zip_url.ssl.verification_mode',
|
||||
ZIP_URL_TLS_VERSION = 'source.zip_url.ssl.supported_protocols',
|
||||
|
||||
THROTTLING_CONFIG = 'throttling.config',
|
||||
IS_THROTTLING_ENABLED = 'throttling.is_enabled',
|
||||
DOWNLOAD_SPEED = 'throttling.download_speed',
|
||||
UPLOAD_SPEED = 'throttling.upload_speed',
|
||||
LATENCY = 'throttling.latency',
|
||||
}
|
||||
|
|
|
@ -17,29 +17,20 @@ import { tlsFormatters } from '../tls/formatters';
|
|||
|
||||
export type BrowserFormatMap = Record<keyof BrowserFields, Formatter>;
|
||||
|
||||
const throttlingFormatter: Formatter = (fields) => {
|
||||
if (!fields[ConfigKey.IS_THROTTLING_ENABLED]) return 'false';
|
||||
export const throttlingFormatter: Formatter = (fields) => {
|
||||
const throttling = fields[ConfigKey.THROTTLING_CONFIG];
|
||||
|
||||
const getThrottlingValue = (v: string | undefined, suffix: 'd' | 'u' | 'l') =>
|
||||
v !== '' && v !== undefined ? `${v}${suffix}` : null;
|
||||
if (!throttling || throttling?.id === 'no-throttling' || !throttling?.value) {
|
||||
return 'false';
|
||||
}
|
||||
|
||||
return [
|
||||
getThrottlingValue(fields[ConfigKey.DOWNLOAD_SPEED], 'd'),
|
||||
getThrottlingValue(fields[ConfigKey.UPLOAD_SPEED], 'u'),
|
||||
getThrottlingValue(fields[ConfigKey.LATENCY], 'l'),
|
||||
]
|
||||
.filter((v) => v !== null)
|
||||
.join('/');
|
||||
return `${throttling.value.download}d/${throttling.value.upload}u/${throttling.value.latency}l`;
|
||||
};
|
||||
|
||||
export const browserFormatters: BrowserFormatMap = {
|
||||
[ConfigKey.SOURCE_PROJECT_CONTENT]: null,
|
||||
[ConfigKey.PARAMS]: null,
|
||||
[ConfigKey.SCREENSHOTS]: null,
|
||||
[ConfigKey.IS_THROTTLING_ENABLED]: null,
|
||||
[ConfigKey.DOWNLOAD_SPEED]: null,
|
||||
[ConfigKey.UPLOAD_SPEED]: null,
|
||||
[ConfigKey.LATENCY]: null,
|
||||
[ConfigKey.IGNORE_HTTPS_ERRORS]: null,
|
||||
[ConfigKey.PLAYWRIGHT_OPTIONS]: null,
|
||||
[ConfigKey.TEXT_ASSERTION]: null,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
import { ConfigKey, DataStream } from '../runtime_types';
|
||||
import { formatSyntheticsPolicy } from './format_synthetics_policy';
|
||||
import { PROFILE_VALUES_ENUM, PROFILES_MAP } from '../constants/monitor_defaults';
|
||||
|
||||
const gParams = { proxyUrl: 'https://proxy.com' };
|
||||
describe('formatSyntheticsPolicy', () => {
|
||||
|
@ -1145,11 +1146,7 @@ const browserConfig: any = {
|
|||
'filter_journeys.match': '',
|
||||
'filter_journeys.tags': [],
|
||||
ignore_https_errors: false,
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.upload_speed': '3',
|
||||
'throttling.latency': '20',
|
||||
'throttling.config': '5d/3u/20l',
|
||||
throttling: PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT],
|
||||
'ssl.certificate_authorities': '',
|
||||
'ssl.certificate': '',
|
||||
'ssl.key': '',
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
import { NewPackagePolicy } from '@kbn/fleet-plugin/common';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { throttlingFormatter } from './browser/formatters';
|
||||
import { LegacyConfigKey } from '../constants/monitor_management';
|
||||
import { replaceStringWithParams } from './formatting_utils';
|
||||
import { syntheticsPolicyFormatters } from './formatters';
|
||||
import { ConfigKey, DataStream, MonitorFields } from '../runtime_types';
|
||||
|
@ -69,5 +71,11 @@ export const formatSyntheticsPolicy = (
|
|||
}
|
||||
});
|
||||
|
||||
// TODO: remove this once we remove legacy support
|
||||
const throttling = dataStream?.vars?.[LegacyConfigKey.THROTTLING_CONFIG];
|
||||
if (throttling) {
|
||||
throttling.value = throttlingFormatter?.(config, ConfigKey.THROTTLING_CONFIG);
|
||||
}
|
||||
|
||||
return { formattedPolicy, hasDataStream: Boolean(dataStream), hasInput: Boolean(currentInput) };
|
||||
};
|
||||
|
|
|
@ -111,15 +111,6 @@ export enum ScreenshotOption {
|
|||
export const ScreenshotOptionCodec = tEnum<ScreenshotOption>('ScreenshotOption', ScreenshotOption);
|
||||
export type ScreenshotOptionType = t.TypeOf<typeof ScreenshotOptionCodec>;
|
||||
|
||||
export enum ThrottlingSuffix {
|
||||
DOWNLOAD = 'd',
|
||||
UPLOAD = 'u',
|
||||
LATENCY = 'l',
|
||||
}
|
||||
|
||||
export const ThrottlingSuffixCodec = tEnum<ThrottlingSuffix>('ThrottlingSuffix', ThrottlingSuffix);
|
||||
export type ThrottlingSuffixType = t.TypeOf<typeof ThrottlingSuffixCodec>;
|
||||
|
||||
export enum SourceType {
|
||||
UI = 'ui',
|
||||
PROJECT = 'project',
|
||||
|
|
|
@ -192,15 +192,6 @@ export const HTTPFieldsCodec = t.intersection([
|
|||
|
||||
export type HTTPFields = t.TypeOf<typeof HTTPFieldsCodec>;
|
||||
|
||||
// Browser Fields
|
||||
export const ThrottlingConfigKeyCodec = t.union([
|
||||
t.literal(ConfigKey.DOWNLOAD_SPEED),
|
||||
t.literal(ConfigKey.UPLOAD_SPEED),
|
||||
t.literal(ConfigKey.LATENCY),
|
||||
]);
|
||||
|
||||
export type ThrottlingConfigKey = t.TypeOf<typeof ThrottlingConfigKeyCodec>;
|
||||
|
||||
export const EncryptedBrowserSimpleFieldsCodec = t.intersection([
|
||||
t.intersection([
|
||||
t.interface({
|
||||
|
@ -225,16 +216,28 @@ export const BrowserSensitiveSimpleFieldsCodec = t.intersection([
|
|||
CommonFieldsCodec,
|
||||
]);
|
||||
|
||||
export const ThrottlingConfigValueCodec = t.interface({
|
||||
download: t.string,
|
||||
upload: t.string,
|
||||
latency: t.string,
|
||||
});
|
||||
|
||||
export type ThrottlingConfigValue = t.TypeOf<typeof ThrottlingConfigValueCodec>;
|
||||
|
||||
export const ThrottlingConfigCodec = t.interface({
|
||||
value: t.union([ThrottlingConfigValueCodec, t.null]),
|
||||
label: t.string,
|
||||
id: t.string,
|
||||
});
|
||||
|
||||
export type ThrottlingConfig = t.TypeOf<typeof ThrottlingConfigCodec>;
|
||||
|
||||
export const EncryptedBrowserAdvancedFieldsCodec = t.interface({
|
||||
[ConfigKey.SCREENSHOTS]: t.string,
|
||||
[ConfigKey.JOURNEY_FILTERS_MATCH]: t.string,
|
||||
[ConfigKey.JOURNEY_FILTERS_TAGS]: t.array(t.string),
|
||||
[ConfigKey.IGNORE_HTTPS_ERRORS]: t.boolean,
|
||||
[ConfigKey.IS_THROTTLING_ENABLED]: t.boolean,
|
||||
[ConfigKey.DOWNLOAD_SPEED]: t.string,
|
||||
[ConfigKey.UPLOAD_SPEED]: t.string,
|
||||
[ConfigKey.LATENCY]: t.string,
|
||||
[ConfigKey.THROTTLING_CONFIG]: t.string,
|
||||
[ConfigKey.THROTTLING_CONFIG]: ThrottlingConfigCodec,
|
||||
});
|
||||
|
||||
export const BrowserSimpleFieldsCodec = t.intersection([
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ConfigKey, MonitorFields } from '../runtime_types';
|
||||
import { ConfigKey, MonitorFields, ThrottlingConfig } from '../runtime_types';
|
||||
|
||||
export type Validator = (config: Partial<MonitorFields>) => boolean;
|
||||
export type NamespaceValidator = (config: Partial<MonitorFields>) => false | string;
|
||||
export type Validator = (config: Partial<MonitorFields & ThrottlingConfig>) => boolean;
|
||||
export type NamespaceValidator = (
|
||||
config: Partial<MonitorFields & ThrottlingConfig>
|
||||
) => false | string;
|
||||
|
||||
export type ConfigValidation = Omit<Record<ConfigKey, Validator>, ConfigKey.NAMESPACE> &
|
||||
Record<ConfigKey.NAMESPACE, NamespaceValidator>;
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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 { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import React from 'react';
|
||||
import { PROFILE_VALUES_ENUM } from '../../../../../../../common/constants/monitor_defaults';
|
||||
import { ThrottlingConfig } from '../../../../../../../common/runtime_types';
|
||||
|
||||
export const ConnectionProfile = ({
|
||||
throttling,
|
||||
id,
|
||||
}: {
|
||||
throttling?: ThrottlingConfig;
|
||||
id: string;
|
||||
}) => {
|
||||
if (id === PROFILE_VALUES_ENUM.NO_THROTTLING) {
|
||||
return (
|
||||
<EuiFlexGroup alignItems="baseline" gutterSize="xs">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.monitorAddEdit.throttling.connectionProfile.disabled.label"
|
||||
defaultMessage="No throttling"
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
||||
if (throttling && throttling.value) {
|
||||
const { label, value } = throttling;
|
||||
|
||||
return (
|
||||
<EuiFlexGroup alignItems="baseline" gutterSize="xs">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText>{label}</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.monitorAddEdit.throttling.connectionProfile"
|
||||
defaultMessage="({download} Mbps, {upload} Mbps, {latency} ms)"
|
||||
values={{
|
||||
download: value.download,
|
||||
upload: value.upload,
|
||||
latency: value.latency,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<EuiFlexGroup alignItems="baseline" gutterSize="xs">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.monitorAddEdit.throttling.connectionProfile.custom.label"
|
||||
defaultMessage="Custom"
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.monitorAddEdit.throttling.connectionProfile.custom"
|
||||
defaultMessage="(X Mbps, Y Mbps, Z ms)"
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { fireEvent, screen } from '@testing-library/react';
|
||||
import { PROFILE_OPTIONS, ThrottlingConfigField } from './throttling_config_field';
|
||||
import { render } from '../../../../utils/testing';
|
||||
import { PROFILES_MAP } from '../../../../../../../common/constants/monitor_defaults';
|
||||
|
||||
describe('ThrottlingConfigField', () => {
|
||||
it('renders', async () => {
|
||||
render(
|
||||
<ThrottlingConfigField
|
||||
ariaLabel={'ariaLabel'}
|
||||
initialValue={PROFILES_MAP.default}
|
||||
value={PROFILES_MAP.default}
|
||||
id={'id'}
|
||||
options={PROFILE_OPTIONS}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
expect(await screen.findByText('(5 Mbps, 3 Mbps, 20 ms)')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('selects custom values', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(
|
||||
<ThrottlingConfigField
|
||||
ariaLabel={'ariaLabel'}
|
||||
initialValue={PROFILES_MAP.default}
|
||||
value={PROFILES_MAP.default}
|
||||
id={'id'}
|
||||
options={PROFILE_OPTIONS}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
expect(await screen.findByText('(5 Mbps, 3 Mbps, 20 ms)')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByTestId('syntheticsThrottlingSelect'));
|
||||
fireEvent.click(await screen.findByTestId('syntheticsThrottlingSelectCustom'));
|
||||
|
||||
const customValue = {
|
||||
id: 'custom',
|
||||
label: 'Custom',
|
||||
value: { download: '5', latency: '20', upload: '3' },
|
||||
};
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith(customValue);
|
||||
});
|
||||
|
||||
it('changes custom values', async () => {
|
||||
const onChange = jest.fn();
|
||||
const customValue = {
|
||||
id: 'custom',
|
||||
label: 'Custom',
|
||||
value: { download: '5', latency: '20', upload: '3' },
|
||||
};
|
||||
|
||||
render(
|
||||
<ThrottlingConfigField
|
||||
ariaLabel={'ariaLabel'}
|
||||
initialValue={customValue}
|
||||
value={customValue}
|
||||
id={'id'}
|
||||
options={PROFILE_OPTIONS}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
|
||||
fireEvent.input(screen.getByTestId('syntheticsBrowserUploadSpeed'), {
|
||||
target: { value: '10' },
|
||||
});
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
...customValue,
|
||||
value: { ...customValue.value, upload: '10' },
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { EuiSuperSelect } from '@elastic/eui';
|
||||
import { useConnectionProfiles } from './use_connection_profiles';
|
||||
import { ThrottlingDisabledCallout } from './throttling_disabled_callout';
|
||||
import { ThrottlingConfig } from '../../../../../../../common/runtime_types';
|
||||
import { ThrottlingFields } from './throttling_fields';
|
||||
import { PROFILE_VALUES_ENUM, PROFILE_VALUES, PROFILES_MAP, CUSTOM_LABEL } from '../../constants';
|
||||
import { ConnectionProfile } from './connection_profile';
|
||||
|
||||
export interface ThrottlingConfigFieldProps {
|
||||
ariaLabel: string;
|
||||
id: string;
|
||||
onChange: (value: ThrottlingConfig) => void;
|
||||
value: ThrottlingConfig;
|
||||
placeholder?: string;
|
||||
height?: string;
|
||||
readOnly?: boolean;
|
||||
disabled?: boolean;
|
||||
fullWidth?: boolean;
|
||||
options: typeof PROFILE_OPTIONS;
|
||||
initialValue?: ThrottlingConfig;
|
||||
}
|
||||
|
||||
export const ThrottlingConfigField = (props: ThrottlingConfigFieldProps) => {
|
||||
const { value, initialValue } = props;
|
||||
|
||||
const isCustom = PROFILES_MAP[value?.id] === undefined;
|
||||
|
||||
const isThrottlingDisabled = value?.id === PROFILE_VALUES_ENUM.NO_THROTTLING;
|
||||
|
||||
const options = useConnectionProfiles(initialValue);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiSuperSelect
|
||||
data-test-subj="syntheticsThrottlingSelect"
|
||||
options={options}
|
||||
onChange={(newValue) => {
|
||||
if (newValue === PROFILE_VALUES_ENUM.CUSTOM) {
|
||||
props.onChange({
|
||||
...PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT],
|
||||
id: PROFILE_VALUES_ENUM.CUSTOM,
|
||||
label: CUSTOM_LABEL,
|
||||
});
|
||||
} else {
|
||||
props.onChange({
|
||||
...PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT],
|
||||
...PROFILES_MAP[newValue],
|
||||
});
|
||||
}
|
||||
}}
|
||||
defaultValue={PROFILE_VALUES_ENUM.DEFAULT}
|
||||
valueOfSelected={value?.id}
|
||||
fullWidth={props.fullWidth}
|
||||
readOnly={props.readOnly}
|
||||
/>
|
||||
{isThrottlingDisabled && <ThrottlingDisabledCallout />}
|
||||
{isCustom && (
|
||||
<ThrottlingFields
|
||||
throttling={props?.value}
|
||||
setValue={props.onChange}
|
||||
readOnly={props.readOnly}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const PROFILE_OPTIONS = PROFILE_VALUES.map(({ id }) => ({
|
||||
value: id,
|
||||
inputDisplay: <ConnectionProfile throttling={PROFILES_MAP[id]} id={id} />,
|
||||
'data-test-subj': `syntheticsThrottlingSelect-${id}`,
|
||||
}));
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 { EuiCallOut, EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import React from 'react';
|
||||
|
||||
export const ThrottlingDisabledCallout = () => {
|
||||
return (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.createPackagePolicy.stepConfigure.browserAdvancedSettings.throttling.automatic_node_cap.title"
|
||||
defaultMessage="Automatic cap"
|
||||
/>
|
||||
}
|
||||
color="warning"
|
||||
iconType="warning"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.createPackagePolicy.stepConfigure.browserAdvancedSettings.throttling.automatic_node_cap.message"
|
||||
defaultMessage="When disabling throttling, your monitor will still have its bandwidth capped by the configurations of the Synthetics Nodes in which it's running."
|
||||
/>
|
||||
</EuiCallOut>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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 { EuiFieldNumber, EuiFormRow, EuiText } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Validation } from '../../../../../../../common/types';
|
||||
import {
|
||||
BandwidthLimitKey,
|
||||
ConfigKey,
|
||||
DEFAULT_BANDWIDTH_LIMIT,
|
||||
ThrottlingConfig,
|
||||
ThrottlingConfigValue,
|
||||
} from '../../../../../../../common/runtime_types';
|
||||
import { ThrottlingExceededMessage } from './throttling_exceeded_callout';
|
||||
import { OptionalLabel } from '../optional_label';
|
||||
|
||||
export const ThrottlingDownloadField = ({
|
||||
handleInputChange,
|
||||
readOnly,
|
||||
onFieldBlur,
|
||||
validate,
|
||||
throttling,
|
||||
throttlingValue,
|
||||
}: {
|
||||
readOnly?: boolean;
|
||||
handleInputChange: (value: string) => void;
|
||||
onFieldBlur?: (field: keyof ThrottlingConfigValue) => void;
|
||||
validate?: Validation;
|
||||
throttling: ThrottlingConfig;
|
||||
throttlingValue: ThrottlingConfigValue;
|
||||
}) => {
|
||||
const maxDownload = Number(DEFAULT_BANDWIDTH_LIMIT[BandwidthLimitKey.DOWNLOAD]);
|
||||
|
||||
const exceedsDownloadLimits = Number(throttlingValue.download) > maxDownload;
|
||||
|
||||
return (
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
label={DOWNLOAD_LABEL}
|
||||
labelAppend={<OptionalLabel />}
|
||||
isInvalid={
|
||||
(validate ? !!validate?.[ConfigKey.THROTTLING_CONFIG]?.(throttling) : false) ||
|
||||
exceedsDownloadLimits
|
||||
}
|
||||
error={
|
||||
exceedsDownloadLimits ? (
|
||||
<ThrottlingExceededMessage throttlingField="download" limit={maxDownload} />
|
||||
) : (
|
||||
DOWNLOAD_SPEED_ERROR
|
||||
)
|
||||
}
|
||||
>
|
||||
<EuiFieldNumber
|
||||
fullWidth
|
||||
min={0}
|
||||
step={0.001}
|
||||
value={throttlingValue.download}
|
||||
onChange={(event) => {
|
||||
handleInputChange(event.target.value);
|
||||
}}
|
||||
onBlur={() => onFieldBlur?.('download')}
|
||||
data-test-subj="syntheticsBrowserDownloadSpeed"
|
||||
append={
|
||||
<EuiText size="xs">
|
||||
<strong>Mbps</strong>
|
||||
</EuiText>
|
||||
}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
};
|
||||
|
||||
export const DOWNLOAD_LABEL = i18n.translate(
|
||||
'xpack.synthetics.createPackagePolicy.stepConfigure.browserAdvancedSettings.throttling.download.label',
|
||||
{
|
||||
defaultMessage: 'Download Speed',
|
||||
}
|
||||
);
|
||||
|
||||
export const DOWNLOAD_SPEED_ERROR = i18n.translate(
|
||||
'xpack.synthetics.createPackagePolicy.stepConfigure.browserAdvancedSettings.throttling.download.error',
|
||||
{
|
||||
defaultMessage: 'Download speed must be greater than zero.',
|
||||
}
|
||||
);
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 { EuiCallOut, EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import React from 'react';
|
||||
|
||||
export const ThrottlingExceededCallout = () => {
|
||||
return (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.createPackagePolicy.stepConfigure.browserAdvancedSettings.throttling.exceeded_throttling.title"
|
||||
defaultMessage="You've exceeded the Synthetics Node bandwidth limits"
|
||||
/>
|
||||
}
|
||||
color="warning"
|
||||
iconType="warning"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.createPackagePolicy.stepConfigure.browserAdvancedSettings.throttling.exceeded_throttling.message"
|
||||
defaultMessage="When using throttling values larger than a Synthetics Node bandwidth limit, your monitor will still have its bandwidth capped."
|
||||
/>
|
||||
</EuiCallOut>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const ThrottlingExceededMessage = ({
|
||||
throttlingField,
|
||||
limit,
|
||||
}: {
|
||||
throttlingField: string;
|
||||
limit: number;
|
||||
}) => {
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.createPackagePolicy.stepConfigure.browserAdvancedSettings.throttling.throttling_exceeded.message"
|
||||
defaultMessage="You have exceeded the { throttlingField } limit for Synthetic Nodes. The { throttlingField } value can't be larger than { limit }Mbps."
|
||||
values={{ throttlingField, limit }}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -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 React from 'react';
|
||||
import { fireEvent, screen } from '@testing-library/react';
|
||||
import { render } from '../../../../utils/testing';
|
||||
import { PROFILES_MAP } from '../../../../../../../common/constants/monitor_defaults';
|
||||
import { ThrottlingFields } from './throttling_fields';
|
||||
|
||||
describe('ThrottlingFields', () => {
|
||||
it('renders', async () => {
|
||||
render(<ThrottlingFields throttling={PROFILES_MAP.default} setValue={() => {}} />);
|
||||
|
||||
expect(await screen.findByText('Download Speed')).toBeInTheDocument();
|
||||
expect(await screen.findByText('Upload Speed')).toBeInTheDocument();
|
||||
expect(await screen.findByText('Latency')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls setValue on change', async () => {
|
||||
const setValue = jest.fn();
|
||||
render(<ThrottlingFields throttling={PROFILES_MAP.default} setValue={setValue} />);
|
||||
|
||||
const throttling = PROFILES_MAP.default;
|
||||
|
||||
const download = await screen.findByTestId('syntheticsBrowserDownloadSpeed');
|
||||
fireEvent.change(download, { target: { value: '10' } });
|
||||
expect(setValue).toHaveBeenCalledWith({
|
||||
...throttling,
|
||||
label: 'Custom',
|
||||
id: 'custom',
|
||||
value: { download: '10', latency: '20', upload: '3' },
|
||||
});
|
||||
|
||||
const upload = await screen.findByTestId('syntheticsBrowserUploadSpeed');
|
||||
fireEvent.change(upload, { target: { value: '10' } });
|
||||
expect(setValue).toHaveBeenLastCalledWith({
|
||||
...throttling,
|
||||
label: 'Custom',
|
||||
id: 'custom',
|
||||
value: { download: '5', latency: '20', upload: '10' },
|
||||
});
|
||||
|
||||
const latency = await screen.findByTestId('syntheticsBrowserLatency');
|
||||
fireEvent.change(latency, { target: { value: '10' } });
|
||||
expect(setValue).toHaveBeenLastCalledWith({
|
||||
...throttling,
|
||||
label: 'Custom',
|
||||
id: 'custom',
|
||||
value: { download: '5', latency: '10', upload: '3' },
|
||||
});
|
||||
});
|
||||
|
||||
it('shows maximum bandwidth callout on download and upload change', async () => {
|
||||
const setValue = jest.fn();
|
||||
const throttling = PROFILES_MAP.default;
|
||||
|
||||
render(
|
||||
<ThrottlingFields
|
||||
throttling={{
|
||||
...throttling,
|
||||
value: {
|
||||
...throttling.value!,
|
||||
download: '500',
|
||||
upload: '500',
|
||||
},
|
||||
}}
|
||||
setValue={setValue}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(
|
||||
await screen.findByText(
|
||||
'When using throttling values larger than a Synthetics Node bandwidth limit, your monitor will still have its bandwidth capped.'
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(
|
||||
await screen.findByText(
|
||||
"You have exceeded the download limit for Synthetic Nodes. The download value can't be larger than 100Mbps."
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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 React, { memo, useCallback } from 'react';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { ThrottlingUploadField } from './throttling_upload_field';
|
||||
import { ThrottlingExceededCallout } from './throttling_exceeded_callout';
|
||||
import {
|
||||
BandwidthLimitKey,
|
||||
DEFAULT_BANDWIDTH_LIMIT,
|
||||
ThrottlingConfig,
|
||||
ThrottlingConfigValue,
|
||||
} from '../../../../../../../common/runtime_types';
|
||||
import { Validation } from '../../types';
|
||||
import { ThrottlingDisabledCallout } from './throttling_disabled_callout';
|
||||
import { ThrottlingDownloadField } from './throttling_download_field';
|
||||
import { ThrottlingLatencyField } from './throttling_latency_field';
|
||||
import { CUSTOM_LABEL, PROFILE_VALUES_ENUM } from '../../constants';
|
||||
|
||||
interface Props {
|
||||
validate?: Validation;
|
||||
minColumnWidth?: string;
|
||||
onFieldBlur?: (field: keyof ThrottlingConfigValue) => void;
|
||||
readOnly?: boolean;
|
||||
throttling: ThrottlingConfig;
|
||||
setValue: (value: ThrottlingConfig) => void;
|
||||
}
|
||||
|
||||
export const ThrottlingFields = memo<Props>(
|
||||
({ validate, onFieldBlur, setValue, readOnly = false, throttling }) => {
|
||||
const maxDownload = DEFAULT_BANDWIDTH_LIMIT[BandwidthLimitKey.DOWNLOAD];
|
||||
const maxUpload = DEFAULT_BANDWIDTH_LIMIT[BandwidthLimitKey.UPLOAD];
|
||||
|
||||
const handleInputChange = useCallback(
|
||||
({ value, configKey }: { value: string; configKey: string }) => {
|
||||
setValue({
|
||||
...throttling,
|
||||
value: { ...throttling.value!, [configKey]: value },
|
||||
label: CUSTOM_LABEL,
|
||||
id: PROFILE_VALUES_ENUM.CUSTOM,
|
||||
});
|
||||
},
|
||||
[setValue, throttling]
|
||||
);
|
||||
|
||||
const exceedsDownloadLimits = Number(throttling.value?.download) > maxDownload;
|
||||
const exceedsUploadLimits = Number(throttling.value?.upload) > maxUpload;
|
||||
const isThrottlingEnabled = throttling.id !== PROFILE_VALUES_ENUM.NO_THROTTLING;
|
||||
|
||||
const hasExceededLimits = isThrottlingEnabled && (exceedsDownloadLimits || exceedsUploadLimits);
|
||||
|
||||
if (!isThrottlingEnabled || !throttling.value) {
|
||||
return <ThrottlingDisabledCallout />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{hasExceededLimits && <ThrottlingExceededCallout />}
|
||||
<EuiSpacer size="m" />
|
||||
<ThrottlingDownloadField
|
||||
validate={validate}
|
||||
onFieldBlur={onFieldBlur}
|
||||
throttling={throttling}
|
||||
throttlingValue={throttling.value}
|
||||
handleInputChange={(val) => {
|
||||
handleInputChange({ value: val, configKey: 'download' });
|
||||
}}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
<ThrottlingUploadField
|
||||
throttlingValue={throttling.value}
|
||||
validate={validate}
|
||||
onFieldBlur={onFieldBlur}
|
||||
throttling={throttling}
|
||||
handleInputChange={(val) => {
|
||||
handleInputChange({ value: val, configKey: 'upload' });
|
||||
}}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
<ThrottlingLatencyField
|
||||
throttlingValue={throttling.value}
|
||||
validate={validate}
|
||||
onFieldBlur={onFieldBlur}
|
||||
throttling={throttling}
|
||||
handleInputChange={(val) => {
|
||||
handleInputChange({ value: val, configKey: 'latency' });
|
||||
}}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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 { EuiFieldNumber, EuiFormRow, EuiText } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Validation } from '../../../../../../../common/types';
|
||||
import {
|
||||
ConfigKey,
|
||||
ThrottlingConfig,
|
||||
ThrottlingConfigValue,
|
||||
} from '../../../../../../../common/runtime_types';
|
||||
import { OptionalLabel } from '../optional_label';
|
||||
|
||||
export const ThrottlingLatencyField = ({
|
||||
throttling,
|
||||
readOnly,
|
||||
onFieldBlur,
|
||||
validate,
|
||||
handleInputChange,
|
||||
throttlingValue,
|
||||
}: {
|
||||
readOnly?: boolean;
|
||||
handleInputChange: (value: string) => void;
|
||||
onFieldBlur?: (field: keyof ThrottlingConfigValue) => void;
|
||||
validate?: Validation;
|
||||
throttling: ThrottlingConfig;
|
||||
throttlingValue: ThrottlingConfigValue;
|
||||
}) => {
|
||||
return (
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
label={LATENCY_LABEL}
|
||||
labelAppend={<OptionalLabel />}
|
||||
isInvalid={validate ? !!validate?.[ConfigKey.THROTTLING_CONFIG]?.(throttling) : false}
|
||||
error={LATENCY_NEGATIVE_ERROR}
|
||||
>
|
||||
<EuiFieldNumber
|
||||
fullWidth
|
||||
min={0}
|
||||
value={throttlingValue.latency}
|
||||
onChange={(event) => handleInputChange(event.target.value)}
|
||||
onBlur={() => onFieldBlur?.('latency')}
|
||||
data-test-subj="syntheticsBrowserLatency"
|
||||
append={
|
||||
<EuiText size="xs">
|
||||
<strong>ms</strong>
|
||||
</EuiText>
|
||||
}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
};
|
||||
|
||||
export const LATENCY_LABEL = i18n.translate(
|
||||
'xpack.synthetics.createPackagePolicy.stepConfigure.browserAdvancedSettings.throttling.latency.label',
|
||||
{
|
||||
defaultMessage: 'Latency',
|
||||
}
|
||||
);
|
||||
|
||||
export const LATENCY_NEGATIVE_ERROR = i18n.translate(
|
||||
'xpack.synthetics.createPackagePolicy.stepConfigure.browserAdvancedSettings.throttling.latency.error',
|
||||
{
|
||||
defaultMessage: 'Latency must not be negative.',
|
||||
}
|
||||
);
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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 { EuiFieldNumber, EuiFormRow, EuiText } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Validation } from '../../../../../../../common/types';
|
||||
import {
|
||||
BandwidthLimitKey,
|
||||
ConfigKey,
|
||||
DEFAULT_BANDWIDTH_LIMIT,
|
||||
ThrottlingConfig,
|
||||
ThrottlingConfigValue,
|
||||
} from '../../../../../../../common/runtime_types';
|
||||
import { ThrottlingExceededMessage } from './throttling_exceeded_callout';
|
||||
import { OptionalLabel } from '../optional_label';
|
||||
|
||||
export const ThrottlingUploadField = ({
|
||||
readOnly,
|
||||
onFieldBlur,
|
||||
throttling,
|
||||
validate,
|
||||
handleInputChange,
|
||||
throttlingValue,
|
||||
}: {
|
||||
readOnly?: boolean;
|
||||
handleInputChange: (value: string) => void;
|
||||
onFieldBlur?: (field: keyof ThrottlingConfigValue) => void;
|
||||
validate?: Validation;
|
||||
throttling: ThrottlingConfig;
|
||||
throttlingValue: ThrottlingConfigValue;
|
||||
}) => {
|
||||
const maxUpload = Number(DEFAULT_BANDWIDTH_LIMIT[BandwidthLimitKey.UPLOAD]);
|
||||
|
||||
const exceedsUploadLimits = Number(throttlingValue.upload) > maxUpload;
|
||||
|
||||
return (
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
label={UPLOAD_LABEL}
|
||||
labelAppend={<OptionalLabel />}
|
||||
isInvalid={
|
||||
(validate ? !!validate?.[ConfigKey.THROTTLING_CONFIG]?.(throttling) : false) ||
|
||||
exceedsUploadLimits
|
||||
}
|
||||
error={
|
||||
exceedsUploadLimits ? (
|
||||
<ThrottlingExceededMessage throttlingField="upload" limit={maxUpload} />
|
||||
) : (
|
||||
UPLOAD_SPEED_ERROR
|
||||
)
|
||||
}
|
||||
>
|
||||
<EuiFieldNumber
|
||||
fullWidth
|
||||
min={0}
|
||||
step={0.001}
|
||||
value={throttlingValue.upload}
|
||||
onChange={(event) => handleInputChange(event.target.value)}
|
||||
onBlur={() => onFieldBlur?.('upload')}
|
||||
data-test-subj="syntheticsBrowserUploadSpeed"
|
||||
append={
|
||||
<EuiText size="xs">
|
||||
<strong>Mbps</strong>
|
||||
</EuiText>
|
||||
}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
};
|
||||
|
||||
export const UPLOAD_LABEL = i18n.translate(
|
||||
'xpack.synthetics.createPackagePolicy.stepConfigure.browserAdvancedSettings.throttling.upload.label',
|
||||
{ defaultMessage: 'Upload Speed' }
|
||||
);
|
||||
|
||||
export const UPLOAD_SPEED_ERROR = i18n.translate(
|
||||
'xpack.synthetics.createPackagePolicy.stepConfigure.browserAdvancedSettings.throttling.upload.error',
|
||||
{
|
||||
defaultMessage: 'Upload speed must be greater than zero.',
|
||||
}
|
||||
);
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 React, { useMemo } from 'react';
|
||||
import { PROFILE_VALUES_ENUM } from '../../../../../../../common/constants/monitor_defaults';
|
||||
import { ConnectionProfile } from './connection_profile';
|
||||
import { PROFILE_OPTIONS } from './throttling_config_field';
|
||||
import { ThrottlingConfig } from '../../../../../../../common/runtime_types';
|
||||
|
||||
export const useConnectionProfiles = (initialValue?: ThrottlingConfig) => {
|
||||
return useMemo(() => {
|
||||
return [
|
||||
...PROFILE_OPTIONS,
|
||||
{
|
||||
value: PROFILE_VALUES_ENUM.CUSTOM,
|
||||
inputDisplay: (
|
||||
<ConnectionProfile
|
||||
id="custom"
|
||||
throttling={initialValue?.id === PROFILE_VALUES_ENUM.CUSTOM ? initialValue : undefined}
|
||||
/>
|
||||
),
|
||||
'data-test-subj': 'syntheticsThrottlingSelectCustom',
|
||||
},
|
||||
];
|
||||
}, [initialValue]);
|
||||
};
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { ConfigKey, DataStream, FormMonitorType, SyntheticsMonitor } from '../types';
|
||||
import { DEFAULT_FIELDS } from '../constants';
|
||||
import { DEFAULT_FIELDS, PROFILE_VALUES_ENUM, PROFILES_MAP } from '../constants';
|
||||
import { formatDefaultFormValues } from './defaults';
|
||||
|
||||
describe('defaults', () => {
|
||||
|
@ -52,11 +52,15 @@ describe('defaults', () => {
|
|||
'ssl.verification_mode': 'full',
|
||||
synthetics_args: [],
|
||||
tags: [],
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '3',
|
||||
throttling: {
|
||||
value: {
|
||||
download: '5',
|
||||
latency: '20',
|
||||
upload: '3',
|
||||
},
|
||||
id: 'default',
|
||||
label: 'Default',
|
||||
},
|
||||
timeout: '16',
|
||||
type: 'browser',
|
||||
'url.port': null,
|
||||
|
@ -114,11 +118,7 @@ describe('defaults', () => {
|
|||
'ssl.verification_mode': 'full',
|
||||
synthetics_args: [],
|
||||
tags: [],
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '3',
|
||||
throttling: PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT],
|
||||
timeout: '16',
|
||||
type: 'browser',
|
||||
'url.port': null,
|
||||
|
|
|
@ -14,8 +14,6 @@ import {
|
|||
EuiComboBoxOptionOption,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiSuperSelect,
|
||||
EuiText,
|
||||
EuiLink,
|
||||
EuiTextArea,
|
||||
EuiSelectProps,
|
||||
|
@ -27,10 +25,13 @@ import {
|
|||
EuiCheckboxProps,
|
||||
EuiTextAreaProps,
|
||||
EuiButtonGroupProps,
|
||||
EuiSuperSelectProps,
|
||||
EuiHighlight,
|
||||
EuiBadge,
|
||||
} from '@elastic/eui';
|
||||
import {
|
||||
PROFILE_OPTIONS,
|
||||
ThrottlingConfigFieldProps,
|
||||
} from '../fields/throttling/throttling_config_field';
|
||||
import {
|
||||
FieldText,
|
||||
FieldNumber,
|
||||
|
@ -53,6 +54,7 @@ import {
|
|||
ResponseBodyIndexField,
|
||||
ResponseBodyIndexFieldProps,
|
||||
ControlledFieldProp,
|
||||
ThrottlingWrapper,
|
||||
} from './field_wrappers';
|
||||
import { getDocLinks } from '../../../../../kibana_services';
|
||||
import { useMonitorName } from '../hooks/use_monitor_name';
|
||||
|
@ -67,12 +69,9 @@ import {
|
|||
VerificationMode,
|
||||
FieldMap,
|
||||
FormLocation,
|
||||
ThrottlingConfig,
|
||||
} from '../types';
|
||||
import {
|
||||
AlertConfigKey,
|
||||
DEFAULT_BROWSER_ADVANCED_FIELDS,
|
||||
ALLOWED_SCHEDULES_IN_MINUTES,
|
||||
} from '../constants';
|
||||
import { AlertConfigKey, ALLOWED_SCHEDULES_IN_MINUTES } from '../constants';
|
||||
import { getDefaultFormFields } from './defaults';
|
||||
import { validate, validateHeaders, WHOLE_NUMBERS_ONLY, FLOATS_ONLY } from './validation';
|
||||
|
||||
|
@ -1123,41 +1122,23 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({
|
|||
},
|
||||
[ConfigKey.THROTTLING_CONFIG]: {
|
||||
fieldKey: ConfigKey.THROTTLING_CONFIG,
|
||||
component: EuiSuperSelect,
|
||||
component: ThrottlingWrapper,
|
||||
label: i18n.translate('xpack.synthetics.monitorConfig.throttling.label', {
|
||||
defaultMessage: 'Connection profile',
|
||||
}),
|
||||
required: true,
|
||||
controlled: true,
|
||||
helpText: i18n.translate('xpack.synthetics.monitorConfig.throttling.helpText', {
|
||||
defaultMessage:
|
||||
'Simulate network throttling (download, upload, latency). More options will be added in a future version.',
|
||||
}),
|
||||
props: (): EuiSuperSelectProps<string> => ({
|
||||
options: [
|
||||
{
|
||||
value: DEFAULT_BROWSER_ADVANCED_FIELDS[ConfigKey.THROTTLING_CONFIG],
|
||||
inputDisplay: (
|
||||
<EuiFlexGroup alignItems="baseline" gutterSize="xs" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText>
|
||||
{i18n.translate('xpack.synthetics.monitorConfig.throttling.options.default', {
|
||||
defaultMessage: 'Default',
|
||||
})}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="xs" color="subdued">
|
||||
{'(5 Mbps, 3 Mbps, 20 ms)'}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
),
|
||||
},
|
||||
],
|
||||
readOnly,
|
||||
disabled: true, // currently disabled through 1.0 until we define connection profiles
|
||||
defaultMessage: 'Simulate network throttling (download, upload, latency).',
|
||||
}),
|
||||
props: ({ formState }): Partial<ThrottlingConfigFieldProps> => {
|
||||
return {
|
||||
options: PROFILE_OPTIONS,
|
||||
readOnly,
|
||||
disabled: false,
|
||||
initialValue: formState.defaultValues?.[ConfigKey.THROTTLING_CONFIG] as ThrottlingConfig,
|
||||
};
|
||||
},
|
||||
validation: () => ({
|
||||
required: true,
|
||||
}),
|
||||
|
|
|
@ -26,6 +26,10 @@ import {
|
|||
EuiComboBox,
|
||||
EuiComboBoxProps,
|
||||
} from '@elastic/eui';
|
||||
import {
|
||||
ThrottlingConfigField,
|
||||
ThrottlingConfigFieldProps,
|
||||
} from '../fields/throttling/throttling_config_field';
|
||||
import { SourceField, SourceFieldProps } from '../fields/source_field';
|
||||
import {
|
||||
FormattedComboBox as DefaultFormattedComboBox,
|
||||
|
@ -132,3 +136,7 @@ export const RequestBodyField = React.forwardRef<unknown, DefaultRequestBodyFiel
|
|||
export const ResponseBodyIndexField = React.forwardRef<unknown, DefaultResponseBodyIndexFieldProps>(
|
||||
(props, _ref) => <DefaultResponseBodyIndexField {...props} />
|
||||
);
|
||||
|
||||
export const ThrottlingWrapper = React.forwardRef<unknown, ThrottlingConfigFieldProps>(
|
||||
(props, _ref) => <ThrottlingConfigField {...props} />
|
||||
);
|
||||
|
|
|
@ -121,6 +121,7 @@ export const BROWSER_ADVANCED = (readOnly: boolean) => [
|
|||
}
|
||||
),
|
||||
components: [
|
||||
FIELD(readOnly)[ConfigKey.THROTTLING_CONFIG],
|
||||
FIELD(readOnly)[ConfigKey.IGNORE_HTTPS_ERRORS],
|
||||
FIELD(readOnly)[ConfigKey.SYNTHETICS_ARGS],
|
||||
FIELD(readOnly)[ConfigKey.PLAYWRIGHT_OPTIONS],
|
||||
|
@ -209,7 +210,6 @@ export const FORM_CONFIG = (readOnly: boolean): FieldConfig => ({
|
|||
FIELD(readOnly)[ConfigKey.NAME],
|
||||
FIELD(readOnly)[ConfigKey.LOCATIONS],
|
||||
FIELD(readOnly)[`${ConfigKey.SCHEDULE}.number`],
|
||||
FIELD(readOnly)[ConfigKey.THROTTLING_CONFIG],
|
||||
FIELD(readOnly)[ConfigKey.ENABLED],
|
||||
FIELD(readOnly)[AlertConfigKey.STATUS_ENABLED],
|
||||
],
|
||||
|
@ -236,7 +236,6 @@ export const FORM_CONFIG = (readOnly: boolean): FieldConfig => ({
|
|||
FIELD(readOnly)[ConfigKey.TEXT_ASSERTION],
|
||||
FIELD(readOnly)[ConfigKey.LOCATIONS],
|
||||
FIELD(readOnly)[`${ConfigKey.SCHEDULE}.number`],
|
||||
FIELD(readOnly)[ConfigKey.THROTTLING_CONFIG],
|
||||
FIELD(readOnly)[ConfigKey.ENABLED],
|
||||
FIELD(readOnly)[AlertConfigKey.STATUS_ENABLED],
|
||||
],
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
|
||||
import { format, ALLOWED_FIELDS } from './formatter';
|
||||
import { DataStream } from '../../../../../../common/runtime_types';
|
||||
import { DEFAULT_FIELDS } from '../../../../../../common/constants/monitor_defaults';
|
||||
import {
|
||||
DEFAULT_FIELDS,
|
||||
PROFILE_VALUES_ENUM,
|
||||
PROFILES_MAP,
|
||||
} from '../../../../../../common/constants/monitor_defaults';
|
||||
|
||||
describe('format', () => {
|
||||
let formValues: Record<string, unknown>;
|
||||
|
@ -199,11 +203,6 @@ describe('format', () => {
|
|||
'filter_journeys.match': '',
|
||||
'filter_journeys.tags': [],
|
||||
ignore_https_errors: false,
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.upload_speed': '3',
|
||||
'throttling.latency': '20',
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'ssl.certificate_authorities': '',
|
||||
'ssl.certificate': '',
|
||||
'ssl.key': '',
|
||||
|
@ -215,9 +214,7 @@ describe('format', () => {
|
|||
script: '',
|
||||
fileName: '',
|
||||
},
|
||||
throttling: {
|
||||
config: '5d/3u/20l',
|
||||
},
|
||||
throttling: PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT],
|
||||
source: {
|
||||
inline: {
|
||||
type: scriptType,
|
||||
|
@ -278,11 +275,6 @@ describe('format', () => {
|
|||
'ssl.verification_mode': 'full',
|
||||
synthetics_args: [],
|
||||
tags: [],
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '3',
|
||||
timeout: '16',
|
||||
type: 'browser',
|
||||
'url.port': null,
|
||||
|
|
|
@ -148,11 +148,15 @@ const validateThrottleValue = (speed: string | undefined, allowZero?: boolean) =
|
|||
const validateBrowser: ValidationLibrary = {
|
||||
...validateCommon,
|
||||
[ConfigKey.SOURCE_INLINE]: ({ [ConfigKey.SOURCE_INLINE]: inlineScript }) => !inlineScript,
|
||||
[ConfigKey.DOWNLOAD_SPEED]: ({ [ConfigKey.DOWNLOAD_SPEED]: downloadSpeed }) =>
|
||||
validateThrottleValue(downloadSpeed),
|
||||
[ConfigKey.UPLOAD_SPEED]: ({ [ConfigKey.UPLOAD_SPEED]: uploadSpeed }) =>
|
||||
validateThrottleValue(uploadSpeed),
|
||||
[ConfigKey.LATENCY]: ({ [ConfigKey.LATENCY]: latency }) => validateThrottleValue(latency, true),
|
||||
[ConfigKey.THROTTLING_CONFIG]: ({ throttling }) => {
|
||||
if (!throttling || throttling.value === null) return true;
|
||||
const { download, upload, latency } = throttling.value;
|
||||
return (
|
||||
validateThrottleValue(String(download)) ||
|
||||
validateThrottleValue(String(upload)) ||
|
||||
validateThrottleValue(String(latency), true)
|
||||
);
|
||||
},
|
||||
[ConfigKey.PLAYWRIGHT_OPTIONS]: ({ [ConfigKey.PLAYWRIGHT_OPTIONS]: playwrightOptions }) =>
|
||||
playwrightOptions ? !validJSONFormat(playwrightOptions) : false,
|
||||
[ConfigKey.PARAMS]: ({ [ConfigKey.PARAMS]: params }) =>
|
||||
|
|
|
@ -12,6 +12,10 @@ import { MonitorEditPage } from './monitor_edit_page';
|
|||
import { ConfigKey } from '../../../../../common/runtime_types';
|
||||
|
||||
import * as observabilityPublic from '@kbn/observability-plugin/public';
|
||||
import {
|
||||
PROFILE_VALUES_ENUM,
|
||||
PROFILES_MAP,
|
||||
} from '../../../../../common/constants/monitor_defaults';
|
||||
|
||||
mockGlobals();
|
||||
|
||||
|
@ -45,6 +49,7 @@ describe('MonitorEditPage', () => {
|
|||
[ConfigKey.MONITOR_SOURCE_TYPE]: 'ui',
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: 'multistep',
|
||||
[ConfigKey.LOCATIONS]: [],
|
||||
[ConfigKey.THROTTLING_CONFIG]: PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT],
|
||||
},
|
||||
},
|
||||
refetch: () => null,
|
||||
|
|
|
@ -430,11 +430,15 @@ function getMonitorDetailsMockSlice() {
|
|||
'filter_journeys.match': '',
|
||||
'filter_journeys.tags': [],
|
||||
ignore_https_errors: false,
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.upload_speed': '3',
|
||||
'throttling.latency': '20',
|
||||
'throttling.config': '5d/3u/20l',
|
||||
throttling: {
|
||||
value: {
|
||||
download: '5',
|
||||
upload: '3',
|
||||
latency: '20',
|
||||
},
|
||||
label: 'Regular 3G',
|
||||
id: 'three_g',
|
||||
},
|
||||
'ssl.certificate_authorities': '',
|
||||
'ssl.certificate': '',
|
||||
'ssl.key': '',
|
||||
|
|
|
@ -8,7 +8,11 @@ import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/s
|
|||
import { migration880 } from './8.8.0';
|
||||
import { migrationMocks } from '@kbn/core/server/mocks';
|
||||
import { ConfigKey, ScheduleUnit } from '../../../../../../common/runtime_types';
|
||||
import { ALLOWED_SCHEDULES_IN_MINUTES } from '../../../../../../common/constants/monitor_defaults';
|
||||
import {
|
||||
ALLOWED_SCHEDULES_IN_MINUTES,
|
||||
PROFILE_VALUES_ENUM,
|
||||
PROFILES_MAP,
|
||||
} from '../../../../../../common/constants/monitor_defaults';
|
||||
import {
|
||||
browserUI,
|
||||
browserProject,
|
||||
|
@ -18,6 +22,8 @@ import {
|
|||
httpUptimeUI,
|
||||
} from './test_fixtures/8.7.0';
|
||||
import { httpUI as httpUI850 } from './test_fixtures/8.5.0';
|
||||
import { LegacyConfigKey } from '../../../../../../common/constants/monitor_management';
|
||||
import { omit } from 'lodash';
|
||||
|
||||
const context = migrationMocks.createContext();
|
||||
const encryptedSavedObjectsSetup = encryptedSavedObjectsMock.createSetup();
|
||||
|
@ -151,11 +157,7 @@ describe('Monitor migrations v8.7.0 -> v8.8.0', () => {
|
|||
'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'],
|
||||
'ssl.verification_mode': 'full',
|
||||
tags: [],
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '3',
|
||||
throttling: PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT],
|
||||
timeout: null,
|
||||
type: 'browser',
|
||||
'url.port': null,
|
||||
|
@ -195,9 +197,24 @@ describe('Monitor migrations v8.7.0 -> v8.8.0', () => {
|
|||
name: null,
|
||||
},
|
||||
};
|
||||
// @ts-ignore specificially testing monitors with invalid values
|
||||
// @ts-ignore specifically testing monitors with invalid values
|
||||
const actual = migration880(encryptedSavedObjectsSetup)(invalidTestMonitor, context);
|
||||
expect(actual).toEqual(invalidTestMonitor);
|
||||
expect(actual).toEqual({
|
||||
...invalidTestMonitor,
|
||||
attributes: omit(
|
||||
{
|
||||
...invalidTestMonitor.attributes,
|
||||
throttling: PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT],
|
||||
},
|
||||
[
|
||||
LegacyConfigKey.THROTTLING_CONFIG,
|
||||
LegacyConfigKey.IS_THROTTLING_ENABLED,
|
||||
LegacyConfigKey.DOWNLOAD_SPEED,
|
||||
LegacyConfigKey.UPLOAD_SPEED,
|
||||
LegacyConfigKey.LATENCY,
|
||||
]
|
||||
),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -413,4 +430,77 @@ describe('Monitor migrations v8.7.0 -> v8.8.0', () => {
|
|||
expect(actual.attributes[ConfigKey.SCHEDULE].unit).toEqual(ScheduleUnit.MINUTES);
|
||||
});
|
||||
});
|
||||
|
||||
describe('throttling migration', () => {
|
||||
it('handles migrating with enabled throttling', () => {
|
||||
const actual = migration880(encryptedSavedObjectsSetup)(browserUI, context);
|
||||
// @ts-ignore
|
||||
expect(actual.attributes[ConfigKey.THROTTLING_CONFIG]).toEqual(
|
||||
PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT]
|
||||
);
|
||||
});
|
||||
|
||||
it('handles migrating with defined throttling value', () => {
|
||||
const testMonitor = {
|
||||
...browserUI,
|
||||
attributes: {
|
||||
...browserUI.attributes,
|
||||
[LegacyConfigKey.UPLOAD_SPEED]: '0.75',
|
||||
[LegacyConfigKey.DOWNLOAD_SPEED]: '9',
|
||||
[LegacyConfigKey.LATENCY]: '170',
|
||||
},
|
||||
};
|
||||
const actual = migration880(encryptedSavedObjectsSetup)(testMonitor, context);
|
||||
// @ts-ignore
|
||||
expect(actual.attributes[ConfigKey.THROTTLING_CONFIG]).toEqual({
|
||||
id: '4g',
|
||||
label: '4G',
|
||||
value: {
|
||||
download: '9',
|
||||
upload: '0.75',
|
||||
latency: '170',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('handles migrating with custom throttling value', () => {
|
||||
const testMonitor = {
|
||||
...browserUI,
|
||||
attributes: {
|
||||
...browserUI.attributes,
|
||||
[LegacyConfigKey.UPLOAD_SPEED]: '5',
|
||||
[LegacyConfigKey.DOWNLOAD_SPEED]: '10',
|
||||
[LegacyConfigKey.LATENCY]: '30',
|
||||
},
|
||||
};
|
||||
const actual = migration880(encryptedSavedObjectsSetup)(testMonitor, context);
|
||||
// @ts-ignore
|
||||
expect(actual.attributes[ConfigKey.THROTTLING_CONFIG]).toEqual({
|
||||
id: 'custom',
|
||||
label: 'Custom',
|
||||
value: {
|
||||
download: '10',
|
||||
upload: '5',
|
||||
latency: '30',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('handles migrating with disabled throttling', () => {
|
||||
const testMonitor = {
|
||||
...browserUI,
|
||||
attributes: {
|
||||
...browserUI.attributes,
|
||||
[LegacyConfigKey.IS_THROTTLING_ENABLED]: false,
|
||||
},
|
||||
};
|
||||
const actual = migration880(encryptedSavedObjectsSetup)(testMonitor, context);
|
||||
// @ts-ignore
|
||||
expect(actual.attributes[ConfigKey.THROTTLING_CONFIG]).toEqual({
|
||||
id: 'no-throttling',
|
||||
label: 'No throttling',
|
||||
value: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,23 +6,31 @@
|
|||
*/
|
||||
import { omit } from 'lodash';
|
||||
import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server';
|
||||
import { SavedObjectUnsanitizedDoc } from '@kbn/core/server';
|
||||
import { SavedObjectMigrationContext, SavedObjectUnsanitizedDoc } from '@kbn/core/server';
|
||||
import { LegacyConfigKey } from '../../../../../../common/constants/monitor_management';
|
||||
import {
|
||||
ConfigKey,
|
||||
SyntheticsMonitorWithSecrets,
|
||||
MonitorFields,
|
||||
BrowserFields,
|
||||
ConfigKey,
|
||||
MonitorFields,
|
||||
ScheduleUnit,
|
||||
SyntheticsMonitorWithSecrets,
|
||||
ThrottlingConfig,
|
||||
} from '../../../../../../common/runtime_types';
|
||||
import { ALLOWED_SCHEDULES_IN_MINUTES } from '../../../../../../common/constants/monitor_defaults';
|
||||
import {
|
||||
ALLOWED_SCHEDULES_IN_MINUTES,
|
||||
CUSTOM_LABEL,
|
||||
PROFILE_VALUES,
|
||||
PROFILE_VALUES_ENUM,
|
||||
PROFILES_MAP,
|
||||
} from '../../../../../../common/constants/monitor_defaults';
|
||||
import {
|
||||
LEGACY_SYNTHETICS_MONITOR_ENCRYPTED_TYPE,
|
||||
SYNTHETICS_MONITOR_ENCRYPTED_TYPE,
|
||||
} from '../../synthetics_monitor';
|
||||
import { validateMonitor } from '../../../../../routes/monitor_cruds/monitor_validation';
|
||||
import {
|
||||
normalizeMonitorSecretAttributes,
|
||||
formatSecrets,
|
||||
normalizeMonitorSecretAttributes,
|
||||
} from '../../../../../synthetics_service/utils/secrets';
|
||||
|
||||
export const migration880 = (encryptedSavedObjects: EncryptedSavedObjectsPluginSetup) => {
|
||||
|
@ -61,6 +69,8 @@ export const migration880 = (encryptedSavedObjects: EncryptedSavedObjectsPluginS
|
|||
},
|
||||
};
|
||||
if (migrated.attributes.type === 'browser') {
|
||||
migrated = updateThrottlingFields(migrated, logger);
|
||||
|
||||
try {
|
||||
const normalizedMonitorAttributes = normalizeMonitorSecretAttributes(migrated.attributes);
|
||||
migrated = {
|
||||
|
@ -118,3 +128,103 @@ const omitZipUrlFields = (fields: BrowserFields) => {
|
|||
|
||||
return formatSecrets(validationResult.decodedMonitor);
|
||||
};
|
||||
|
||||
const updateThrottlingFields = (
|
||||
doc: SavedObjectUnsanitizedDoc<
|
||||
SyntheticsMonitorWithSecrets &
|
||||
Partial<{
|
||||
[LegacyConfigKey.THROTTLING_CONFIG]: string;
|
||||
[LegacyConfigKey.IS_THROTTLING_ENABLED]: boolean;
|
||||
[LegacyConfigKey.DOWNLOAD_SPEED]: string;
|
||||
[LegacyConfigKey.UPLOAD_SPEED]: string;
|
||||
[LegacyConfigKey.LATENCY]: string;
|
||||
[ConfigKey.THROTTLING_CONFIG]: ThrottlingConfig;
|
||||
}>
|
||||
>,
|
||||
logger: SavedObjectMigrationContext
|
||||
) => {
|
||||
try {
|
||||
const { attributes } = doc;
|
||||
|
||||
const migrated = {
|
||||
...doc,
|
||||
attributes: {
|
||||
...doc.attributes,
|
||||
[ConfigKey.CONFIG_HASH]: '',
|
||||
},
|
||||
};
|
||||
|
||||
const isThrottlingEnabled = attributes[LegacyConfigKey.IS_THROTTLING_ENABLED];
|
||||
if (isThrottlingEnabled) {
|
||||
const defaultProfileValue = PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT].value!;
|
||||
|
||||
const download =
|
||||
String(attributes[LegacyConfigKey.DOWNLOAD_SPEED]) || defaultProfileValue.download;
|
||||
const upload = String(attributes[LegacyConfigKey.UPLOAD_SPEED]) || defaultProfileValue.upload;
|
||||
const latency = String(attributes[LegacyConfigKey.LATENCY]) || defaultProfileValue.latency;
|
||||
|
||||
migrated.attributes[ConfigKey.THROTTLING_CONFIG] = getMatchingThrottlingConfig(
|
||||
download,
|
||||
upload,
|
||||
latency
|
||||
);
|
||||
} else {
|
||||
migrated.attributes[ConfigKey.THROTTLING_CONFIG] =
|
||||
PROFILES_MAP[PROFILE_VALUES_ENUM.NO_THROTTLING];
|
||||
}
|
||||
|
||||
// filter out legacy throttling fields
|
||||
return {
|
||||
...migrated,
|
||||
attributes: omit(migrated.attributes, [
|
||||
LegacyConfigKey.THROTTLING_CONFIG,
|
||||
LegacyConfigKey.IS_THROTTLING_ENABLED,
|
||||
LegacyConfigKey.DOWNLOAD_SPEED,
|
||||
LegacyConfigKey.UPLOAD_SPEED,
|
||||
LegacyConfigKey.LATENCY,
|
||||
]),
|
||||
};
|
||||
} catch (e) {
|
||||
logger.log.warn(
|
||||
`Failed to migrate throttling fields from legacy Synthetics monitor: ${e.message}`
|
||||
);
|
||||
const { attributes } = doc;
|
||||
|
||||
attributes[ConfigKey.THROTTLING_CONFIG] = PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT];
|
||||
|
||||
return {
|
||||
...doc,
|
||||
attributes: omit(attributes, [
|
||||
LegacyConfigKey.THROTTLING_CONFIG,
|
||||
LegacyConfigKey.IS_THROTTLING_ENABLED,
|
||||
LegacyConfigKey.DOWNLOAD_SPEED,
|
||||
LegacyConfigKey.UPLOAD_SPEED,
|
||||
LegacyConfigKey.LATENCY,
|
||||
]),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const getMatchingThrottlingConfig = (download: string, upload: string, latency: string) => {
|
||||
const matchedProfile = PROFILE_VALUES.find(({ value }) => {
|
||||
return (
|
||||
Number(value?.download) === Number(download) &&
|
||||
Number(value?.upload) === Number(upload) &&
|
||||
Number(value?.latency) === Number(latency)
|
||||
);
|
||||
});
|
||||
|
||||
if (matchedProfile) {
|
||||
return matchedProfile;
|
||||
} else {
|
||||
return {
|
||||
id: PROFILE_VALUES_ENUM.CUSTOM,
|
||||
label: CUSTOM_LABEL,
|
||||
value: {
|
||||
download: String(download),
|
||||
upload: String(upload),
|
||||
latency: String(latency),
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -170,6 +170,13 @@ export const getSyntheticsMonitorSavedObjectType = (
|
|||
},
|
||||
},
|
||||
},
|
||||
throttling: {
|
||||
properties: {
|
||||
label: {
|
||||
type: 'keyword',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
management: {
|
||||
|
|
|
@ -78,7 +78,7 @@ export const addSyntheticsProjectMonitorRoute: SyntheticsRestApiRouteFactory = (
|
|||
};
|
||||
} catch (error) {
|
||||
server.logger.error(`Error adding monitors to project ${decodedProjectName}`);
|
||||
if (error.output.statusCode === 404) {
|
||||
if (error.output?.statusCode === 404) {
|
||||
const spaceId = server.spaces?.spacesService.getSpaceId(request) ?? DEFAULT_SPACE_ID;
|
||||
return response.notFound({ body: { message: `Kibana space '${spaceId}' does not exist` } });
|
||||
}
|
||||
|
|
|
@ -175,11 +175,15 @@ describe('validateMonitor', () => {
|
|||
[ConfigKey.JOURNEY_FILTERS_MATCH]: 'false',
|
||||
[ConfigKey.JOURNEY_FILTERS_TAGS]: testTags,
|
||||
[ConfigKey.IGNORE_HTTPS_ERRORS]: false,
|
||||
[ConfigKey.IS_THROTTLING_ENABLED]: true,
|
||||
[ConfigKey.DOWNLOAD_SPEED]: '5',
|
||||
[ConfigKey.UPLOAD_SPEED]: '3',
|
||||
[ConfigKey.LATENCY]: '20',
|
||||
[ConfigKey.THROTTLING_CONFIG]: '5d/3u/20l',
|
||||
[ConfigKey.THROTTLING_CONFIG]: {
|
||||
value: {
|
||||
download: '5',
|
||||
upload: '3',
|
||||
latency: '20',
|
||||
},
|
||||
id: 'test',
|
||||
label: 'test',
|
||||
},
|
||||
};
|
||||
|
||||
testBrowserFields = {
|
||||
|
|
|
@ -15,21 +15,21 @@ import { arrayFormatter, objectFormatter, stringToObjectFormatter } from './form
|
|||
export type BrowserFormatMap = Record<keyof BrowserFields, Formatter>;
|
||||
|
||||
const throttlingFormatter: Formatter = (fields) => {
|
||||
if (!fields[ConfigKey.IS_THROTTLING_ENABLED]) return false;
|
||||
const value = fields[ConfigKey.THROTTLING_CONFIG];
|
||||
const defaultThrottling = DEFAULT_BROWSER_ADVANCED_FIELDS[ConfigKey.THROTTLING_CONFIG].value;
|
||||
|
||||
const thValue = value?.value;
|
||||
|
||||
if (!thValue || !defaultThrottling) return false;
|
||||
|
||||
if (thValue?.download === '0' && thValue?.upload === '0' && thValue?.latency === '0')
|
||||
return false;
|
||||
if (value?.label === 'no-throttling') return false;
|
||||
|
||||
return {
|
||||
download: parseInt(
|
||||
fields[ConfigKey.DOWNLOAD_SPEED] || DEFAULT_BROWSER_ADVANCED_FIELDS[ConfigKey.DOWNLOAD_SPEED],
|
||||
10
|
||||
),
|
||||
upload: parseInt(
|
||||
fields[ConfigKey.UPLOAD_SPEED] || DEFAULT_BROWSER_ADVANCED_FIELDS[ConfigKey.UPLOAD_SPEED],
|
||||
10
|
||||
),
|
||||
latency: parseInt(
|
||||
fields[ConfigKey.LATENCY] || DEFAULT_BROWSER_ADVANCED_FIELDS[ConfigKey.LATENCY],
|
||||
10
|
||||
),
|
||||
download: Number(thValue?.download ?? defaultThrottling.download),
|
||||
upload: Number(thValue?.upload ?? defaultThrottling.upload),
|
||||
latency: Number(thValue?.latency ?? defaultThrottling.latency),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -73,11 +73,15 @@ const testBrowserConfig: Partial<MonitorFields> = {
|
|||
'filter_journeys.match': '',
|
||||
'filter_journeys.tags': ['dev'],
|
||||
ignore_https_errors: false,
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.upload_speed': '3',
|
||||
'throttling.latency': '20',
|
||||
'throttling.config': '5d/3u/20l',
|
||||
throttling: {
|
||||
value: {
|
||||
download: '5',
|
||||
latency: '20',
|
||||
upload: '3',
|
||||
},
|
||||
id: 'default',
|
||||
label: 'default',
|
||||
},
|
||||
project_id: 'test-project',
|
||||
};
|
||||
|
||||
|
@ -203,12 +207,16 @@ describe('browser fields', () => {
|
|||
});
|
||||
|
||||
it('excludes UI fields', () => {
|
||||
testBrowserConfig['throttling.is_enabled'] = false;
|
||||
testBrowserConfig['throttling.upload_speed'] = '3';
|
||||
|
||||
const formattedConfig = formatMonitorConfigFields(
|
||||
Object.keys(testBrowserConfig) as ConfigKey[],
|
||||
testBrowserConfig,
|
||||
{
|
||||
...testBrowserConfig,
|
||||
throttling: {
|
||||
value: null,
|
||||
label: 'no-throttling',
|
||||
id: 'no-throttling',
|
||||
},
|
||||
},
|
||||
logger,
|
||||
{ proxyUrl: 'https://www.google.com' }
|
||||
);
|
||||
|
@ -216,8 +224,6 @@ describe('browser fields', () => {
|
|||
const expected = {
|
||||
...formattedConfig,
|
||||
throttling: false,
|
||||
'throttling.is_enabled': undefined,
|
||||
'throttling.upload_speed': undefined,
|
||||
};
|
||||
|
||||
expect(formattedConfig).toEqual(expected);
|
||||
|
|
|
@ -23,10 +23,6 @@ const UI_KEYS_TO_SKIP = [
|
|||
ConfigKey.JOURNEY_ID,
|
||||
ConfigKey.PROJECT_ID,
|
||||
ConfigKey.METADATA,
|
||||
ConfigKey.UPLOAD_SPEED,
|
||||
ConfigKey.DOWNLOAD_SPEED,
|
||||
ConfigKey.LATENCY,
|
||||
ConfigKey.IS_THROTTLING_ENABLED,
|
||||
ConfigKey.REVISION,
|
||||
ConfigKey.CUSTOM_HEARTBEAT_ID,
|
||||
ConfigKey.FORM_MONITOR_TYPE,
|
||||
|
@ -36,19 +32,13 @@ const UI_KEYS_TO_SKIP = [
|
|||
'secrets',
|
||||
];
|
||||
|
||||
const uiToHeartbeatKeyMap = {
|
||||
throttling: ConfigKey.THROTTLING_CONFIG,
|
||||
};
|
||||
|
||||
type YamlKeys = keyof typeof uiToHeartbeatKeyMap;
|
||||
|
||||
export const formatMonitorConfigFields = (
|
||||
configKeys: ConfigKey[],
|
||||
config: Partial<MonitorFields>,
|
||||
logger: Logger,
|
||||
params: Record<string, string>
|
||||
) => {
|
||||
const formattedMonitor = {} as Record<ConfigKey | YamlKeys, any>;
|
||||
const formattedMonitor = {} as Record<ConfigKey, any>;
|
||||
|
||||
configKeys.forEach((key) => {
|
||||
if (!UI_KEYS_TO_SKIP.includes(key)) {
|
||||
|
@ -85,13 +75,6 @@ export const formatMonitorConfigFields = (
|
|||
sslKeys.forEach((key) => (formattedMonitor[key] = null));
|
||||
}
|
||||
|
||||
Object.keys(uiToHeartbeatKeyMap).forEach((key) => {
|
||||
const hbKey = key as YamlKeys;
|
||||
const configKey = uiToHeartbeatKeyMap[hbKey];
|
||||
formattedMonitor[hbKey] = formattedMonitor[configKey];
|
||||
delete formattedMonitor[configKey];
|
||||
});
|
||||
|
||||
return omitBy(formattedMonitor, isNil) as Partial<MonitorFields>;
|
||||
};
|
||||
|
||||
|
|
|
@ -311,11 +311,7 @@ const dummyBrowserConfig: Partial<MonitorFields> & {
|
|||
'filter_journeys.match': '',
|
||||
'filter_journeys.tags': [],
|
||||
ignore_https_errors: false,
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.upload_speed': '3',
|
||||
'throttling.latency': '20',
|
||||
'throttling.config': '5d/3u/20l',
|
||||
throttling: { value: { download: '5', upload: '3', latency: '20' }, label: 'test', id: 'test' },
|
||||
id: '75cdd125-5b62-4459-870c-46f59bf37e89',
|
||||
config_id: '75cdd125-5b62-4459-870c-46f59bf37e89',
|
||||
fields: { config_id: '75cdd125-5b62-4459-870c-46f59bf37e89', run_once: true },
|
||||
|
|
|
@ -13,7 +13,11 @@ import {
|
|||
ProjectMonitor,
|
||||
PrivateLocation,
|
||||
} from '../../../../common/runtime_types';
|
||||
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
|
||||
import {
|
||||
DEFAULT_FIELDS,
|
||||
PROFILE_VALUES_ENUM,
|
||||
PROFILES_MAP,
|
||||
} from '../../../../common/constants/monitor_defaults';
|
||||
import { normalizeProjectMonitors } from '.';
|
||||
|
||||
describe('browser normalizers', () => {
|
||||
|
@ -143,11 +147,6 @@ describe('browser normalizers', () => {
|
|||
'service.name': '',
|
||||
'source.project.content': 'test content 1',
|
||||
tags: ['tag1', 'tag2'],
|
||||
'throttling.config': '5d/10u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '10',
|
||||
params: '',
|
||||
type: 'browser',
|
||||
project_id: projectId,
|
||||
|
@ -157,6 +156,15 @@ describe('browser normalizers', () => {
|
|||
timeout: null,
|
||||
id: '',
|
||||
hash: testHash,
|
||||
throttling: {
|
||||
id: 'custom',
|
||||
label: 'Custom',
|
||||
value: {
|
||||
download: '5',
|
||||
latency: '20',
|
||||
upload: '10',
|
||||
},
|
||||
},
|
||||
},
|
||||
unsupportedKeys: [],
|
||||
errors: [],
|
||||
|
@ -198,11 +206,6 @@ describe('browser normalizers', () => {
|
|||
'service.name': '',
|
||||
'source.project.content': 'test content 2',
|
||||
tags: ['tag3', 'tag4'],
|
||||
'throttling.config': '10d/15u/18l',
|
||||
'throttling.download_speed': '10',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '18',
|
||||
'throttling.upload_speed': '15',
|
||||
type: 'browser',
|
||||
project_id: projectId,
|
||||
namespace: 'test_space',
|
||||
|
@ -211,6 +214,15 @@ describe('browser normalizers', () => {
|
|||
timeout: null,
|
||||
id: '',
|
||||
hash: testHash,
|
||||
throttling: {
|
||||
id: 'custom',
|
||||
label: 'Custom',
|
||||
value: {
|
||||
download: '10',
|
||||
latency: '18',
|
||||
upload: '15',
|
||||
},
|
||||
},
|
||||
},
|
||||
unsupportedKeys: [],
|
||||
errors: [],
|
||||
|
@ -257,11 +269,6 @@ describe('browser normalizers', () => {
|
|||
'service.name': '',
|
||||
'source.project.content': 'test content 3',
|
||||
tags: ['tag3', 'tag4'],
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': false,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '3',
|
||||
type: 'browser',
|
||||
project_id: projectId,
|
||||
namespace: 'test_space',
|
||||
|
@ -270,6 +277,147 @@ describe('browser normalizers', () => {
|
|||
timeout: null,
|
||||
id: '',
|
||||
hash: testHash,
|
||||
throttling: PROFILES_MAP[PROFILE_VALUES_ENUM.NO_THROTTLING],
|
||||
},
|
||||
unsupportedKeys: [],
|
||||
errors: [],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('handles defined throttling values', () => {
|
||||
const actual = normalizeProjectMonitors({
|
||||
locations,
|
||||
privateLocations,
|
||||
monitors: [
|
||||
{
|
||||
...monitors[0],
|
||||
throttling: {
|
||||
download: 9,
|
||||
upload: 0.75,
|
||||
latency: 170,
|
||||
},
|
||||
},
|
||||
],
|
||||
projectId,
|
||||
namespace: 'test-space',
|
||||
version: '8.5.0',
|
||||
});
|
||||
expect(actual).toEqual([
|
||||
{
|
||||
normalizedFields: {
|
||||
...DEFAULT_FIELDS[DataStream.BROWSER],
|
||||
journey_id: 'test-id-1',
|
||||
ignore_https_errors: true,
|
||||
origin: 'project',
|
||||
locations: [
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_central',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
},
|
||||
],
|
||||
name: 'test-name-1',
|
||||
schedule: {
|
||||
number: '3',
|
||||
unit: 'm',
|
||||
},
|
||||
screenshots: 'off',
|
||||
'service.name': '',
|
||||
'source.project.content': 'test content 1',
|
||||
tags: ['tag1', 'tag2'],
|
||||
params: '',
|
||||
type: 'browser',
|
||||
project_id: projectId,
|
||||
namespace: 'test_space',
|
||||
original_space: 'test-space',
|
||||
custom_heartbeat_id: 'test-id-1-test-project-id-test-space',
|
||||
timeout: null,
|
||||
id: '',
|
||||
hash: testHash,
|
||||
throttling: {
|
||||
id: '4g',
|
||||
label: '4G',
|
||||
value: {
|
||||
download: '9',
|
||||
latency: '170',
|
||||
upload: '0.75',
|
||||
},
|
||||
},
|
||||
},
|
||||
unsupportedKeys: [],
|
||||
errors: [],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('handles custom throttling values', () => {
|
||||
const actual = normalizeProjectMonitors({
|
||||
locations,
|
||||
privateLocations,
|
||||
monitors: [
|
||||
{
|
||||
...monitors[0],
|
||||
throttling: {
|
||||
download: 10,
|
||||
upload: 5,
|
||||
latency: 30,
|
||||
},
|
||||
},
|
||||
],
|
||||
projectId,
|
||||
namespace: 'test-space',
|
||||
version: '8.5.0',
|
||||
});
|
||||
expect(actual).toEqual([
|
||||
{
|
||||
normalizedFields: {
|
||||
...DEFAULT_FIELDS[DataStream.BROWSER],
|
||||
journey_id: 'test-id-1',
|
||||
ignore_https_errors: true,
|
||||
origin: 'project',
|
||||
locations: [
|
||||
{
|
||||
geo: {
|
||||
lat: 33.333,
|
||||
lon: 73.333,
|
||||
},
|
||||
id: 'us_central',
|
||||
isServiceManaged: true,
|
||||
label: 'Test Location',
|
||||
},
|
||||
],
|
||||
name: 'test-name-1',
|
||||
schedule: {
|
||||
number: '3',
|
||||
unit: 'm',
|
||||
},
|
||||
screenshots: 'off',
|
||||
'service.name': '',
|
||||
'source.project.content': 'test content 1',
|
||||
tags: ['tag1', 'tag2'],
|
||||
params: '',
|
||||
type: 'browser',
|
||||
project_id: projectId,
|
||||
namespace: 'test_space',
|
||||
original_space: 'test-space',
|
||||
custom_heartbeat_id: 'test-id-1-test-project-id-test-space',
|
||||
timeout: null,
|
||||
id: '',
|
||||
hash: testHash,
|
||||
throttling: {
|
||||
id: 'custom',
|
||||
label: 'Custom',
|
||||
value: {
|
||||
download: '10',
|
||||
latency: '30',
|
||||
upload: '5',
|
||||
},
|
||||
},
|
||||
},
|
||||
unsupportedKeys: [],
|
||||
errors: [],
|
||||
|
|
|
@ -10,8 +10,16 @@ import {
|
|||
ConfigKey,
|
||||
DataStream,
|
||||
FormMonitorType,
|
||||
ProjectMonitor,
|
||||
ThrottlingConfig,
|
||||
} from '../../../../common/runtime_types';
|
||||
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
|
||||
import {
|
||||
PROFILE_VALUES_ENUM,
|
||||
DEFAULT_FIELDS,
|
||||
PROFILES_MAP,
|
||||
PROFILE_VALUES,
|
||||
CUSTOM_LABEL,
|
||||
} from '../../../../common/constants/monitor_defaults';
|
||||
import {
|
||||
NormalizedProjectProps,
|
||||
NormalizerResult,
|
||||
|
@ -38,33 +46,15 @@ export const getNormalizeBrowserFields = ({
|
|||
version,
|
||||
});
|
||||
|
||||
const throttling = normalizeThrottling(monitor.throttling);
|
||||
|
||||
const normalizedFields = {
|
||||
...commonFields,
|
||||
[ConfigKey.MONITOR_TYPE]: DataStream.BROWSER,
|
||||
[ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.MULTISTEP,
|
||||
[ConfigKey.SOURCE_PROJECT_CONTENT]:
|
||||
monitor.content || defaultFields[ConfigKey.SOURCE_PROJECT_CONTENT],
|
||||
[ConfigKey.THROTTLING_CONFIG]:
|
||||
typeof monitor.throttling !== 'boolean'
|
||||
? `${monitor.throttling?.download}d/${monitor.throttling?.upload}u/${monitor.throttling?.latency}l`
|
||||
: defaultFields[ConfigKey.THROTTLING_CONFIG],
|
||||
[ConfigKey.DOWNLOAD_SPEED]: `${
|
||||
typeof monitor.throttling !== 'boolean'
|
||||
? monitor.throttling?.download
|
||||
: defaultFields[ConfigKey.DOWNLOAD_SPEED]
|
||||
}`,
|
||||
[ConfigKey.UPLOAD_SPEED]: `${
|
||||
typeof monitor.throttling !== 'boolean'
|
||||
? monitor.throttling?.upload
|
||||
: defaultFields[ConfigKey.UPLOAD_SPEED]
|
||||
}`,
|
||||
[ConfigKey.IS_THROTTLING_ENABLED]:
|
||||
Boolean(monitor.throttling) ?? defaultFields[ConfigKey.IS_THROTTLING_ENABLED],
|
||||
[ConfigKey.LATENCY]: `${
|
||||
typeof monitor.throttling !== 'boolean'
|
||||
? monitor.throttling?.latency
|
||||
: defaultFields[ConfigKey.LATENCY]
|
||||
}`,
|
||||
[ConfigKey.THROTTLING_CONFIG]: throttling,
|
||||
[ConfigKey.IGNORE_HTTPS_ERRORS]:
|
||||
monitor.ignoreHTTPSErrors || defaultFields[ConfigKey.IGNORE_HTTPS_ERRORS],
|
||||
[ConfigKey.SCREENSHOTS]: monitor.screenshot || defaultFields[ConfigKey.SCREENSHOTS],
|
||||
|
@ -89,3 +79,40 @@ export const getNormalizeBrowserFields = ({
|
|||
errors,
|
||||
};
|
||||
};
|
||||
|
||||
export const normalizeThrottling = (
|
||||
monitorThrottling: ProjectMonitor['throttling']
|
||||
): ThrottlingConfig => {
|
||||
const defaultFields = DEFAULT_FIELDS[DataStream.BROWSER];
|
||||
|
||||
let throttling = defaultFields[ConfigKey.THROTTLING_CONFIG];
|
||||
if (typeof monitorThrottling === 'boolean' && !monitorThrottling) {
|
||||
throttling = PROFILES_MAP[PROFILE_VALUES_ENUM.NO_THROTTLING];
|
||||
}
|
||||
if (typeof monitorThrottling === 'object') {
|
||||
const { download, upload, latency } = monitorThrottling;
|
||||
const matchedProfile = PROFILE_VALUES.find(({ value }) => {
|
||||
return (
|
||||
Number(value?.download) === download &&
|
||||
Number(value?.upload) === upload &&
|
||||
Number(value?.latency) === latency
|
||||
);
|
||||
});
|
||||
|
||||
if (matchedProfile) {
|
||||
return matchedProfile;
|
||||
} else {
|
||||
return {
|
||||
id: PROFILE_VALUES_ENUM.CUSTOM,
|
||||
label: CUSTOM_LABEL,
|
||||
value: {
|
||||
download: String(download),
|
||||
upload: String(upload),
|
||||
latency: String(latency),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return throttling;
|
||||
};
|
||||
|
|
|
@ -485,11 +485,6 @@ const payloadData = [
|
|||
'ssl.verification_mode': 'full',
|
||||
synthetics_args: [],
|
||||
tags: [],
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '3',
|
||||
timeout: null,
|
||||
type: 'browser',
|
||||
'url.port': null,
|
||||
|
@ -540,11 +535,6 @@ const payloadData = [
|
|||
'ssl.verification_mode': 'full',
|
||||
synthetics_args: [],
|
||||
tags: [],
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '3',
|
||||
timeout: null,
|
||||
type: 'browser',
|
||||
'url.port': null,
|
||||
|
|
|
@ -554,11 +554,6 @@ const payloadData = [
|
|||
'ssl.verification_mode': 'full',
|
||||
synthetics_args: [],
|
||||
tags: [],
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '3',
|
||||
timeout: null,
|
||||
type: 'browser',
|
||||
'url.port': null,
|
||||
|
@ -609,11 +604,6 @@ const payloadData = [
|
|||
'ssl.verification_mode': 'full',
|
||||
synthetics_args: [],
|
||||
tags: [],
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '3',
|
||||
timeout: null,
|
||||
type: 'browser',
|
||||
'url.port': null,
|
||||
|
|
|
@ -34909,7 +34909,6 @@
|
|||
"xpack.synthetics.monitorConfig.textAssertion.label": "Assertion de texte",
|
||||
"xpack.synthetics.monitorConfig.throttling.helpText": "Simulez la régulation du réseau (téléchargement, chargement, latence). D'autres options seront ajoutées dans une prochaine version.",
|
||||
"xpack.synthetics.monitorConfig.throttling.label": "Profil de connexion",
|
||||
"xpack.synthetics.monitorConfig.throttling.options.default": "Par défaut",
|
||||
"xpack.synthetics.monitorConfig.timeout.formatError": "Le délai d'expiration n'est pas valide.",
|
||||
"xpack.synthetics.monitorConfig.timeout.greaterThan0Error": "Le délai d'expiration doit être supérieur ou égal à 0.",
|
||||
"xpack.synthetics.monitorConfig.timeout.helpText": "Temps total autorisé pour tester la connexion et l'échange de données.",
|
||||
|
|
|
@ -34888,7 +34888,6 @@
|
|||
"xpack.synthetics.monitorConfig.textAssertion.label": "テキストアサーション",
|
||||
"xpack.synthetics.monitorConfig.throttling.helpText": "ネットワークスロットリングをシミュレートします(ダウンロード、アップロード、レイテンシ)。今後のバージョンではその他のオプションが追加されます。",
|
||||
"xpack.synthetics.monitorConfig.throttling.label": "接続プロファイル",
|
||||
"xpack.synthetics.monitorConfig.throttling.options.default": "デフォルト",
|
||||
"xpack.synthetics.monitorConfig.timeout.formatError": "タイムアウトが無効です。",
|
||||
"xpack.synthetics.monitorConfig.timeout.greaterThan0Error": "タイムアウトは0以上でなければなりません。",
|
||||
"xpack.synthetics.monitorConfig.timeout.helpText": "接続のテストとデータの交換に許可された合計時間。",
|
||||
|
|
|
@ -34904,7 +34904,6 @@
|
|||
"xpack.synthetics.monitorConfig.textAssertion.label": "文本断言",
|
||||
"xpack.synthetics.monitorConfig.throttling.helpText": "模拟网络限制(下载、上传、延迟)。将在未来版本中添加更多选项。",
|
||||
"xpack.synthetics.monitorConfig.throttling.label": "连接配置文件",
|
||||
"xpack.synthetics.monitorConfig.throttling.options.default": "默认",
|
||||
"xpack.synthetics.monitorConfig.timeout.formatError": "超时无效。",
|
||||
"xpack.synthetics.monitorConfig.timeout.greaterThan0Error": "超时必须大于或等于 0。",
|
||||
"xpack.synthetics.monitorConfig.timeout.helpText": "允许用于测试连接并交换数据的总时间。",
|
||||
|
|
|
@ -12,6 +12,10 @@ import { formatKibanaNamespace } from '@kbn/synthetics-plugin/common/formatters'
|
|||
import { syntheticsMonitorType } from '@kbn/synthetics-plugin/server/legacy_uptime/lib/saved_objects/synthetics_monitor';
|
||||
import { REQUEST_TOO_LARGE } from '@kbn/synthetics-plugin/server/routes/monitor_cruds/add_monitor_project';
|
||||
import { PackagePolicy } from '@kbn/fleet-plugin/common';
|
||||
import {
|
||||
PROFILE_VALUES_ENUM,
|
||||
PROFILES_MAP,
|
||||
} from '@kbn/synthetics-plugin/common/constants/monitor_defaults';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { getFixtureJson } from '../uptime/rest/helper/get_fixture_json';
|
||||
import { PrivateLocationTestService } from './services/private_location_test_service';
|
||||
|
@ -190,11 +194,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
'service.name': '',
|
||||
synthetics_args: [],
|
||||
tags: [],
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '3',
|
||||
throttling: PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT],
|
||||
'ssl.certificate': '',
|
||||
'ssl.certificate_authorities': '',
|
||||
'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'],
|
||||
|
@ -253,7 +253,11 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
.set('kbn-xsrf', 'true')
|
||||
.expect(200);
|
||||
|
||||
expect(decryptedCreatedMonitor.body.attributes['throttling.is_enabled']).to.eql(false);
|
||||
expect(decryptedCreatedMonitor.body.attributes.throttling).to.eql({
|
||||
value: null,
|
||||
id: 'no-throttling',
|
||||
label: 'No throttling',
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
await Promise.all([
|
||||
|
|
|
@ -16,6 +16,10 @@ import { API_URLS } from '@kbn/synthetics-plugin/common/constants';
|
|||
import { formatKibanaNamespace } from '@kbn/synthetics-plugin/common/formatters';
|
||||
import { syntheticsMonitorType } from '@kbn/synthetics-plugin/server/legacy_uptime/lib/saved_objects/synthetics_monitor';
|
||||
import { PackagePolicy } from '@kbn/fleet-plugin/common';
|
||||
import {
|
||||
PROFILE_VALUES_ENUM,
|
||||
PROFILES_MAP,
|
||||
} from '@kbn/synthetics-plugin/common/constants/monitor_defaults';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { getFixtureJson } from '../uptime/rest/helper/get_fixture_json';
|
||||
import { PrivateLocationTestService } from './services/private_location_test_service';
|
||||
|
@ -175,11 +179,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
'service.name': '',
|
||||
synthetics_args: [],
|
||||
tags: [],
|
||||
'throttling.config': '5d/3u/20l',
|
||||
'throttling.download_speed': '5',
|
||||
'throttling.is_enabled': true,
|
||||
'throttling.latency': '20',
|
||||
'throttling.upload_speed': '3',
|
||||
throttling: PROFILES_MAP[PROFILE_VALUES_ENUM.DEFAULT],
|
||||
'ssl.certificate': '',
|
||||
'ssl.certificate_authorities': '',
|
||||
'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'],
|
||||
|
|
|
@ -31,11 +31,15 @@
|
|||
"filter_journeys.match": "",
|
||||
"filter_journeys.tags": [],
|
||||
"ignore_https_errors": false,
|
||||
"throttling.is_enabled": true,
|
||||
"throttling.download_speed": "5",
|
||||
"throttling.upload_speed": "3",
|
||||
"throttling.latency": "20",
|
||||
"throttling.config": "5d/3u/20l",
|
||||
"throttling": {
|
||||
"value": {
|
||||
"download": "5",
|
||||
"latency": "20",
|
||||
"upload": "3"
|
||||
},
|
||||
"id": "default",
|
||||
"label": "Default"
|
||||
},
|
||||
"locations": [],
|
||||
"name": "Test HTTP Monitor 03",
|
||||
"namespace": "testnamespace",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue