Uptime - Remove timeout for browser monitors (#122498)

* remove timeout for browser monitors

* adjust types

* update tests

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Dominique Clarke 2022-01-31 16:37:21 -05:00 committed by GitHub
parent b6ff8a6859
commit 99fc4eab1a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 262 additions and 92 deletions

View file

@ -48,18 +48,22 @@ export const ZipUrlTLSFieldsCodec = t.partial({
export type ZipUrlTLSFields = t.TypeOf<typeof ZipUrlTLSFieldsCodec>;
// CommonFields
export const CommonFieldsCodec = t.interface({
[ConfigKey.NAME]: t.string,
[ConfigKey.NAMESPACE]: t.string,
[ConfigKey.MONITOR_TYPE]: DataStreamCodec,
[ConfigKey.ENABLED]: t.boolean,
[ConfigKey.SCHEDULE]: Schedule,
[ConfigKey.LOCATIONS]: t.array(t.string),
[ConfigKey.APM_SERVICE_NAME]: t.string,
[ConfigKey.TIMEOUT]: t.string,
[ConfigKey.TAGS]: t.array(t.string),
[ConfigKey.LOCATIONS]: ServiceLocationsCodec,
});
export const CommonFieldsCodec = t.intersection([
t.interface({
[ConfigKey.NAME]: t.string,
[ConfigKey.NAMESPACE]: t.string,
[ConfigKey.MONITOR_TYPE]: DataStreamCodec,
[ConfigKey.ENABLED]: t.boolean,
[ConfigKey.SCHEDULE]: Schedule,
[ConfigKey.LOCATIONS]: t.array(t.string),
[ConfigKey.APM_SERVICE_NAME]: t.string,
[ConfigKey.TAGS]: t.array(t.string),
[ConfigKey.LOCATIONS]: ServiceLocationsCodec,
}),
t.partial({
[ConfigKey.TIMEOUT]: t.union([t.string, t.null]),
}),
]);
export type CommonFields = t.TypeOf<typeof CommonFieldsCodec>;

View file

@ -21,9 +21,12 @@ interface Props {
export const BrowserSimpleFields = memo<Props>(({ validate }) => {
const { fields, setFields, defaultValues } = useBrowserSimpleFieldsContext();
const handleInputChange = ({ value, configKey }: { value: unknown; configKey: ConfigKey }) => {
setFields((prevFields) => ({ ...prevFields, [configKey]: value }));
};
const handleInputChange = useCallback(
({ value, configKey }: { value: unknown; configKey: ConfigKey }) => {
setFields((prevFields) => ({ ...prevFields, [configKey]: value }));
},
[setFields]
);
const onChangeSourceField = useCallback(
({
zipUrl,

View file

@ -5,21 +5,41 @@
* 2.0.
*/
import React from 'react';
import React, { useEffect } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiFormRow, EuiFieldText, EuiFieldNumber } from '@elastic/eui';
import { Validation } from '../types';
import { Validation, DataStream } from '../types';
import { ConfigKey, CommonFields as CommonFieldsType } from '../types';
import { ComboBox } from '../combo_box';
import { OptionalLabel } from '../optional_label';
import { usePolicyConfigContext } from '../contexts';
interface Props {
validate: Validation;
fields: CommonFieldsType;
onChange: ({ value, configKey }: { value: string | string[]; configKey: ConfigKey }) => void;
onChange: ({
value,
configKey,
}: {
value: string | string[] | null;
configKey: ConfigKey;
}) => void;
}
export function CommonFields({ fields, onChange, validate }: Props) {
const { monitorType } = usePolicyConfigContext();
const isBrowser = monitorType === DataStream.BROWSER;
useEffect(() => {
if (monitorType === DataStream.BROWSER) {
onChange({
value: null,
configKey: ConfigKey.TIMEOUT,
});
}
}, [onChange, monitorType]);
return (
<>
<EuiFormRow
@ -48,46 +68,48 @@ export function CommonFields({ fields, onChange, validate }: Props) {
data-test-subj="syntheticsAPMServiceName"
/>
</EuiFormRow>
<EuiFormRow
label={
<FormattedMessage
id="xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.timeout.label"
defaultMessage="Timeout in seconds"
/>
}
isInvalid={!!validate[ConfigKey.TIMEOUT]?.(fields)}
error={
parseInt(fields[ConfigKey.TIMEOUT], 10) < 0 ? (
{!isBrowser && (
<EuiFormRow
label={
<FormattedMessage
id="xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.timeout.moreThanZeroError"
defaultMessage="Timeout must be greater than or equal to 0"
id="xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.timeout.label"
defaultMessage="Timeout in seconds"
/>
) : (
<FormattedMessage
id="xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.timeout.lessThanIntervalError"
defaultMessage="Timeout must be less than the monitor interval"
/>
)
}
helpText={
<FormattedMessage
id="xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.timeout.helpText"
defaultMessage="The total time allowed for testing the connection and exchanging data."
/>
}
>
<EuiFieldNumber
min={0}
value={fields[ConfigKey.TIMEOUT]}
onChange={(event) =>
onChange({
value: event.target.value,
configKey: ConfigKey.TIMEOUT,
})
}
step={'any'}
/>
</EuiFormRow>
isInvalid={!!validate[ConfigKey.TIMEOUT]?.(fields)}
error={
parseInt(fields[ConfigKey.TIMEOUT] || '', 10) < 0 ? (
<FormattedMessage
id="xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.timeout.moreThanZeroError"
defaultMessage="Timeout must be greater than or equal to 0"
/>
) : (
<FormattedMessage
id="xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.timeout.lessThanIntervalError"
defaultMessage="Timeout must be less than the monitor interval"
/>
)
}
helpText={
<FormattedMessage
id="xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.timeout.helpText"
defaultMessage="The total time allowed for testing the connection and exchanging data."
/>
}
>
<EuiFieldNumber
min={0}
value={fields[ConfigKey.TIMEOUT] || ''}
onChange={(event) =>
onChange({
value: event.target.value,
configKey: ConfigKey.TIMEOUT,
})
}
step={'any'}
/>
</EuiFormRow>
)}
<EuiFormRow
label={
<FormattedMessage

View file

@ -22,7 +22,7 @@ export const commonFormatters: CommonFormatMap = {
),
[ConfigKey.APM_SERVICE_NAME]: null,
[ConfigKey.TAGS]: (fields) => arrayToJsonFormatter(fields[ConfigKey.TAGS]),
[ConfigKey.TIMEOUT]: (fields) => secondsToCronFormatter(fields[ConfigKey.TIMEOUT]),
[ConfigKey.TIMEOUT]: (fields) => secondsToCronFormatter(fields[ConfigKey.TIMEOUT] || undefined),
[ConfigKey.NAMESPACE]: null,
};

View file

@ -255,6 +255,28 @@ describe('<CustomFields />', () => {
expect(queryByLabelText('Wait in seconds')).not.toBeInTheDocument();
});
it('does not show timeout for browser monitors', () => {
const { getByLabelText, queryByLabelText } = render(<WrappedComponent />);
const monitorType = getByLabelText('Monitor Type') as HTMLInputElement;
let timeout = getByLabelText('Timeout in seconds') as HTMLInputElement;
expect(monitorType).toBeInTheDocument();
expect(monitorType.value).toEqual(defaultHTTPConfig[ConfigKey.MONITOR_TYPE]);
expect(timeout.value).toEqual(defaultHTTPConfig[ConfigKey.TIMEOUT]);
// change to browser monitor
fireEvent.change(monitorType, { target: { value: DataStream.BROWSER } });
// expect timeout not to be in the DOM
expect(queryByLabelText('Timeout in seconds')).not.toBeInTheDocument();
// change back to HTTP
fireEvent.change(monitorType, { target: { value: DataStream.HTTP } });
// expect timeout value to be present with the correct value
timeout = getByLabelText('Timeout in seconds') as HTMLInputElement;
expect(timeout.value).toEqual(defaultHTTPConfig[ConfigKey.TIMEOUT]);
});
it('shows resolve hostnames locally field when proxy url is filled for tcp monitors', () => {
const { getByLabelText, queryByLabelText } = render(<WrappedComponent />);
const monitorType = getByLabelText('Monitor Type') as HTMLInputElement;

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { memo } from 'react';
import React, { memo, useCallback } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiFormRow, EuiFieldText, EuiFieldNumber } from '@elastic/eui';
import { ConfigKey, Validation } from '../types';
@ -20,9 +20,12 @@ interface Props {
export const HTTPSimpleFields = memo<Props>(({ validate }) => {
const { fields, setFields } = useHTTPSimpleFieldsContext();
const handleInputChange = ({ value, configKey }: { value: unknown; configKey: ConfigKey }) => {
setFields((prevFields) => ({ ...prevFields, [configKey]: value }));
};
const handleInputChange = useCallback(
({ value, configKey }: { value: unknown; configKey: ConfigKey }) => {
setFields((prevFields) => ({ ...prevFields, [configKey]: value }));
},
[setFields]
);
return (
<SimpleFieldsWrapper fields={fields} validate={validate} onInputChange={handleInputChange}>

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { memo } from 'react';
import React, { memo, useCallback } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiFormRow, EuiFieldText, EuiFieldNumber } from '@elastic/eui';
import { ConfigKey, Validation } from '../types';
@ -20,9 +20,12 @@ interface Props {
export const ICMPSimpleFields = memo<Props>(({ validate }) => {
const { fields, setFields } = useICMPSimpleFieldsContext();
const handleInputChange = ({ value, configKey }: { value: unknown; configKey: ConfigKey }) => {
setFields((prevFields) => ({ ...prevFields, [configKey]: value }));
};
const handleInputChange = useCallback(
({ value, configKey }: { value: unknown; configKey: ConfigKey }) => {
setFields((prevFields) => ({ ...prevFields, [configKey]: value }));
},
[setFields]
);
return (
<SimpleFieldsWrapper fields={fields} validate={validate} onInputChange={handleInputChange}>

View file

@ -710,21 +710,17 @@ describe('<SyntheticsPolicyCreateExtension />', () => {
const zipUrl = getByRole('textbox', { name: 'Zip URL' }) as HTMLInputElement;
const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement;
const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement;
// create errors
fireEvent.change(zipUrl, { target: { value: '' } });
fireEvent.change(monitorIntervalNumber, { target: { value: '-1' } });
fireEvent.change(timeout, { target: { value: '-1' } });
await waitFor(() => {
const hostError = getByText('Zip URL is required');
const monitorIntervalError = getByText('Monitor interval is required');
const timeoutError = getByText('Timeout must be greater than or equal to 0');
expect(hostError).toBeInTheDocument();
expect(monitorIntervalError).toBeInTheDocument();
expect(timeoutError).toBeInTheDocument();
expect(onChange).toBeCalledWith(
expect.objectContaining({
isValid: false,
@ -735,12 +731,10 @@ describe('<SyntheticsPolicyCreateExtension />', () => {
// resolve errors
fireEvent.change(zipUrl, { target: { value: 'http://github.com/tests.zip' } });
fireEvent.change(monitorIntervalNumber, { target: { value: '1' } });
fireEvent.change(timeout, { target: { value: '1' } });
await waitFor(() => {
expect(queryByText('Zip URL is required')).not.toBeInTheDocument();
expect(queryByText('Monitor interval is required')).not.toBeInTheDocument();
expect(queryByText('Timeout must be greater than or equal to 0')).not.toBeInTheDocument();
expect(onChange).toBeCalledWith(
expect.objectContaining({
isValid: true,

View file

@ -643,21 +643,17 @@ describe('<SyntheticsPolicyEditExtension />', () => {
const zipUrl = getByRole('textbox', { name: 'Zip URL' }) as HTMLInputElement;
const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement;
const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement;
// create errors
fireEvent.change(zipUrl, { target: { value: '' } });
fireEvent.change(monitorIntervalNumber, { target: { value: '-1' } });
fireEvent.change(timeout, { target: { value: '-1' } });
await waitFor(() => {
const hostError = getByText('Zip URL is required');
const monitorIntervalError = getByText('Monitor interval is required');
const timeoutError = getByText('Timeout must be greater than or equal to 0');
expect(hostError).toBeInTheDocument();
expect(monitorIntervalError).toBeInTheDocument();
expect(timeoutError).toBeInTheDocument();
expect(onChange).toBeCalledWith(
expect.objectContaining({
isValid: false,
@ -668,10 +664,8 @@ describe('<SyntheticsPolicyEditExtension />', () => {
await waitFor(() => {
fireEvent.change(zipUrl, { target: { value: 'http://github.com/tests.zip' } });
fireEvent.change(monitorIntervalNumber, { target: { value: '2' } });
fireEvent.change(timeout, { target: { value: '1' } });
expect(zipUrl.value).toEqual('http://github.com/tests.zip');
expect(monitorIntervalNumber.value).toEqual('2');
expect(timeout.value).toEqual('1');
expect(queryByText('Zip URL is required')).not.toBeInTheDocument();
expect(queryByText('Monitor interval is required')).not.toBeInTheDocument();
expect(queryByText('Timeout must be greater than or equal to 0')).not.toBeInTheDocument();
@ -1088,7 +1082,6 @@ describe('<SyntheticsPolicyEditExtension />', () => {
const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement;
const monitorIntervalUnit = getByLabelText('Unit') as HTMLInputElement;
const apmServiceName = getByLabelText('APM service name') as HTMLInputElement;
const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement;
expect(zipUrl).toBeInTheDocument();
expect(zipUrl.value).toEqual(defaultBrowserConfig[ConfigKey.SOURCE_ZIP_URL]);
expect(monitorIntervalNumber).toBeInTheDocument();
@ -1097,8 +1090,6 @@ describe('<SyntheticsPolicyEditExtension />', () => {
expect(monitorIntervalUnit.value).toEqual(defaultBrowserConfig[ConfigKey.SCHEDULE].unit);
expect(apmServiceName).toBeInTheDocument();
expect(apmServiceName.value).toEqual(defaultBrowserConfig[ConfigKey.APM_SERVICE_NAME]);
expect(timeout).toBeInTheDocument();
expect(timeout.value).toEqual(`${defaultBrowserConfig[ConfigKey.TIMEOUT]}`);
// ensure other monitor type options are not in the DOM
expect(queryByLabelText('Url')).not.toBeInTheDocument();

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { memo } from 'react';
import React, { memo, useCallback } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiFormRow, EuiFieldText } from '@elastic/eui';
import { ConfigKey, Validation } from '../types';
@ -19,9 +19,12 @@ interface Props {
export const TCPSimpleFields = memo<Props>(({ validate }) => {
const { fields, setFields } = useTCPSimpleFieldsContext();
const handleInputChange = ({ value, configKey }: { value: unknown; configKey: ConfigKey }) => {
setFields((prevFields) => ({ ...prevFields, [configKey]: value }));
};
const handleInputChange = useCallback(
({ value, configKey }: { value: unknown; configKey: ConfigKey }) => {
setFields((prevFields) => ({ ...prevFields, [configKey]: value }));
},
[setFields]
);
return (
<SimpleFieldsWrapper fields={fields} validate={validate} onInputChange={handleInputChange}>

View file

@ -0,0 +1,74 @@
/*
* 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 {
ConfigKey,
DataStream,
HTTPFields,
BrowserFields,
MonitorFields,
ScheduleUnit,
} from '../../../common/runtime_types';
import { validate } from './validation';
describe('[Monitor Management] validation', () => {
const commonPropsValid: Partial<MonitorFields> = {
[ConfigKey.SCHEDULE]: { number: '5', unit: ScheduleUnit.MINUTES },
[ConfigKey.TIMEOUT]: '3m',
};
describe('HTTP', () => {
const httpPropsValid: Partial<HTTPFields> = {
...commonPropsValid,
[ConfigKey.RESPONSE_STATUS_CHECK]: ['200', '204'],
[ConfigKey.RESPONSE_HEADERS_CHECK]: { 'Content-Type': 'application/json' },
[ConfigKey.REQUEST_HEADERS_CHECK]: { 'Accept-Language': 'en-GB,en-US;q=0.9,en;q=0.8' },
[ConfigKey.MAX_REDIRECTS]: '3',
[ConfigKey.URLS]: 'https:// example-url.com',
};
it('should return false for all valid props', () => {
const validators = validate[DataStream.HTTP];
const keysToValidate = [
ConfigKey.SCHEDULE,
ConfigKey.TIMEOUT,
ConfigKey.RESPONSE_STATUS_CHECK,
ConfigKey.RESPONSE_HEADERS_CHECK,
ConfigKey.REQUEST_HEADERS_CHECK,
ConfigKey.MAX_REDIRECTS,
ConfigKey.URLS,
];
const validatorFns = keysToValidate.map((key) => validators[key]);
const result = validatorFns.map((fn) => fn?.(httpPropsValid) ?? true);
expect(result).not.toEqual(expect.arrayContaining([true]));
});
});
describe.each([
[ConfigKey.SOURCE_INLINE, 'step(() => {});'],
[ConfigKey.SOURCE_ZIP_URL, 'https://test.zip'],
])('Browser', (configKey, value) => {
const browserProps: Partial<BrowserFields> = {
...commonPropsValid,
[ConfigKey.MONITOR_TYPE]: DataStream.BROWSER,
[ConfigKey.TIMEOUT]: null,
[configKey]: value,
};
it('should return false for all valid props', () => {
const validators = validate[DataStream.BROWSER];
const keysToValidate = [ConfigKey.SCHEDULE, ConfigKey.TIMEOUT, configKey];
const validatorFns = keysToValidate.map((key) => validators[key]);
const result = validatorFns.map((fn) => fn?.(browserProps) ?? true);
expect(result).not.toEqual(expect.arrayContaining([true]));
});
});
// TODO: Add test for other monitor types if needed
});

View file

@ -55,9 +55,18 @@ const validateCommon: ValidationLibrary = {
const parsedFloat = parseFloat(number);
return !parsedFloat || !unit || parsedFloat < 1;
},
[ConfigKey.TIMEOUT]: ({ [ConfigKey.TIMEOUT]: timeout, [ConfigKey.SCHEDULE]: schedule }) => {
[ConfigKey.TIMEOUT]: ({
[ConfigKey.MONITOR_TYPE]: monitorType,
[ConfigKey.TIMEOUT]: timeout,
[ConfigKey.SCHEDULE]: schedule,
}) => {
const { number, unit } = schedule as MonitorFields[ConfigKey.SCHEDULE];
// Timeout is not currently supported by browser monitors
if (monitorType === DataStream.BROWSER) {
return false;
}
return (
!timeout ||
parseFloat(timeout) < 0 ||

View file

@ -9,6 +9,7 @@ import {
ConfigKey,
DataStream,
HTTPFields,
BrowserFields,
MonitorFields,
ScheduleUnit,
ServiceLocations,
@ -90,5 +91,37 @@ describe('[Monitor Management] validation', () => {
});
});
describe.each([
[ConfigKey.SOURCE_INLINE, 'step(() => {});'],
[ConfigKey.SOURCE_ZIP_URL, 'https://test.zip'],
])('Browser', (configKey, value) => {
const browserProps: Partial<BrowserFields> = {
...commonPropsValid,
[ConfigKey.MONITOR_TYPE]: DataStream.BROWSER,
[ConfigKey.TIMEOUT]: undefined,
[configKey]: value,
};
it('should return false for all valid props', () => {
const validators = validate[DataStream.BROWSER];
const keysToValidate = [ConfigKey.SCHEDULE, ConfigKey.TIMEOUT, configKey];
const validatorFns = keysToValidate.map((key) => validators[key]);
const result = validatorFns.map((fn) => fn?.(browserProps) ?? true);
expect(result).not.toEqual(expect.arrayContaining([true]));
});
it('should invalidate when locations is empty', () => {
const validators = validate[DataStream.BROWSER];
const validatorFn = validators[ConfigKey.LOCATIONS];
const result = [undefined, null, []].map(
(testValue) =>
validatorFn?.({ [ConfigKey.LOCATIONS]: testValue } as Partial<MonitorFields>) ?? false
);
expect(result).toEqual([true, true, true]);
});
});
// TODO: Add test for other monitor types if needed
});

View file

@ -64,9 +64,18 @@ export const validateCommon: Validation = {
const parsedFloat = parseFloat(number);
return !parsedFloat || !unit || parsedFloat < 1;
},
[ConfigKey.TIMEOUT]: ({ [ConfigKey.TIMEOUT]: timeout, [ConfigKey.SCHEDULE]: schedule }) => {
[ConfigKey.TIMEOUT]: ({
[ConfigKey.MONITOR_TYPE]: monitorType,
[ConfigKey.TIMEOUT]: timeout,
[ConfigKey.SCHEDULE]: schedule,
}) => {
const { number, unit } = schedule as MonitorFields[ConfigKey.SCHEDULE];
// Timeout is not currently supported by browser monitors
if (monitorType === DataStream.BROWSER) {
return false;
}
return (
!timeout ||
parseFloat(timeout) < 0 ||

View file

@ -23,7 +23,7 @@ export const commonFormatters: CommonFormatMap = {
`@every ${fields[ConfigKey.SCHEDULE]?.number}${fields[ConfigKey.SCHEDULE]?.unit}`,
[ConfigKey.APM_SERVICE_NAME]: null,
[ConfigKey.TAGS]: (fields) => arrayFormatter(fields[ConfigKey.TAGS]),
[ConfigKey.TIMEOUT]: (fields) => secondsToCronFormatter(fields[ConfigKey.TIMEOUT]),
[ConfigKey.TIMEOUT]: (fields) => secondsToCronFormatter(fields[ConfigKey.TIMEOUT] || undefined),
[ConfigKey.NAMESPACE]: null,
};

View file

@ -282,14 +282,14 @@ describe('validateMonitor', () => {
const testMonitor = {
...testTCPFields,
...({
[ConfigKey.TIMEOUT]: undefined,
[ConfigKey.NAME]: undefined,
} as unknown as Partial<TCPFields>),
} as MonitorFields;
const result = validateMonitor(testMonitor);
expect(result.details).toEqual(expect.stringContaining('Invalid value'));
expect(result.details).toEqual(expect.stringContaining(ConfigKey.TIMEOUT));
expect(result.details).toEqual(expect.stringContaining(ConfigKey.NAME));
expect(result).toMatchObject({
valid: false,
reason: `Monitor is not a valid monitor of type ${DataStream.TCP}`,

View file

@ -555,7 +555,7 @@ export default function (providerContext: FtrProviderContext) {
config: {
screenshots: 'on',
schedule: '@every 3m',
timeout: '16s',
timeout: null,
tags: [config.tags],
throttling: '5d/3u/20l',
'service.name': config.apmServiceName,
@ -605,7 +605,7 @@ export default function (providerContext: FtrProviderContext) {
config: {
screenshots: 'on',
schedule: '@every 3m',
timeout: '16s',
timeout: null,
tags: [config.tags],
throttling: '5d/3u/20l',
'service.name': config.apmServiceName,
@ -664,7 +664,7 @@ export default function (providerContext: FtrProviderContext) {
config: {
screenshots: advancedConfig.screenshots,
schedule: '@every 3m',
timeout: '16s',
timeout: null,
tags: [config.tags],
throttling: '1337d/1338u/1339l',
'service.name': config.apmServiceName,
@ -728,7 +728,7 @@ export default function (providerContext: FtrProviderContext) {
config: {
screenshots: advancedConfig.screenshots,
schedule: '@every 3m',
timeout: '16s',
timeout: null,
tags: [config.tags],
'service.name': config.apmServiceName,
'source.zip_url.url': config.zipUrl,