mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
# Backport This will backport the following commits from `main` to `8.6`: - [[Synthetics] Deprecate adding synthetics integrations from fleet (#146369)](https://github.com/elastic/kibana/pull/146369) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Shahzad","email":"shahzad.muhammad@elastic.co"},"sourceCommit":{"committedDate":"2022-11-29T20:29:26Z","message":"[Synthetics] Deprecate adding synthetics integrations from fleet (#146369)\n\nCo-authored-by: florent-leborgne <florent.leborgne@elastic.co>\r\nFixes https://github.com/elastic/kibana/issues/137501","sha":"d13666885469c354bdb55c7bb84f127d23b1b83f","branchLabelMapping":{"^v8.7.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:uptime","release_note:skip","Team:Fleet","v8.6.0","v8.7.0"],"number":146369,"url":"https://github.com/elastic/kibana/pull/146369","mergeCommit":{"message":"[Synthetics] Deprecate adding synthetics integrations from fleet (#146369)\n\nCo-authored-by: florent-leborgne <florent.leborgne@elastic.co>\r\nFixes https://github.com/elastic/kibana/issues/137501","sha":"d13666885469c354bdb55c7bb84f127d23b1b83f"}},"sourceBranch":"main","suggestedTargetBranches":["8.6"],"targetPullRequestStates":[{"branch":"8.6","label":"v8.6.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.7.0","labelRegex":"^v8.7.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/146369","number":146369,"mergeCommit":{"message":"[Synthetics] Deprecate adding synthetics integrations from fleet (#146369)\n\nCo-authored-by: florent-leborgne <florent.leborgne@elastic.co>\r\nFixes https://github.com/elastic/kibana/issues/137501","sha":"d13666885469c354bdb55c7bb84f127d23b1b83f"}}]}] BACKPORT--> Co-authored-by: Shahzad <shahzad.muhammad@elastic.co>
This commit is contained in:
parent
42bf33f146
commit
c9fe5ac74b
24 changed files with 138 additions and 2559 deletions
|
@ -155,7 +155,6 @@ enabled:
|
|||
- x-pack/test/functional_embedded/config.ts
|
||||
- x-pack/test/functional_enterprise_search/without_host_configured.config.ts
|
||||
- x-pack/test/functional_execution_context/config.ts
|
||||
- x-pack/test/functional_synthetics/config.js
|
||||
- x-pack/test/functional_with_es_ssl/config.ts
|
||||
- x-pack/test/functional/apps/advanced_settings/config.ts
|
||||
- x-pack/test/functional/apps/aiops/config.ts
|
||||
|
|
|
@ -181,7 +181,6 @@ As part of the bundled package update process, we'll likely also need to update
|
|||
- `x-pack/test/fleet_api_integration/config.ts`
|
||||
- `x-pack/plugins/fleet/server/integration_tests/helpers/docker_registry_helper.ts`
|
||||
- `x-pack/test/functional/config.base.js`
|
||||
- `x-pack/test/functional_synthetics/config.js`
|
||||
|
||||
To update this registry image, pull the digest SHA from the package storage Jenkins pipeline at https://beats-ci.elastic.co/blue/organizations/jenkins/Ingest-manager%2Fpackage-storage/activity and update the files above. The digest value should appear in the "publish Docker image" step as part of the `docker push` command in the logs.
|
||||
|
||||
|
|
|
@ -20,11 +20,6 @@ export const ManageMonitorsBtn = () => {
|
|||
|
||||
const history = useHistory();
|
||||
|
||||
const handleOnClick = () => {
|
||||
setIsOpen(false);
|
||||
history.push(MONITOR_MANAGEMENT_ROUTE + '/all');
|
||||
};
|
||||
|
||||
return (
|
||||
<EuiTourStep
|
||||
content={
|
||||
|
@ -33,7 +28,13 @@ export const ManageMonitorsBtn = () => {
|
|||
<p>{PUBLIC_BETA_DESCRIPTION}</p>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiButton color="primary" fill onClick={handleOnClick}>
|
||||
<EuiButton
|
||||
color="primary"
|
||||
fill
|
||||
href={history.createHref({
|
||||
pathname: MONITOR_MANAGEMENT_ROUTE,
|
||||
})}
|
||||
>
|
||||
{MONITOR_MANAGEMENT_LABEL}
|
||||
</EuiButton>
|
||||
</>
|
||||
|
@ -56,7 +57,9 @@ export const ManageMonitorsBtn = () => {
|
|||
aria-label={NAVIGATE_LABEL}
|
||||
color="text"
|
||||
data-test-subj="syntheticsManagementPageLink"
|
||||
onClick={handleOnClick}
|
||||
href={history.createHref({
|
||||
pathname: MONITOR_MANAGEMENT_ROUTE,
|
||||
})}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.page_header.manageMonitors"
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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 { EuiConfirmModal, EuiIcon, EuiLink } from '@elastic/eui';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
export const DeprecateNoticeModal = ({ onCancel }: { onCancel: () => void }) => {
|
||||
const { application } = useKibana().services;
|
||||
|
||||
return (
|
||||
<EuiConfirmModal
|
||||
title={
|
||||
<>
|
||||
{HEADER_TEXT} <EuiIcon type="cheer" />
|
||||
</>
|
||||
}
|
||||
onCancel={onCancel}
|
||||
onConfirm={() => {
|
||||
application?.navigateToApp('uptime', { path: '/manage-monitors' });
|
||||
}}
|
||||
confirmButtonText={GO_MONITOR_MANAGEMENT_TEXT}
|
||||
cancelButtonText={GO_BACK_TEXT}
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.deprecateNoticeModal.description"
|
||||
defaultMessage="The Elastic Synthetics integration is deprecated. Instead, you can now monitor endpoints,
|
||||
pages, and user journeys directly from Uptime much more efficiently:"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<li>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.deprecateNoticeModal.addPrivateLocations"
|
||||
defaultMessage="Add private locations against your fleet policies"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.deprecateNoticeModal.manageMonitors"
|
||||
defaultMessage="Manage lightweight and browser monitors from a single place"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.deprecateNoticeModal.elasticManagedLocations"
|
||||
defaultMessage="Run monitors in multiple locations managed by Elastic, or from your own private locations"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.deprecateNoticeModal.automateMonitors"
|
||||
defaultMessage="Automate the creation of your monitors using project monitors"
|
||||
/>
|
||||
</li>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.deprecateNoticeModal.forMoreInformation"
|
||||
defaultMessage="For more information, {docsLink}"
|
||||
values={{
|
||||
docsLink: (
|
||||
<EuiLink
|
||||
target="_blank"
|
||||
href="https://www.elastic.co/guide/en/observability/current/monitor-uptime-synthetics.html"
|
||||
>
|
||||
{READ_DOCS_TEXT}
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</EuiConfirmModal>
|
||||
);
|
||||
};
|
||||
|
||||
const HEADER_TEXT = i18n.translate('xpack.synthetics.deprecateNoticeModal.headerText', {
|
||||
defaultMessage: 'Synthetic Monitoring is now available out of the box in Uptime',
|
||||
});
|
||||
|
||||
const GO_BACK_TEXT = i18n.translate('xpack.synthetics.deprecateNoticeModal.goBack', {
|
||||
defaultMessage: 'Go back',
|
||||
});
|
||||
|
||||
const READ_DOCS_TEXT = i18n.translate('xpack.synthetics.deprecateNoticeModal.readDocs', {
|
||||
defaultMessage: 'read docs.',
|
||||
});
|
||||
|
||||
const GO_MONITOR_MANAGEMENT_TEXT = i18n.translate(
|
||||
'xpack.synthetics.deprecateNoticeModal.goToMonitorManagement',
|
||||
{
|
||||
defaultMessage: 'Go to Monitor Management',
|
||||
}
|
||||
);
|
|
@ -5,16 +5,13 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { memo, useEffect, useMemo } from 'react';
|
||||
import React, { memo, useCallback } from 'react';
|
||||
import { PackagePolicyCreateExtensionComponentProps } from '@kbn/fleet-plugin/public';
|
||||
import { useTrackPageview } from '@kbn/observability-plugin/public';
|
||||
import { DataStream, PolicyConfig, MonitorFields } from './types';
|
||||
import { usePolicyConfigContext } from './contexts';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { DeprecateNoticeModal } from './deprecate_notice_modal';
|
||||
import { PolicyConfig } from './types';
|
||||
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
|
||||
import { CustomFields } from './custom_fields';
|
||||
import { useUpdatePolicy } from './hooks/use_update_policy';
|
||||
import { usePolicy } from './hooks/use_policy';
|
||||
import { validate } from './validation';
|
||||
|
||||
export const defaultConfig: PolicyConfig = DEFAULT_FIELDS;
|
||||
|
||||
|
@ -27,39 +24,16 @@ export const SyntheticsPolicyCreateExtension = memo<PackagePolicyCreateExtension
|
|||
useTrackPageview({ app: 'fleet', path: 'syntheticsCreate' });
|
||||
useTrackPageview({ app: 'fleet', path: 'syntheticsCreate', delay: 15000 });
|
||||
|
||||
const { monitorType } = usePolicyConfigContext();
|
||||
const policyConfig: PolicyConfig = usePolicy(newPolicy.name);
|
||||
const { application } = useKibana().services;
|
||||
|
||||
const dataStreams: DataStream[] = useMemo(() => {
|
||||
return newPolicy.inputs.map((input) => {
|
||||
return input.type.replace(/synthetics\//g, '') as DataStream;
|
||||
const { package: pkg } = newPolicy;
|
||||
|
||||
const onCancel = useCallback(() => {
|
||||
application?.navigateToApp('integrations', {
|
||||
path: `/detail/${pkg?.name}-${pkg?.version}/overview`,
|
||||
});
|
||||
}, [newPolicy]);
|
||||
|
||||
useUpdatePolicy({
|
||||
monitorType,
|
||||
defaultConfig: defaultConfig[monitorType] as Partial<MonitorFields>,
|
||||
config: policyConfig[monitorType] as Partial<MonitorFields>,
|
||||
newPolicy,
|
||||
onChange,
|
||||
validate,
|
||||
});
|
||||
|
||||
// Fleet will initialize the create form with a default name for the integratin policy, however,
|
||||
// for synthetics, we want the user to explicitely type in a name to use as the monitor name,
|
||||
// so we blank it out only during 1st component render (thus why the eslint disabled rule below).
|
||||
useEffect(() => {
|
||||
onChange({
|
||||
isValid: false,
|
||||
updatedPolicy: {
|
||||
...newPolicy,
|
||||
name: '',
|
||||
},
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return <CustomFields validate={validate[monitorType]} dataStreams={dataStreams} />;
|
||||
}, [application, pkg?.name, pkg?.version]);
|
||||
return <DeprecateNoticeModal onCancel={onCancel} />;
|
||||
}
|
||||
);
|
||||
SyntheticsPolicyCreateExtension.displayName = 'SyntheticsPolicyCreateExtension';
|
||||
|
|
|
@ -1,837 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
|
||||
import React from 'react';
|
||||
import { fireEvent, waitFor } from '@testing-library/react';
|
||||
import { render } from '../../lib/helper/rtl_helpers';
|
||||
import { NewPackagePolicy } from '@kbn/fleet-plugin/public';
|
||||
import { SyntheticsPolicyCreateExtensionWrapper } from './synthetics_policy_create_extension_wrapper';
|
||||
import { defaultConfig } from './synthetics_policy_create_extension';
|
||||
import { ConfigKey, DataStream, ScheduleUnit, VerificationMode } from './types';
|
||||
|
||||
// ensures that fields appropriately match to their label
|
||||
jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({
|
||||
...jest.requireActual('@elastic/eui/lib/services/accessibility/html_id_generator'),
|
||||
htmlIdGenerator: () => () => `id-${Math.random()}`,
|
||||
}));
|
||||
|
||||
// ensures that fields appropriately match to their label
|
||||
jest.mock('@elastic/eui/lib/services/accessibility', () => ({
|
||||
...jest.requireActual('@elastic/eui/lib/services/accessibility'),
|
||||
useGeneratedHtmlId: () => `id-${Math.random()}`,
|
||||
}));
|
||||
|
||||
jest.mock('@kbn/kibana-react-plugin/public', () => {
|
||||
const original = jest.requireActual('@kbn/kibana-react-plugin/public');
|
||||
return {
|
||||
...original,
|
||||
// Mocking CodeEditor, which uses React Monaco under the hood
|
||||
CodeEditor: (props: any) => (
|
||||
<input
|
||||
data-test-subj={props['data-test-subj'] || 'mockCodeEditor'}
|
||||
data-currentvalue={props.value}
|
||||
onChange={(e: any) => {
|
||||
props.onChange(e.jsonContent);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
const defaultNewPolicy: NewPackagePolicy = {
|
||||
name: 'samplePolicyName',
|
||||
description: '',
|
||||
namespace: 'default',
|
||||
policy_id: 'ae774160-8e49-11eb-aba5-99269d21ba6e',
|
||||
enabled: true,
|
||||
inputs: [
|
||||
{
|
||||
type: 'synthetics/http',
|
||||
enabled: true,
|
||||
streams: [
|
||||
{
|
||||
enabled: true,
|
||||
data_stream: {
|
||||
type: 'synthetics',
|
||||
dataset: 'http',
|
||||
},
|
||||
vars: {
|
||||
__ui: {
|
||||
value: JSON.stringify({ is_tls_enabled: true }),
|
||||
type: 'yaml',
|
||||
},
|
||||
type: {
|
||||
value: 'http',
|
||||
type: 'text',
|
||||
},
|
||||
name: {
|
||||
value: 'Sample name',
|
||||
type: 'text',
|
||||
},
|
||||
schedule: {
|
||||
value: '"@every 5s"',
|
||||
type: 'text',
|
||||
},
|
||||
urls: {
|
||||
value: '',
|
||||
type: 'text',
|
||||
},
|
||||
'service.name': {
|
||||
value: '',
|
||||
type: 'text',
|
||||
},
|
||||
timeout: {
|
||||
value: '16s',
|
||||
type: 'text',
|
||||
},
|
||||
max_redirects: {
|
||||
value: 0,
|
||||
type: 'integer',
|
||||
},
|
||||
proxy_url: {
|
||||
value: '',
|
||||
type: 'text',
|
||||
},
|
||||
tags: {
|
||||
value: '[]',
|
||||
type: 'yaml',
|
||||
},
|
||||
'response.include_headers': {
|
||||
value: true,
|
||||
type: 'bool',
|
||||
},
|
||||
'response.include_body': {
|
||||
value: 'on_error',
|
||||
type: 'text',
|
||||
},
|
||||
'check.request.method': {
|
||||
value: 'GET',
|
||||
type: 'text',
|
||||
},
|
||||
'check.request.headers': {
|
||||
value: '{}',
|
||||
type: 'yaml',
|
||||
},
|
||||
'check.request.body': {
|
||||
value: '""',
|
||||
type: 'yaml',
|
||||
},
|
||||
'check.response.status': {
|
||||
value: '[]',
|
||||
type: 'yaml',
|
||||
},
|
||||
'check.response.headers': {
|
||||
value: '{}',
|
||||
type: 'yaml',
|
||||
},
|
||||
'check.response.body.positive': {
|
||||
value: '[]',
|
||||
type: 'yaml',
|
||||
},
|
||||
'check.response.body.negative': {
|
||||
value: '[]',
|
||||
type: 'yaml',
|
||||
},
|
||||
'ssl.certificate_authorities': {
|
||||
value: '',
|
||||
type: 'yaml',
|
||||
},
|
||||
'ssl.certificate': {
|
||||
value: '',
|
||||
type: 'yaml',
|
||||
},
|
||||
'ssl.key': {
|
||||
value: '',
|
||||
type: 'yaml',
|
||||
},
|
||||
'ssl.key_passphrase': {
|
||||
type: 'text',
|
||||
},
|
||||
'ssl.verification_mode': {
|
||||
value: 'full',
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'synthetics/tcp',
|
||||
enabled: false,
|
||||
streams: [
|
||||
{
|
||||
enabled: false,
|
||||
data_stream: {
|
||||
type: 'synthetics',
|
||||
dataset: 'tcp',
|
||||
},
|
||||
vars: {
|
||||
type: {
|
||||
value: 'tcp',
|
||||
type: 'text',
|
||||
},
|
||||
name: {
|
||||
value: 'Sample name',
|
||||
type: 'text',
|
||||
},
|
||||
schedule: {
|
||||
value: '10s',
|
||||
type: 'text',
|
||||
},
|
||||
hosts: {
|
||||
type: 'text',
|
||||
},
|
||||
'service.name': {
|
||||
type: 'text',
|
||||
},
|
||||
timeout: {
|
||||
type: 'text',
|
||||
},
|
||||
max_redirects: {
|
||||
type: 'integer',
|
||||
},
|
||||
proxy_url: {
|
||||
type: 'text',
|
||||
},
|
||||
proxy_use_local_resolver: {
|
||||
value: false,
|
||||
type: 'bool',
|
||||
},
|
||||
tags: {
|
||||
type: 'yaml',
|
||||
},
|
||||
'check.send': {
|
||||
type: 'text',
|
||||
},
|
||||
'check.receive': {
|
||||
type: 'yaml',
|
||||
},
|
||||
'ssl.certificate_authorities': {
|
||||
type: 'yaml',
|
||||
},
|
||||
'ssl.certificate': {
|
||||
type: 'yaml',
|
||||
},
|
||||
'ssl.key': {
|
||||
type: 'yaml',
|
||||
},
|
||||
'ssl.key_passphrase': {
|
||||
type: 'text',
|
||||
},
|
||||
'ssl.verification_mode': {
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'synthetics/icmp',
|
||||
enabled: false,
|
||||
streams: [
|
||||
{
|
||||
enabled: false,
|
||||
data_stream: {
|
||||
type: 'synthetics',
|
||||
dataset: 'icmp',
|
||||
},
|
||||
vars: {
|
||||
type: {
|
||||
value: 'icmp',
|
||||
type: 'text',
|
||||
},
|
||||
name: {
|
||||
value: 'Sample name',
|
||||
type: 'text',
|
||||
},
|
||||
schedule: {
|
||||
value: '10s',
|
||||
type: 'text',
|
||||
},
|
||||
wait: {
|
||||
value: '1s',
|
||||
type: 'text',
|
||||
},
|
||||
hosts: {
|
||||
type: 'text',
|
||||
},
|
||||
'service.name': {
|
||||
type: 'text',
|
||||
},
|
||||
timeout: {
|
||||
type: 'text',
|
||||
},
|
||||
tags: {
|
||||
type: 'yaml',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'synthetics/browser',
|
||||
enabled: false,
|
||||
streams: [
|
||||
{
|
||||
enabled: false,
|
||||
data_stream: {
|
||||
type: 'synthetics',
|
||||
dataset: 'browser',
|
||||
},
|
||||
vars: {
|
||||
type: {
|
||||
value: 'browser',
|
||||
type: 'text',
|
||||
},
|
||||
name: {
|
||||
value: 'Sample name',
|
||||
type: 'text',
|
||||
},
|
||||
schedule: {
|
||||
value: '10s',
|
||||
type: 'text',
|
||||
},
|
||||
'source.zip_url.url': {
|
||||
type: 'text',
|
||||
},
|
||||
'source.zip_url.username': {
|
||||
type: 'text',
|
||||
},
|
||||
'source.zip_url.password': {
|
||||
type: 'password',
|
||||
},
|
||||
'source.zip_url.folder': {
|
||||
type: 'text',
|
||||
},
|
||||
'source.inline.script': {
|
||||
type: 'yaml',
|
||||
},
|
||||
timeout: {
|
||||
type: 'text',
|
||||
},
|
||||
tags: {
|
||||
type: 'yaml',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
package: {
|
||||
name: 'synthetics',
|
||||
title: 'Elastic Synthetics',
|
||||
version: '0.66.0',
|
||||
},
|
||||
};
|
||||
|
||||
const defaultHTTPConfig = defaultConfig[DataStream.HTTP];
|
||||
const defaultTCPConfig = defaultConfig[DataStream.TCP];
|
||||
|
||||
describe('<SyntheticsPolicyCreateExtension />', () => {
|
||||
const onChange = jest.fn();
|
||||
const WrappedComponent = ({ newPolicy = defaultNewPolicy }) => {
|
||||
return <SyntheticsPolicyCreateExtensionWrapper newPolicy={newPolicy} onChange={onChange} />;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
onChange.mockClear();
|
||||
});
|
||||
|
||||
it('renders SyntheticsPolicyCreateExtension', async () => {
|
||||
const { getByText, getByLabelText, queryByLabelText } = render(<WrappedComponent />);
|
||||
const monitorType = queryByLabelText('Monitor Type') as HTMLInputElement;
|
||||
const url = getByLabelText('URL') as HTMLInputElement;
|
||||
const proxyUrl = getByLabelText('Proxy URL') as HTMLInputElement;
|
||||
const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement;
|
||||
const monitorIntervalUnit = getByLabelText('Unit') as HTMLInputElement;
|
||||
const apmServiceName = getByLabelText('APM service name') as HTMLInputElement;
|
||||
const maxRedirects = getByLabelText('Max redirects') as HTMLInputElement;
|
||||
const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement;
|
||||
expect(monitorType).toBeInTheDocument();
|
||||
expect(monitorType.value).toEqual(DataStream.HTTP);
|
||||
expect(url).toBeInTheDocument();
|
||||
expect(url.value).toEqual(defaultHTTPConfig[ConfigKey.URLS]);
|
||||
expect(proxyUrl).toBeInTheDocument();
|
||||
expect(proxyUrl.value).toEqual(defaultHTTPConfig[ConfigKey.PROXY_URL]);
|
||||
expect(monitorIntervalNumber).toBeInTheDocument();
|
||||
expect(monitorIntervalNumber.value).toEqual(defaultHTTPConfig[ConfigKey.SCHEDULE].number);
|
||||
expect(monitorIntervalUnit).toBeInTheDocument();
|
||||
expect(monitorIntervalUnit.value).toEqual(defaultHTTPConfig[ConfigKey.SCHEDULE].unit);
|
||||
expect(apmServiceName).toBeInTheDocument();
|
||||
expect(apmServiceName.value).toEqual(defaultHTTPConfig[ConfigKey.APM_SERVICE_NAME]);
|
||||
expect(maxRedirects).toBeInTheDocument();
|
||||
expect(maxRedirects.value).toEqual(`${defaultHTTPConfig[ConfigKey.MAX_REDIRECTS]}`);
|
||||
expect(timeout).toBeInTheDocument();
|
||||
expect(timeout.value).toEqual(`${defaultHTTPConfig[ConfigKey.TIMEOUT]}`);
|
||||
|
||||
// ensure other monitor type options are not in the DOM
|
||||
expect(queryByLabelText('Host')).not.toBeInTheDocument();
|
||||
expect(queryByLabelText('Wait in seconds')).not.toBeInTheDocument();
|
||||
|
||||
// ensure at least one http advanced option is present
|
||||
const advancedOptionsButton = getByText('Advanced HTTP options');
|
||||
fireEvent.click(advancedOptionsButton);
|
||||
await waitFor(() => {
|
||||
expect(getByLabelText('Request method')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('handles updating fields', async () => {
|
||||
const { getByLabelText } = render(<WrappedComponent />);
|
||||
const url = getByLabelText('URL') as HTMLInputElement;
|
||||
const proxyUrl = getByLabelText('Proxy URL') as HTMLInputElement;
|
||||
const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement;
|
||||
const monitorIntervalUnit = getByLabelText('Unit') as HTMLInputElement;
|
||||
const apmServiceName = getByLabelText('APM service name') as HTMLInputElement;
|
||||
const maxRedirects = getByLabelText('Max redirects') as HTMLInputElement;
|
||||
const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement;
|
||||
|
||||
fireEvent.change(url, { target: { value: 'http://elastic.co' } });
|
||||
fireEvent.change(proxyUrl, { target: { value: 'http://proxy.co' } });
|
||||
fireEvent.change(monitorIntervalNumber, { target: { value: '1' } });
|
||||
fireEvent.change(monitorIntervalUnit, { target: { value: ScheduleUnit.MINUTES } });
|
||||
fireEvent.change(apmServiceName, { target: { value: 'APM Service' } });
|
||||
fireEvent.change(maxRedirects, { target: { value: '2' } });
|
||||
fireEvent.change(timeout, { target: { value: '3' } });
|
||||
|
||||
expect(url.value).toEqual('http://elastic.co');
|
||||
expect(proxyUrl.value).toEqual('http://proxy.co');
|
||||
expect(monitorIntervalNumber.value).toEqual('1');
|
||||
expect(monitorIntervalUnit.value).toEqual(ScheduleUnit.MINUTES);
|
||||
expect(apmServiceName.value).toEqual('APM Service');
|
||||
expect(maxRedirects.value).toEqual('2');
|
||||
expect(timeout.value).toEqual('3');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(onChange).toBeCalledWith({
|
||||
isValid: true,
|
||||
updatedPolicy: {
|
||||
...defaultNewPolicy,
|
||||
inputs: [
|
||||
{
|
||||
...defaultNewPolicy.inputs[0],
|
||||
streams: [
|
||||
{
|
||||
...defaultNewPolicy.inputs[0].streams[0],
|
||||
vars: {
|
||||
...defaultNewPolicy.inputs[0].streams[0].vars,
|
||||
urls: {
|
||||
value: 'http://elastic.co',
|
||||
type: 'text',
|
||||
},
|
||||
proxy_url: {
|
||||
value: 'http://proxy.co',
|
||||
type: 'text',
|
||||
},
|
||||
schedule: {
|
||||
value: '"@every 1m"',
|
||||
type: 'text',
|
||||
},
|
||||
'service.name': {
|
||||
value: 'APM Service',
|
||||
type: 'text',
|
||||
},
|
||||
max_redirects: {
|
||||
value: '2',
|
||||
type: 'integer',
|
||||
},
|
||||
timeout: {
|
||||
value: '3s',
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultNewPolicy.inputs[1],
|
||||
defaultNewPolicy.inputs[2],
|
||||
defaultNewPolicy.inputs[3],
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('handles calling onChange', async () => {
|
||||
const { getByLabelText } = render(<WrappedComponent />);
|
||||
const url = getByLabelText('URL') as HTMLInputElement;
|
||||
|
||||
fireEvent.change(url, { target: { value: 'http://elastic.co' } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(onChange).toBeCalledWith({
|
||||
isValid: true,
|
||||
updatedPolicy: {
|
||||
...defaultNewPolicy,
|
||||
inputs: [
|
||||
{
|
||||
...defaultNewPolicy.inputs[0],
|
||||
streams: [
|
||||
{
|
||||
...defaultNewPolicy.inputs[0].streams[0],
|
||||
vars: {
|
||||
...defaultNewPolicy.inputs[0].streams[0].vars,
|
||||
urls: {
|
||||
value: 'http://elastic.co',
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultNewPolicy.inputs[1],
|
||||
defaultNewPolicy.inputs[2],
|
||||
defaultNewPolicy.inputs[3],
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('handles switching monitor type', async () => {
|
||||
const { getByText, getByLabelText, queryByLabelText } = render(<WrappedComponent />);
|
||||
const monitorType = getByLabelText('Monitor Type') as HTMLInputElement;
|
||||
expect(monitorType).toBeInTheDocument();
|
||||
expect(monitorType.value).toEqual(DataStream.HTTP);
|
||||
fireEvent.change(monitorType, { target: { value: DataStream.TCP } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(onChange).toBeCalledWith({
|
||||
isValid: false,
|
||||
updatedPolicy: {
|
||||
...defaultNewPolicy,
|
||||
inputs: [
|
||||
{
|
||||
...defaultNewPolicy.inputs[0],
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
...defaultNewPolicy.inputs[1],
|
||||
enabled: true,
|
||||
},
|
||||
defaultNewPolicy.inputs[2],
|
||||
defaultNewPolicy.inputs[3],
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// expect tcp fields to be in the DOM
|
||||
const host = getByLabelText('Host:Port') as HTMLInputElement;
|
||||
|
||||
expect(host).toBeInTheDocument();
|
||||
expect(host.value).toEqual(defaultTCPConfig[ConfigKey.HOSTS]);
|
||||
|
||||
// expect HTTP fields not to be in the DOM
|
||||
expect(queryByLabelText('URL')).not.toBeInTheDocument();
|
||||
expect(queryByLabelText('Max redirects')).not.toBeInTheDocument();
|
||||
|
||||
// ensure at least one tcp advanced option is present
|
||||
const advancedOptionsButton = getByText('Advanced TCP options');
|
||||
fireEvent.click(advancedOptionsButton);
|
||||
|
||||
expect(queryByLabelText('Request method')).not.toBeInTheDocument();
|
||||
expect(getByLabelText('Request payload')).toBeInTheDocument();
|
||||
|
||||
fireEvent.change(monitorType, { target: { value: DataStream.ICMP } });
|
||||
|
||||
// expect ICMP fields to be in the DOM
|
||||
expect(getByLabelText('Wait in seconds')).toBeInTheDocument();
|
||||
|
||||
// expect TCP fields not to be in the DOM
|
||||
expect(queryByLabelText('Proxy URL')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('handles http validation', async () => {
|
||||
const { getByText, getByLabelText, queryByText } = render(<WrappedComponent />);
|
||||
|
||||
const url = getByLabelText('URL') as HTMLInputElement;
|
||||
const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement;
|
||||
const maxRedirects = getByLabelText('Max redirects') as HTMLInputElement;
|
||||
const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement;
|
||||
|
||||
// create errors
|
||||
fireEvent.change(monitorIntervalNumber, { target: { value: '-1' } });
|
||||
fireEvent.change(maxRedirects, { target: { value: '-1' } });
|
||||
fireEvent.change(timeout, { target: { value: '-1' } });
|
||||
|
||||
const urlError = getByText('URL is required');
|
||||
const monitorIntervalError = getByText('Monitor frequency is required');
|
||||
const maxRedirectsError = getByText('Max redirects must be 0 or greater');
|
||||
const timeoutError = getByText('Timeout must be greater than or equal to 0');
|
||||
|
||||
expect(urlError).toBeInTheDocument();
|
||||
expect(monitorIntervalError).toBeInTheDocument();
|
||||
expect(maxRedirectsError).toBeInTheDocument();
|
||||
expect(timeoutError).toBeInTheDocument();
|
||||
|
||||
// expect onChange to be called with isValid false
|
||||
await waitFor(() => {
|
||||
expect(onChange).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
isValid: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// resolve errors
|
||||
fireEvent.change(url, { target: { value: 'http://elastic.co' } });
|
||||
fireEvent.change(monitorIntervalNumber, { target: { value: '1' } });
|
||||
fireEvent.change(maxRedirects, { target: { value: '1' } });
|
||||
fireEvent.change(timeout, { target: { value: '1' } });
|
||||
|
||||
// expect onChange to be called with isValid true
|
||||
await waitFor(() => {
|
||||
expect(queryByText('URL is required')).not.toBeInTheDocument();
|
||||
expect(queryByText('Monitor frequency is required')).not.toBeInTheDocument();
|
||||
expect(queryByText('Max redirects must be 0 or greater')).not.toBeInTheDocument();
|
||||
expect(queryByText('Timeout must be greater than or equal to 0')).not.toBeInTheDocument();
|
||||
expect(onChange).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
isValid: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles tcp validation', async () => {
|
||||
const { getByText, getByLabelText, queryByText } = render(<WrappedComponent />);
|
||||
|
||||
const monitorType = getByLabelText('Monitor Type') as HTMLInputElement;
|
||||
fireEvent.change(monitorType, { target: { value: DataStream.TCP } });
|
||||
|
||||
const host = getByLabelText('Host:Port') as HTMLInputElement;
|
||||
const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement;
|
||||
const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement;
|
||||
|
||||
// create errors
|
||||
fireEvent.change(host, { target: { value: 'localhost' } }); // host without port
|
||||
fireEvent.change(monitorIntervalNumber, { target: { value: '-1' } });
|
||||
fireEvent.change(timeout, { target: { value: '-1' } });
|
||||
|
||||
await waitFor(() => {
|
||||
const hostError = getByText('Host and port are required');
|
||||
const monitorIntervalError = getByText('Monitor frequency 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,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// resolve errors
|
||||
fireEvent.change(host, { target: { value: 'smtp.gmail.com:587' } });
|
||||
fireEvent.change(monitorIntervalNumber, { target: { value: '1' } });
|
||||
fireEvent.change(timeout, { target: { value: '1' } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByText('Host and port are required')).not.toBeInTheDocument();
|
||||
expect(queryByText('Monitor frequency is required')).not.toBeInTheDocument();
|
||||
expect(queryByText('Max redirects must be 0 or greater')).not.toBeInTheDocument();
|
||||
expect(queryByText('Timeout must be greater than or equal to 0')).not.toBeInTheDocument();
|
||||
expect(onChange).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
isValid: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles icmp validation', async () => {
|
||||
const { getByText, getByLabelText, queryByText } = render(<WrappedComponent />);
|
||||
|
||||
const monitorType = getByLabelText('Monitor Type') as HTMLInputElement;
|
||||
fireEvent.change(monitorType, { target: { value: DataStream.ICMP } });
|
||||
|
||||
const host = getByLabelText('Host') as HTMLInputElement;
|
||||
const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement;
|
||||
const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement;
|
||||
const wait = getByLabelText('Wait in seconds') as HTMLInputElement;
|
||||
|
||||
// create errors
|
||||
fireEvent.change(host, { target: { value: '' } });
|
||||
fireEvent.change(monitorIntervalNumber, { target: { value: '-1' } });
|
||||
fireEvent.change(timeout, { target: { value: '-1' } });
|
||||
fireEvent.change(wait, { target: { value: '-1' } });
|
||||
|
||||
await waitFor(() => {
|
||||
const hostError = getByText('Host is required');
|
||||
const monitorIntervalError = getByText('Monitor frequency is required');
|
||||
const timeoutError = getByText('Timeout must be greater than or equal to 0');
|
||||
const waitError = getByText('Wait must be 0 or greater');
|
||||
|
||||
expect(hostError).toBeInTheDocument();
|
||||
expect(monitorIntervalError).toBeInTheDocument();
|
||||
expect(timeoutError).toBeInTheDocument();
|
||||
expect(waitError).toBeInTheDocument();
|
||||
expect(onChange).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
isValid: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// resolve errors
|
||||
fireEvent.change(host, { target: { value: '1.1.1.1' } });
|
||||
fireEvent.change(monitorIntervalNumber, { target: { value: '1' } });
|
||||
fireEvent.change(timeout, { target: { value: '1' } });
|
||||
fireEvent.change(wait, { target: { value: '1' } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByText('Host is required')).not.toBeInTheDocument();
|
||||
expect(queryByText('Monitor frequency is required')).not.toBeInTheDocument();
|
||||
expect(queryByText('Timeout must be greater than or equal to 0')).not.toBeInTheDocument();
|
||||
expect(queryByText('Wait must be 0 or greater')).not.toBeInTheDocument();
|
||||
expect(onChange).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
isValid: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles browser validation', async () => {
|
||||
const { getByText, getByLabelText, queryByText, getByRole, getByTestId } = render(
|
||||
<WrappedComponent />
|
||||
);
|
||||
|
||||
const monitorType = getByLabelText('Monitor Type') as HTMLInputElement;
|
||||
fireEvent.change(monitorType, { target: { value: DataStream.BROWSER } });
|
||||
|
||||
const zip = getByTestId('syntheticsSourceTab__zipUrl');
|
||||
fireEvent.click(zip);
|
||||
const zipUrl = getByRole('textbox', { name: 'Zip URL' }) as HTMLInputElement;
|
||||
const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement;
|
||||
|
||||
// create errors
|
||||
fireEvent.change(zipUrl, { target: { value: '' } });
|
||||
fireEvent.change(monitorIntervalNumber, { target: { value: '-1' } });
|
||||
|
||||
await waitFor(() => {
|
||||
const hostError = getByText('Zip URL is required');
|
||||
const monitorIntervalError = getByText('Monitor frequency is required');
|
||||
|
||||
expect(hostError).toBeInTheDocument();
|
||||
expect(monitorIntervalError).toBeInTheDocument();
|
||||
expect(onChange).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
isValid: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// resolve errors
|
||||
fireEvent.change(zipUrl, { target: { value: 'http://github.com/tests.zip' } });
|
||||
fireEvent.change(monitorIntervalNumber, { target: { value: '1' } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByText('Zip URL is required')).not.toBeInTheDocument();
|
||||
expect(queryByText('Monitor frequency is required')).not.toBeInTheDocument();
|
||||
expect(onChange).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
isValid: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// test inline script validation
|
||||
fireEvent.click(getByText('Inline script'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('Script is required')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('handles changing TLS fields', async () => {
|
||||
const { findByLabelText, queryByLabelText } = render(<WrappedComponent />);
|
||||
const enableSSL = queryByLabelText('Enable TLS configuration') as HTMLInputElement;
|
||||
|
||||
// ensure at least one http advanced option is present
|
||||
fireEvent.click(enableSSL);
|
||||
|
||||
const ca = (await findByLabelText('Certificate authorities')) as HTMLInputElement;
|
||||
const clientKey = (await findByLabelText('Client key')) as HTMLInputElement;
|
||||
const clientKeyPassphrase = (await findByLabelText(
|
||||
'Client key passphrase'
|
||||
)) as HTMLInputElement;
|
||||
const clientCertificate = (await findByLabelText('Client certificate')) as HTMLInputElement;
|
||||
const verificationMode = (await findByLabelText('Verification mode')) as HTMLInputElement;
|
||||
|
||||
await waitFor(() => {
|
||||
fireEvent.change(ca, { target: { value: 'certificateAuthorities' } });
|
||||
expect(ca.value).toEqual(defaultHTTPConfig[ConfigKey.TLS_CERTIFICATE_AUTHORITIES]);
|
||||
});
|
||||
await waitFor(() => {
|
||||
fireEvent.change(clientCertificate, { target: { value: 'clientCertificate' } });
|
||||
expect(clientCertificate.value).toEqual(defaultHTTPConfig[ConfigKey.TLS_KEY]);
|
||||
});
|
||||
await waitFor(() => {
|
||||
fireEvent.change(clientKey, { target: { value: 'clientKey' } });
|
||||
expect(clientKey.value).toEqual(defaultHTTPConfig[ConfigKey.TLS_KEY]);
|
||||
});
|
||||
await waitFor(() => {
|
||||
fireEvent.change(clientKeyPassphrase, { target: { value: 'clientKeyPassphrase' } });
|
||||
expect(clientKeyPassphrase.value).toEqual(defaultHTTPConfig[ConfigKey.TLS_KEY_PASSPHRASE]);
|
||||
});
|
||||
await waitFor(() => {
|
||||
fireEvent.change(verificationMode, { target: { value: VerificationMode.NONE } });
|
||||
expect(verificationMode.value).toEqual(defaultHTTPConfig[ConfigKey.TLS_VERIFICATION_MODE]);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(onChange).toBeCalledWith({
|
||||
isValid: false,
|
||||
updatedPolicy: {
|
||||
...defaultNewPolicy,
|
||||
inputs: [
|
||||
{
|
||||
...defaultNewPolicy.inputs[0],
|
||||
streams: [
|
||||
{
|
||||
...defaultNewPolicy.inputs[0].streams[0],
|
||||
vars: {
|
||||
...defaultNewPolicy.inputs[0].streams[0].vars,
|
||||
[ConfigKey.TLS_CERTIFICATE_AUTHORITIES]: {
|
||||
value: '"certificateAuthorities"',
|
||||
type: 'yaml',
|
||||
},
|
||||
[ConfigKey.TLS_CERTIFICATE]: {
|
||||
value: '"clientCertificate"',
|
||||
type: 'yaml',
|
||||
},
|
||||
[ConfigKey.TLS_KEY]: {
|
||||
value: '"clientKey"',
|
||||
type: 'yaml',
|
||||
},
|
||||
[ConfigKey.TLS_KEY_PASSPHRASE]: {
|
||||
value: 'clientKeyPassphrase',
|
||||
type: 'text',
|
||||
},
|
||||
[ConfigKey.TLS_VERIFICATION_MODE]: {
|
||||
value: VerificationMode.NONE,
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultNewPolicy.inputs[1],
|
||||
defaultNewPolicy.inputs[2],
|
||||
defaultNewPolicy.inputs[3],
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -27,7 +27,7 @@ export function useMonitorList() {
|
|||
|
||||
const { pageIndex, pageSize, sortField, sortOrder } = pageState as MonitorManagementListPageState;
|
||||
|
||||
const { type: viewType } = useParams<{ type: 'all' | 'invalid' }>();
|
||||
const { type: viewType = 'all' } = useParams<{ type: 'all' | 'invalid' }>();
|
||||
|
||||
useEffect(() => {
|
||||
if (viewType === 'all') {
|
||||
|
|
|
@ -48,19 +48,22 @@ export const EmptyLocations = ({
|
|||
}
|
||||
footer={
|
||||
<EuiText size="s">
|
||||
{LEARN_MORE}{' '}
|
||||
<EuiLink
|
||||
href="https://www.elastic.co/guide/en/observability/current/uptime-set-up-choose-agent.html#private-locations"
|
||||
target="_blank"
|
||||
>
|
||||
{READ_DOCS}
|
||||
</EuiLink>
|
||||
{LEARN_MORE} <PrivateLocationDocsLink />
|
||||
</EuiText>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const PrivateLocationDocsLink = ({ label }: { label?: string }) => (
|
||||
<EuiLink
|
||||
href="https://www.elastic.co/guide/en/observability/current/uptime-set-up-choose-agent.html#private-locations"
|
||||
target="_blank"
|
||||
>
|
||||
{label ?? READ_DOCS}
|
||||
</EuiLink>
|
||||
);
|
||||
|
||||
const FIRST_MONITOR = i18n.translate('xpack.synthetics.monitorManagement.firstLocationMonitor', {
|
||||
defaultMessage: 'In order to create a monitor, you will need to add a location first.',
|
||||
});
|
||||
|
|
|
@ -35,7 +35,7 @@ export const MonitorListTabs = ({
|
|||
|
||||
const history = useHistory();
|
||||
|
||||
const { type: viewType } = useParams<{ type: 'all' | 'invalid' }>();
|
||||
const { type: viewType = 'all' } = useParams<{ type: 'all' | 'invalid' }>();
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedTabId(viewType);
|
||||
|
@ -52,7 +52,7 @@ export const MonitorListTabs = ({
|
|||
id: 'all',
|
||||
name: ALL_MONITORS_LABEL,
|
||||
content: <Fragment />,
|
||||
href: history.createHref({ pathname: '/manage-monitors/all' }),
|
||||
href: history.createHref({ pathname: '/manage-monitors' }),
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -46,7 +46,7 @@ export const MonitorListContainer = ({
|
|||
|
||||
const monitorList = useSelector(monitorManagementListSelector);
|
||||
|
||||
const { type: viewType } = useParams<{ type: 'all' | 'invalid' }>();
|
||||
const { type: viewType = 'all' } = useParams<{ type: 'all' | 'invalid' }>();
|
||||
const { errorSummaries, loading, count } = useInlineErrors({
|
||||
onlyInvalidMonitors: viewType === 'invalid',
|
||||
sortField: pageState.sortField,
|
||||
|
|
|
@ -240,7 +240,7 @@ const getRoutes = (): RouteProps[] => {
|
|||
defaultMessage: 'Monitor Management | {baseTitle}',
|
||||
values: { baseTitle },
|
||||
}),
|
||||
path: MONITOR_MANAGEMENT_ROUTE + '/:type',
|
||||
path: MONITOR_MANAGEMENT_ROUTE + '/:type?',
|
||||
component: () => (
|
||||
<ServiceAllowedWrapper>
|
||||
<MonitorManagementPage />
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# Kibana Functional Testing
|
||||
|
||||
See our [Functional Testing Guide](https://www.elastic.co/guide/en/kibana/current/development-tests.html#development-functional-tests)
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default ({ loadTestFile, getService }: FtrProviderContext) => {
|
||||
describe('Uptime app', function () {
|
||||
describe('with generated data', () => {
|
||||
loadTestFile(require.resolve('./synthetics_integration'));
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,772 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FullAgentPolicy } from '@kbn/fleet-plugin/common';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { skipIfNoDockerRegistry } from '../../helpers';
|
||||
|
||||
export default function (providerContext: FtrProviderContext) {
|
||||
const { getPageObjects, getService } = providerContext;
|
||||
const monitorName = 'Sample Synthetics integration';
|
||||
|
||||
const uptimePage = getPageObjects(['syntheticsIntegration']);
|
||||
const testSubjects = getService('testSubjects');
|
||||
const uptimeService = getService('uptime');
|
||||
|
||||
const getSyntheticsPolicy = (agentFullPolicy: FullAgentPolicy) =>
|
||||
agentFullPolicy.inputs.find((input) => input.meta?.package?.name === 'synthetics');
|
||||
|
||||
const generatePolicy = ({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
monitorType,
|
||||
name,
|
||||
config,
|
||||
}: {
|
||||
agentFullPolicy: FullAgentPolicy;
|
||||
version: string;
|
||||
monitorType: string;
|
||||
name: string;
|
||||
config: Record<string, any>;
|
||||
}) => ({
|
||||
data_stream: {
|
||||
namespace: 'default',
|
||||
},
|
||||
id: getSyntheticsPolicy(agentFullPolicy)?.id,
|
||||
meta: {
|
||||
package: {
|
||||
name: 'synthetics',
|
||||
version,
|
||||
},
|
||||
},
|
||||
name,
|
||||
package_policy_id: getSyntheticsPolicy(agentFullPolicy)?.package_policy_id,
|
||||
revision: 1,
|
||||
streams: [
|
||||
{
|
||||
data_stream: {
|
||||
dataset: monitorType,
|
||||
elasticsearch: {
|
||||
privileges: {
|
||||
indices: ['auto_configure', 'create_doc', 'read'],
|
||||
},
|
||||
},
|
||||
type: 'synthetics',
|
||||
},
|
||||
id: `${getSyntheticsPolicy(agentFullPolicy)?.streams?.[0]?.id}`,
|
||||
name,
|
||||
type: monitorType,
|
||||
enabled: true,
|
||||
processors: [
|
||||
{
|
||||
add_observer_metadata: {
|
||||
geo: {
|
||||
name: 'Fleet managed',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
add_fields: {
|
||||
fields: {
|
||||
'monitor.fleet_managed': true,
|
||||
},
|
||||
target: '',
|
||||
},
|
||||
},
|
||||
],
|
||||
...config,
|
||||
},
|
||||
...(monitorType === 'browser'
|
||||
? [
|
||||
{
|
||||
data_stream: {
|
||||
dataset: 'browser.network',
|
||||
elasticsearch: {
|
||||
privileges: {
|
||||
indices: ['auto_configure', 'create_doc', 'read'],
|
||||
},
|
||||
},
|
||||
type: 'synthetics',
|
||||
},
|
||||
id: `${getSyntheticsPolicy(agentFullPolicy)?.streams?.[1]?.id}`,
|
||||
processors: [
|
||||
{
|
||||
add_observer_metadata: {
|
||||
geo: {
|
||||
name: 'Fleet managed',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
add_fields: {
|
||||
fields: {
|
||||
'monitor.fleet_managed': true,
|
||||
},
|
||||
target: '',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
data_stream: {
|
||||
dataset: 'browser.screenshot',
|
||||
elasticsearch: {
|
||||
privileges: {
|
||||
indices: ['auto_configure', 'create_doc', 'read'],
|
||||
},
|
||||
},
|
||||
type: 'synthetics',
|
||||
},
|
||||
id: `${getSyntheticsPolicy(agentFullPolicy)?.streams?.[2]?.id}`,
|
||||
processors: [
|
||||
{
|
||||
add_observer_metadata: {
|
||||
geo: {
|
||||
name: 'Fleet managed',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
add_fields: {
|
||||
fields: {
|
||||
'monitor.fleet_managed': true,
|
||||
},
|
||||
target: '',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
type: `synthetics/${monitorType}`,
|
||||
use_output: 'default',
|
||||
});
|
||||
|
||||
describe('When on the Synthetics Integration Policy Create Page', function () {
|
||||
skipIfNoDockerRegistry(providerContext);
|
||||
const basicConfig = {
|
||||
name: monitorName,
|
||||
apmServiceName: 'Sample APM Service',
|
||||
tags: 'sample tag',
|
||||
};
|
||||
|
||||
const generateHTTPConfig = (url: string) => ({
|
||||
...basicConfig,
|
||||
url,
|
||||
});
|
||||
|
||||
const generateTCPorICMPConfig = (host: string) => ({
|
||||
...basicConfig,
|
||||
host,
|
||||
});
|
||||
|
||||
const generateBrowserConfig = (config: Record<string, string>): Record<string, string> => ({
|
||||
...basicConfig,
|
||||
...config,
|
||||
});
|
||||
|
||||
describe('displays custom UI', () => {
|
||||
before(async () => {
|
||||
const version = await uptimeService.syntheticsPackage.getSyntheticsPackageVersion();
|
||||
await uptimePage.syntheticsIntegration.navigateToPackagePage(version!);
|
||||
});
|
||||
|
||||
it('should display policy view', async () => {
|
||||
await uptimePage.syntheticsIntegration.ensureIsOnPackagePage();
|
||||
});
|
||||
|
||||
it('prevent saving when integration name, url/host, or schedule is missing', async () => {
|
||||
const saveButton = await uptimePage.syntheticsIntegration.findSaveButton();
|
||||
await saveButton.click();
|
||||
|
||||
await testSubjects.missingOrFail('postInstallAddAgentModal');
|
||||
});
|
||||
});
|
||||
|
||||
describe('create new policy', () => {
|
||||
let version: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
version = (await uptimeService.syntheticsPackage.getSyntheticsPackageVersion())!;
|
||||
await uptimePage.syntheticsIntegration.navigateToPackagePage(version!);
|
||||
await uptimeService.syntheticsPackage.deletePolicyByName(monitorName);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await uptimeService.syntheticsPackage.deletePolicyByName(monitorName);
|
||||
});
|
||||
|
||||
it('allows saving when user enters a valid integration name and url/host', async () => {
|
||||
// This test ensures that updates made to the Synthetics Policy are carried all the way through
|
||||
// to the generated Agent Policy that is dispatch down to the Elastic Agent.
|
||||
const config = generateHTTPConfig('http://elastic.co');
|
||||
await uptimePage.syntheticsIntegration.createBasicHTTPMonitorDetails(config);
|
||||
await uptimePage.syntheticsIntegration.confirmAndSave();
|
||||
|
||||
await uptimePage.syntheticsIntegration.isPolicyCreatedSuccessfully();
|
||||
|
||||
const [agentPolicy] = await uptimeService.syntheticsPackage.getAgentPolicyList();
|
||||
const agentPolicyId = agentPolicy.id;
|
||||
const agentFullPolicy = await uptimeService.syntheticsPackage.getFullAgentPolicy(
|
||||
agentPolicyId
|
||||
);
|
||||
|
||||
expect(getSyntheticsPolicy(agentFullPolicy)).to.eql(
|
||||
generatePolicy({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
name: monitorName,
|
||||
monitorType: 'http',
|
||||
config: {
|
||||
max_redirects: 0,
|
||||
'response.include_body': 'on_error',
|
||||
'response.include_headers': true,
|
||||
schedule: '@every 3m',
|
||||
timeout: '16s',
|
||||
urls: config.url,
|
||||
'service.name': config.apmServiceName,
|
||||
tags: [config.tags],
|
||||
'check.request.method': 'GET',
|
||||
__ui: {
|
||||
is_tls_enabled: false,
|
||||
is_zip_url_tls_enabled: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('allows enabling tls with defaults', async () => {
|
||||
// This test ensures that updates made to the Synthetics Policy are carried all the way through
|
||||
// to the generated Agent Policy that is dispatch down to the Elastic Agent.
|
||||
const config = generateHTTPConfig('http://elastic.co');
|
||||
|
||||
await uptimePage.syntheticsIntegration.createBasicHTTPMonitorDetails(config);
|
||||
await uptimePage.syntheticsIntegration.enableTLS();
|
||||
await uptimePage.syntheticsIntegration.confirmAndSave();
|
||||
|
||||
await uptimePage.syntheticsIntegration.isPolicyCreatedSuccessfully();
|
||||
|
||||
const [agentPolicy] = await uptimeService.syntheticsPackage.getAgentPolicyList();
|
||||
const agentPolicyId = agentPolicy.id;
|
||||
const agentFullPolicy = await uptimeService.syntheticsPackage.getFullAgentPolicy(
|
||||
agentPolicyId
|
||||
);
|
||||
|
||||
expect(
|
||||
agentFullPolicy.inputs.find((input) => input.meta?.package?.name === 'synthetics')
|
||||
).to.eql(
|
||||
generatePolicy({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
name: monitorName,
|
||||
monitorType: 'http',
|
||||
config: {
|
||||
max_redirects: 0,
|
||||
'check.request.method': 'GET',
|
||||
'response.include_body': 'on_error',
|
||||
'response.include_headers': true,
|
||||
schedule: '@every 3m',
|
||||
'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'],
|
||||
'ssl.verification_mode': 'full',
|
||||
timeout: '16s',
|
||||
urls: config.url,
|
||||
'service.name': config.apmServiceName,
|
||||
tags: [config.tags],
|
||||
__ui: {
|
||||
is_tls_enabled: true,
|
||||
is_zip_url_tls_enabled: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('allows configuring tls', async () => {
|
||||
// This test ensures that updates made to the Synthetics Policy are carried all the way through
|
||||
// to the generated Agent Policy that is dispatch down to the Elastic Agent.
|
||||
const config = generateHTTPConfig('http://elastic.co');
|
||||
|
||||
const tlsConfig = {
|
||||
verificationMode: 'strict',
|
||||
ca: 'ca',
|
||||
cert: 'cert',
|
||||
certKey: 'certKey',
|
||||
certKeyPassphrase: 'certKeyPassphrase',
|
||||
};
|
||||
await uptimePage.syntheticsIntegration.createBasicHTTPMonitorDetails(config);
|
||||
await uptimePage.syntheticsIntegration.configureTLSOptions(tlsConfig);
|
||||
await uptimePage.syntheticsIntegration.confirmAndSave();
|
||||
|
||||
await uptimePage.syntheticsIntegration.isPolicyCreatedSuccessfully();
|
||||
|
||||
const [agentPolicy] = await uptimeService.syntheticsPackage.getAgentPolicyList();
|
||||
const agentPolicyId = agentPolicy.id;
|
||||
const agentFullPolicy = await uptimeService.syntheticsPackage.getFullAgentPolicy(
|
||||
agentPolicyId
|
||||
);
|
||||
|
||||
expect(getSyntheticsPolicy(agentFullPolicy)).to.eql(
|
||||
generatePolicy({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
name: monitorName,
|
||||
monitorType: 'http',
|
||||
config: {
|
||||
max_redirects: 0,
|
||||
'check.request.method': 'GET',
|
||||
'response.include_body': 'on_error',
|
||||
'response.include_headers': true,
|
||||
schedule: '@every 3m',
|
||||
'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'],
|
||||
'ssl.verification_mode': tlsConfig.verificationMode,
|
||||
'ssl.certificate': tlsConfig.cert,
|
||||
'ssl.certificate_authorities': tlsConfig.ca,
|
||||
'ssl.key': tlsConfig.certKey,
|
||||
'ssl.key_passphrase': tlsConfig.certKeyPassphrase,
|
||||
timeout: '16s',
|
||||
urls: config.url,
|
||||
'service.name': config.apmServiceName,
|
||||
tags: [config.tags],
|
||||
__ui: {
|
||||
is_tls_enabled: true,
|
||||
is_zip_url_tls_enabled: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('allows configuring http advanced options', async () => {
|
||||
// This test ensures that updates made to the Synthetics Policy are carried all the way through
|
||||
// to the generated Agent Policy that is dispatch down to the Elastic Agent.
|
||||
const config = generateHTTPConfig('http://elastic.co');
|
||||
|
||||
await uptimePage.syntheticsIntegration.createBasicHTTPMonitorDetails(config);
|
||||
const advancedConfig = {
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
proxyUrl: 'proxyUrl',
|
||||
requestMethod: 'POST',
|
||||
responseStatusCheck: '204',
|
||||
responseBodyCheckPositive: 'success',
|
||||
responseBodyCheckNegative: 'failure',
|
||||
requestHeaders: {
|
||||
sampleRequestHeader1: 'sampleRequestKey1',
|
||||
sampleRequestHeader2: 'sampleRequestKey2',
|
||||
},
|
||||
responseHeaders: {
|
||||
sampleResponseHeader1: 'sampleResponseKey1',
|
||||
sampleResponseHeader2: 'sampleResponseKey2',
|
||||
},
|
||||
requestBody: {
|
||||
type: 'xml',
|
||||
value: '<samplexml>samplexml<samplexml>',
|
||||
},
|
||||
indexResponseBody: false,
|
||||
indexResponseHeaders: false,
|
||||
};
|
||||
await uptimePage.syntheticsIntegration.configureHTTPAdvancedOptions(advancedConfig);
|
||||
await uptimePage.syntheticsIntegration.confirmAndSave();
|
||||
|
||||
await uptimePage.syntheticsIntegration.isPolicyCreatedSuccessfully();
|
||||
|
||||
const [agentPolicy] = await uptimeService.syntheticsPackage.getAgentPolicyList();
|
||||
const agentPolicyId = agentPolicy.id;
|
||||
const agentFullPolicy = await uptimeService.syntheticsPackage.getFullAgentPolicy(
|
||||
agentPolicyId
|
||||
);
|
||||
|
||||
expect(getSyntheticsPolicy(agentFullPolicy)).to.eql(
|
||||
generatePolicy({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
name: monitorName,
|
||||
monitorType: 'http',
|
||||
config: {
|
||||
max_redirects: 0,
|
||||
'check.request.method': advancedConfig.requestMethod,
|
||||
'check.request.headers': {
|
||||
'Content-Type': 'application/xml',
|
||||
...advancedConfig.requestHeaders,
|
||||
},
|
||||
'check.response.headers': advancedConfig.responseHeaders,
|
||||
'check.response.status': [advancedConfig.responseStatusCheck],
|
||||
'check.request.body': advancedConfig.requestBody.value,
|
||||
'check.response.body.positive': [advancedConfig.responseBodyCheckPositive],
|
||||
'check.response.body.negative': [advancedConfig.responseBodyCheckNegative],
|
||||
'response.include_body': advancedConfig.indexResponseBody ? 'on_error' : 'never',
|
||||
'response.include_headers': advancedConfig.indexResponseHeaders,
|
||||
schedule: '@every 3m',
|
||||
timeout: '16s',
|
||||
urls: config.url,
|
||||
proxy_url: advancedConfig.proxyUrl,
|
||||
username: advancedConfig.username,
|
||||
password: advancedConfig.password,
|
||||
'service.name': config.apmServiceName,
|
||||
tags: [config.tags],
|
||||
__ui: {
|
||||
is_tls_enabled: false,
|
||||
is_zip_url_tls_enabled: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('allows saving tcp monitor when user enters a valid integration name and host+port', async () => {
|
||||
// This test ensures that updates made to the Synthetics Policy are carried all the way through
|
||||
// to the generated Agent Policy that is dispatch down to the Elastic Agent.
|
||||
const config = generateTCPorICMPConfig('smtp.gmail.com:587');
|
||||
|
||||
await uptimePage.syntheticsIntegration.createBasicTCPMonitorDetails(config);
|
||||
await uptimePage.syntheticsIntegration.confirmAndSave();
|
||||
|
||||
await uptimePage.syntheticsIntegration.isPolicyCreatedSuccessfully();
|
||||
|
||||
const [agentPolicy] = await uptimeService.syntheticsPackage.getAgentPolicyList();
|
||||
const agentPolicyId = agentPolicy.id;
|
||||
const agentFullPolicy = await uptimeService.syntheticsPackage.getFullAgentPolicy(
|
||||
agentPolicyId
|
||||
);
|
||||
|
||||
expect(getSyntheticsPolicy(agentFullPolicy)).to.eql(
|
||||
generatePolicy({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
name: monitorName,
|
||||
monitorType: 'tcp',
|
||||
config: {
|
||||
proxy_use_local_resolver: false,
|
||||
schedule: '@every 3m',
|
||||
timeout: '16s',
|
||||
hosts: config.host,
|
||||
tags: [config.tags],
|
||||
'service.name': config.apmServiceName,
|
||||
__ui: {
|
||||
is_tls_enabled: false,
|
||||
is_zip_url_tls_enabled: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('allows configuring tcp advanced options', async () => {
|
||||
// This test ensures that updates made to the Synthetics Policy are carried all the way through
|
||||
// to the generated Agent Policy that is dispatch down to the Elastic Agent.
|
||||
const config = generateTCPorICMPConfig('smtp.gmail.com:587');
|
||||
|
||||
await uptimePage.syntheticsIntegration.createBasicTCPMonitorDetails(config);
|
||||
const advancedConfig = {
|
||||
proxyUrl: 'proxyUrl',
|
||||
requestSendCheck: 'body',
|
||||
responseReceiveCheck: 'success',
|
||||
proxyUseLocalResolver: true,
|
||||
};
|
||||
await uptimePage.syntheticsIntegration.configureTCPAdvancedOptions(advancedConfig);
|
||||
await uptimePage.syntheticsIntegration.confirmAndSave();
|
||||
|
||||
await uptimePage.syntheticsIntegration.isPolicyCreatedSuccessfully();
|
||||
|
||||
const [agentPolicy] = await uptimeService.syntheticsPackage.getAgentPolicyList();
|
||||
const agentPolicyId = agentPolicy.id;
|
||||
const agentFullPolicy = await uptimeService.syntheticsPackage.getFullAgentPolicy(
|
||||
agentPolicyId
|
||||
);
|
||||
|
||||
expect(getSyntheticsPolicy(agentFullPolicy)).to.eql(
|
||||
generatePolicy({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
name: monitorName,
|
||||
monitorType: 'tcp',
|
||||
config: {
|
||||
schedule: '@every 3m',
|
||||
timeout: '16s',
|
||||
hosts: config.host,
|
||||
proxy_url: advancedConfig.proxyUrl,
|
||||
proxy_use_local_resolver: advancedConfig.proxyUseLocalResolver,
|
||||
'check.receive': advancedConfig.responseReceiveCheck,
|
||||
'check.send': advancedConfig.requestSendCheck,
|
||||
'service.name': config.apmServiceName,
|
||||
tags: [config.tags],
|
||||
__ui: {
|
||||
is_tls_enabled: false,
|
||||
is_zip_url_tls_enabled: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('allows saving icmp monitor when user enters a valid integration name and host', async () => {
|
||||
// This test ensures that updates made to the Synthetics Policy are carried all the way through
|
||||
// to the generated Agent Policy that is dispatch down to the Elastic Agent.
|
||||
const config = generateTCPorICMPConfig('1.1.1.1');
|
||||
|
||||
await uptimePage.syntheticsIntegration.createBasicICMPMonitorDetails(config);
|
||||
await uptimePage.syntheticsIntegration.confirmAndSave();
|
||||
|
||||
await uptimePage.syntheticsIntegration.isPolicyCreatedSuccessfully();
|
||||
|
||||
const [agentPolicy] = await uptimeService.syntheticsPackage.getAgentPolicyList();
|
||||
const agentPolicyId = agentPolicy.id;
|
||||
const agentFullPolicy = await uptimeService.syntheticsPackage.getFullAgentPolicy(
|
||||
agentPolicyId
|
||||
);
|
||||
|
||||
expect(getSyntheticsPolicy(agentFullPolicy)).to.eql(
|
||||
generatePolicy({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
name: monitorName,
|
||||
monitorType: 'icmp',
|
||||
config: {
|
||||
schedule: '@every 3m',
|
||||
timeout: '16s',
|
||||
wait: '1s',
|
||||
hosts: config.host,
|
||||
'service.name': config.apmServiceName,
|
||||
tags: [config.tags],
|
||||
__ui: null,
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('allows saving browser monitor', async () => {
|
||||
// This test ensures that updates made to the Synthetics Policy are carried all the way through
|
||||
// to the generated Agent Policy that is dispatch down to the Elastic Agent.
|
||||
const config = generateBrowserConfig({
|
||||
zipUrl: 'http://test.zip',
|
||||
params: JSON.stringify({ url: 'http://localhost:8080' }),
|
||||
folder: 'folder',
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
});
|
||||
|
||||
await uptimePage.syntheticsIntegration.createBasicBrowserMonitorDetails(config);
|
||||
await uptimePage.syntheticsIntegration.confirmAndSave();
|
||||
|
||||
await uptimePage.syntheticsIntegration.isPolicyCreatedSuccessfully();
|
||||
|
||||
const [agentPolicy] = await uptimeService.syntheticsPackage.getAgentPolicyList();
|
||||
const agentPolicyId = agentPolicy.id;
|
||||
const agentFullPolicy = await uptimeService.syntheticsPackage.getFullAgentPolicy(
|
||||
agentPolicyId
|
||||
);
|
||||
|
||||
expect(getSyntheticsPolicy(agentFullPolicy)).to.eql(
|
||||
generatePolicy({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
name: monitorName,
|
||||
monitorType: 'browser',
|
||||
config: {
|
||||
screenshots: 'on',
|
||||
schedule: '@every 10m',
|
||||
timeout: null,
|
||||
tags: [config.tags],
|
||||
throttling: '5d/3u/20l',
|
||||
'service.name': config.apmServiceName,
|
||||
'source.zip_url.url': config.zipUrl,
|
||||
'source.zip_url.folder': config.folder,
|
||||
'source.zip_url.username': config.username,
|
||||
'source.zip_url.password': config.password,
|
||||
params: JSON.parse(config.params),
|
||||
__ui: {
|
||||
is_tls_enabled: false,
|
||||
is_zip_url_tls_enabled: false,
|
||||
script_source: {
|
||||
file_name: '',
|
||||
is_generated_script: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('allows saving browser monitor with inline script', async () => {
|
||||
// This test ensures that updates made to the Synthetics Policy are carried all the way through
|
||||
// to the generated Agent Policy that is dispatch down to the Elastic Agent.
|
||||
const config = generateBrowserConfig({
|
||||
inlineScript:
|
||||
'step("load homepage", async () => { await page.goto(\'https://www.elastic.co\'); });',
|
||||
});
|
||||
|
||||
await uptimePage.syntheticsIntegration.createBasicBrowserMonitorDetails(config, true);
|
||||
await uptimePage.syntheticsIntegration.confirmAndSave();
|
||||
|
||||
await uptimePage.syntheticsIntegration.isPolicyCreatedSuccessfully();
|
||||
|
||||
const [agentPolicy] = await uptimeService.syntheticsPackage.getAgentPolicyList();
|
||||
const agentPolicyId = agentPolicy.id;
|
||||
const agentFullPolicy = await uptimeService.syntheticsPackage.getFullAgentPolicy(
|
||||
agentPolicyId
|
||||
);
|
||||
|
||||
expect(getSyntheticsPolicy(agentFullPolicy)).to.eql(
|
||||
generatePolicy({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
name: monitorName,
|
||||
monitorType: 'browser',
|
||||
config: {
|
||||
screenshots: 'on',
|
||||
schedule: '@every 10m',
|
||||
timeout: null,
|
||||
tags: [config.tags],
|
||||
throttling: '5d/3u/20l',
|
||||
'service.name': config.apmServiceName,
|
||||
'source.inline.script': config.inlineScript,
|
||||
__ui: {
|
||||
is_tls_enabled: false,
|
||||
is_zip_url_tls_enabled: false,
|
||||
script_source: {
|
||||
file_name: '',
|
||||
is_generated_script: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('allows saving browser monitor advanced options', async () => {
|
||||
// This test ensures that updates made to the Synthetics Policy are carried all the way through
|
||||
// to the generated Agent Policy that is dispatch down to the Elastic Agent.
|
||||
const config = generateBrowserConfig({
|
||||
zipUrl: 'http://test.zip',
|
||||
params: JSON.stringify({ url: 'http://localhost:8080' }),
|
||||
folder: 'folder',
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
});
|
||||
|
||||
const advancedConfig = {
|
||||
screenshots: 'off',
|
||||
syntheticsArgs: '-ssBlocks',
|
||||
isThrottlingEnabled: true,
|
||||
downloadSpeed: '1337',
|
||||
uploadSpeed: '1338',
|
||||
latency: '1339',
|
||||
};
|
||||
|
||||
await uptimePage.syntheticsIntegration.createBasicBrowserMonitorDetails(config);
|
||||
await uptimePage.syntheticsIntegration.configureBrowserAdvancedOptions(advancedConfig);
|
||||
await uptimePage.syntheticsIntegration.confirmAndSave();
|
||||
|
||||
await uptimePage.syntheticsIntegration.isPolicyCreatedSuccessfully();
|
||||
|
||||
const [agentPolicy] = await uptimeService.syntheticsPackage.getAgentPolicyList();
|
||||
const agentPolicyId = agentPolicy.id;
|
||||
const agentFullPolicy = await uptimeService.syntheticsPackage.getFullAgentPolicy(
|
||||
agentPolicyId
|
||||
);
|
||||
|
||||
expect(getSyntheticsPolicy(agentFullPolicy)).to.eql(
|
||||
generatePolicy({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
name: monitorName,
|
||||
monitorType: 'browser',
|
||||
config: {
|
||||
screenshots: advancedConfig.screenshots,
|
||||
schedule: '@every 10m',
|
||||
timeout: null,
|
||||
tags: [config.tags],
|
||||
throttling: '1337d/1338u/1339l',
|
||||
'service.name': config.apmServiceName,
|
||||
'source.zip_url.url': config.zipUrl,
|
||||
'source.zip_url.folder': config.folder,
|
||||
'source.zip_url.username': config.username,
|
||||
'source.zip_url.password': config.password,
|
||||
params: JSON.parse(config.params),
|
||||
synthetics_args: [advancedConfig.syntheticsArgs],
|
||||
__ui: {
|
||||
is_tls_enabled: false,
|
||||
is_zip_url_tls_enabled: false,
|
||||
script_source: {
|
||||
file_name: '',
|
||||
is_generated_script: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('allows saving disabling throttling', async () => {
|
||||
// This test ensures that updates made to the Synthetics Policy are carried all the way through
|
||||
// to the generated Agent Policy that is dispatch down to the Elastic Agent.
|
||||
const config = generateBrowserConfig({
|
||||
zipUrl: 'http://test.zip',
|
||||
params: JSON.stringify({ url: 'http://localhost:8080' }),
|
||||
folder: 'folder',
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
});
|
||||
|
||||
const advancedConfig = {
|
||||
screenshots: 'off',
|
||||
syntheticsArgs: '-ssBlocks',
|
||||
isThrottlingEnabled: false,
|
||||
downloadSpeed: '1337',
|
||||
uploadSpeed: '1338',
|
||||
latency: '1339',
|
||||
};
|
||||
|
||||
await uptimePage.syntheticsIntegration.createBasicBrowserMonitorDetails(config);
|
||||
await uptimePage.syntheticsIntegration.configureBrowserAdvancedOptions(advancedConfig);
|
||||
await uptimePage.syntheticsIntegration.confirmAndSave();
|
||||
|
||||
await uptimePage.syntheticsIntegration.isPolicyCreatedSuccessfully();
|
||||
|
||||
const [agentPolicy] = await uptimeService.syntheticsPackage.getAgentPolicyList();
|
||||
const agentPolicyId = agentPolicy.id;
|
||||
const agentFullPolicy = await uptimeService.syntheticsPackage.getFullAgentPolicy(
|
||||
agentPolicyId
|
||||
);
|
||||
|
||||
expect(getSyntheticsPolicy(agentFullPolicy)).to.eql(
|
||||
generatePolicy({
|
||||
agentFullPolicy,
|
||||
version,
|
||||
name: monitorName,
|
||||
monitorType: 'browser',
|
||||
config: {
|
||||
screenshots: advancedConfig.screenshots,
|
||||
schedule: '@every 10m',
|
||||
timeout: null,
|
||||
tags: [config.tags],
|
||||
'service.name': config.apmServiceName,
|
||||
'source.zip_url.url': config.zipUrl,
|
||||
'source.zip_url.folder': config.folder,
|
||||
'source.zip_url.username': config.username,
|
||||
'source.zip_url.password': config.password,
|
||||
params: JSON.parse(config.params),
|
||||
synthetics_args: [advancedConfig.syntheticsArgs],
|
||||
throttling: false,
|
||||
__ui: {
|
||||
is_tls_enabled: false,
|
||||
is_zip_url_tls_enabled: false,
|
||||
script_source: {
|
||||
file_name: '',
|
||||
is_generated_script: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import path, { resolve } from 'path';
|
||||
|
||||
import { defineDockerServersConfig } from '@kbn/test';
|
||||
import { dockerImage as fleetDockerImage } from '../fleet_api_integration/config';
|
||||
|
||||
import { services } from './services';
|
||||
import { pageObjects } from './page_objects';
|
||||
|
||||
// the default export of config files must be a config provider
|
||||
// that returns an object with the projects config values
|
||||
export default async function ({ readConfigFile }) {
|
||||
const registryPort = process.env.FLEET_PACKAGE_REGISTRY_PORT;
|
||||
|
||||
const kibanaCommonConfig = await readConfigFile(
|
||||
require.resolve('../../../test/common/config.js')
|
||||
);
|
||||
const kibanaFunctionalConfig = await readConfigFile(
|
||||
require.resolve('../../../test/functional/config.base.js')
|
||||
);
|
||||
|
||||
// mount the config file for the package registry as well as
|
||||
// the directory containing additional packages into the container
|
||||
const dockerArgs = [
|
||||
'-v',
|
||||
`${path.join(
|
||||
path.dirname(__filename),
|
||||
'./fixtures/package_registry_config.yml'
|
||||
)}:/package-registry/config.yml`,
|
||||
];
|
||||
|
||||
return {
|
||||
// list paths to the files that contain your plugins tests
|
||||
testFiles: [resolve(__dirname, './apps/uptime')],
|
||||
|
||||
services,
|
||||
pageObjects,
|
||||
|
||||
servers: kibanaFunctionalConfig.get('servers'),
|
||||
|
||||
esTestCluster: {
|
||||
license: 'trial',
|
||||
from: 'snapshot',
|
||||
serverArgs: ['path.repo=/tmp/', 'xpack.security.authc.api_key.enabled=true'],
|
||||
},
|
||||
|
||||
kbnTestServer: {
|
||||
...kibanaCommonConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...kibanaCommonConfig.get('kbnTestServer.serverArgs'),
|
||||
'--status.allowAnonymous=true',
|
||||
'--server.uuid=5b2de169-2785-441b-ae8c-186a1936b17d',
|
||||
'--xpack.maps.showMapsInspectorAdapter=true',
|
||||
'--xpack.maps.preserveDrawingBuffer=true',
|
||||
'--xpack.security.encryptionKey="wuGNaIhoMpk5sO4UBxgr3NyW1sFcLgIf"', // server restarts should not invalidate active sessions
|
||||
'--xpack.encryptedSavedObjects.encryptionKey="DkdXazszSCYexXqz4YktBGHCRkV6hyNK"',
|
||||
'--xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled=true',
|
||||
'--savedObjects.maxImportPayloadBytes=10485760', // for OSS test management/_import_objects,
|
||||
...(registryPort ? [`--xpack.fleet.registryUrl=http://localhost:${registryPort}`] : []),
|
||||
],
|
||||
},
|
||||
uiSettings: {
|
||||
defaults: {
|
||||
'accessibility:disableAnimations': true,
|
||||
'dateFormat:tz': 'UTC',
|
||||
},
|
||||
},
|
||||
// the apps section defines the urls that
|
||||
// `PageObjects.common.navigateTo(appKey)` will use.
|
||||
// Merge urls for your plugin with the urls defined in
|
||||
// Kibana's config in order to use this helper
|
||||
apps: {
|
||||
...kibanaFunctionalConfig.get('apps'),
|
||||
fleet: {
|
||||
pathname: '/app/fleet',
|
||||
},
|
||||
},
|
||||
|
||||
// choose where screenshots should be saved
|
||||
screenshots: {
|
||||
directory: resolve(__dirname, 'screenshots'),
|
||||
},
|
||||
|
||||
junit: {
|
||||
reportName: 'Chrome Elastic Synthetics Integration UI Functional Tests',
|
||||
},
|
||||
dockerServers: defineDockerServersConfig({
|
||||
registry: {
|
||||
enabled: !!registryPort,
|
||||
image: fleetDockerImage,
|
||||
portInContainer: 8080,
|
||||
port: registryPort,
|
||||
args: dockerArgs,
|
||||
waitForLogLine: 'package manifests loaded',
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
package_paths:
|
||||
- /packages/package-storage
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { GenericFtrProviderContext, GenericFtrService } from '@kbn/test';
|
||||
|
||||
import { pageObjects } from './page_objects';
|
||||
import { services } from './services';
|
||||
|
||||
export type FtrProviderContext = GenericFtrProviderContext<typeof services, typeof pageObjects>;
|
||||
export class FtrService extends GenericFtrService<FtrProviderContext> {}
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { Context } from 'mocha';
|
||||
import { ToolingLog } from '@kbn/tooling-log';
|
||||
import { FtrProviderContext } from './ftr_provider_context';
|
||||
|
||||
export function warnAndSkipTest(mochaContext: Context, log: ToolingLog) {
|
||||
log.warning(
|
||||
'disabling tests because DockerServers service is not enabled, set FLEET_PACKAGE_REGISTRY_PORT to run them'
|
||||
);
|
||||
mochaContext.skip();
|
||||
}
|
||||
|
||||
export function skipIfNoDockerRegistry(providerContext: FtrProviderContext) {
|
||||
const { getService } = providerContext;
|
||||
const dockerServers = getService('dockerServers');
|
||||
|
||||
const server = dockerServers.get('registry');
|
||||
const log = getService('log');
|
||||
|
||||
beforeEach(function beforeSetupWithDockerRegistry() {
|
||||
if (!server.enabled) {
|
||||
warnAndSkipTest(this, log);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { pageObjects as kibanaFunctionalPageObjects } from '../../../../test/functional/page_objects';
|
||||
|
||||
import { SyntheticsIntegrationPageProvider } from './synthetics_integration_page';
|
||||
|
||||
// just like services, PageObjects are defined as a map of
|
||||
// names to Providers. Merge in Kibana's or pick specific ones
|
||||
export const pageObjects = {
|
||||
...kibanaFunctionalPageObjects,
|
||||
syntheticsIntegration: SyntheticsIntegrationPageProvider,
|
||||
};
|
|
@ -1,483 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper';
|
||||
import { FtrProviderContext } from '../ftr_provider_context';
|
||||
|
||||
export function SyntheticsIntegrationPageProvider({
|
||||
getService,
|
||||
getPageObjects,
|
||||
}: FtrProviderContext) {
|
||||
const pageObjects = getPageObjects(['common', 'header']);
|
||||
const testSubjects = getService('testSubjects');
|
||||
const comboBox = getService('comboBox');
|
||||
|
||||
const fixedFooterHeight = 72; // Size of EuiBottomBar more or less
|
||||
|
||||
return {
|
||||
/**
|
||||
* Navigates to the Synthetics Integration page
|
||||
*
|
||||
*/
|
||||
async navigateToPackagePage(packageVersion: string) {
|
||||
await pageObjects.common.navigateToUrlWithBrowserHistory(
|
||||
'fleet',
|
||||
`/integrations/synthetics-${packageVersion}/add-integration`
|
||||
);
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
},
|
||||
|
||||
async navigateToPackageEditPage(packageId: string, agentId: string) {
|
||||
await pageObjects.common.navigateToUrlWithBrowserHistory(
|
||||
'fleet',
|
||||
`/policies/${agentId}/edit-integration/${packageId}`
|
||||
);
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds and returns the Policy Details Page Save button
|
||||
*/
|
||||
async findSaveButton(isEditPage?: boolean) {
|
||||
await this.ensureIsOnPackagePage();
|
||||
return await testSubjects.find(
|
||||
isEditPage ? 'saveIntegration' : 'createPackagePolicySaveButton'
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds and returns the Policy Details Page Cancel Button
|
||||
*/
|
||||
async findCancelButton() {
|
||||
await this.ensureIsOnPackagePage();
|
||||
return await testSubjects.find('policyDetailsCancelButton');
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if the policy was created successfully by looking for the creation success toast
|
||||
*/
|
||||
async isPolicyCreatedSuccessfully() {
|
||||
await testSubjects.existOrFail('postInstallAddAgentModal');
|
||||
},
|
||||
|
||||
/**
|
||||
* Selects the monitor type
|
||||
* @params {monitorType} the type of monitor, tcp, http, or icmp
|
||||
*/
|
||||
async selectMonitorType(monitorType: string) {
|
||||
await testSubjects.selectValue('syntheticsMonitorTypeField', monitorType);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fills a text input
|
||||
* @params {testSubj} the testSubj of the input to fill
|
||||
* @params {value} the value of the input
|
||||
*/
|
||||
async fillTextInputByTestSubj(testSubj: string, value: string) {
|
||||
const field = await testSubjects.find(testSubj);
|
||||
await field.scrollIntoViewIfNecessary({ bottomOffset: fixedFooterHeight });
|
||||
await field.click();
|
||||
await field.clearValue();
|
||||
await field.type(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fills a text input
|
||||
* @params {testSubj} the testSubj of the input to fill
|
||||
* @params {value} the value of the input
|
||||
*/
|
||||
async fillTextInput(field: WebElementWrapper, value: string) {
|
||||
await field.scrollIntoViewIfNecessary({ bottomOffset: fixedFooterHeight });
|
||||
await field.click();
|
||||
await field.clearValue();
|
||||
await field.type(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fills a text input
|
||||
* @params {testSubj} the testSubj of the comboBox
|
||||
*/
|
||||
async setComboBox(testSubj: string, value: string) {
|
||||
await comboBox.setCustom(`${testSubj} > comboBoxInput`, value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds and returns the HTTP advanced options accordion trigger
|
||||
*/
|
||||
async findHTTPAdvancedOptionsAccordion() {
|
||||
await this.ensureIsOnPackagePage();
|
||||
const accordion = await testSubjects.find('syntheticsHTTPAdvancedFieldsAccordion');
|
||||
return accordion;
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds and returns the enable throttling checkbox
|
||||
*/
|
||||
async findThrottleSwitch() {
|
||||
await this.ensureIsOnPackagePage();
|
||||
return await testSubjects.find('syntheticsBrowserIsThrottlingEnabled');
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds and returns the enable TLS checkbox
|
||||
*/
|
||||
async findEnableTLSSwitch() {
|
||||
await this.ensureIsOnPackagePage();
|
||||
return await testSubjects.find('syntheticsIsTLSEnabled');
|
||||
},
|
||||
|
||||
/**
|
||||
* ensures that the package page is the currently display view
|
||||
*/
|
||||
async ensureIsOnPackagePage() {
|
||||
await testSubjects.existOrFail('monitorSettingsSection');
|
||||
},
|
||||
|
||||
/**
|
||||
* Clicks save button and confirms update on the Policy Details page
|
||||
*/
|
||||
async confirmAndSave(isEditPage?: boolean) {
|
||||
await this.ensureIsOnPackagePage();
|
||||
const saveButton = await this.findSaveButton(isEditPage);
|
||||
await saveButton.click();
|
||||
await this.maybeForceInstall();
|
||||
},
|
||||
|
||||
/**
|
||||
* If the force install modal opens, click force install
|
||||
*/
|
||||
async maybeForceInstall() {
|
||||
const confirmForceInstallModalOpen = await testSubjects.exists('confirmForceInstallModal');
|
||||
|
||||
if (confirmForceInstallModalOpen) {
|
||||
const forceInstallBtn = await testSubjects.find('confirmModalConfirmButton');
|
||||
return forceInstallBtn.click();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fills in the username and password field
|
||||
* @params username {string} the value of the username
|
||||
* @params password {string} the value of the password
|
||||
*/
|
||||
async configureUsernameAndPassword({ username, password }: Record<string, string>) {
|
||||
await this.fillTextInputByTestSubj('syntheticsUsername', username);
|
||||
await this.fillTextInputByTestSubj('syntheticsPassword', password);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Configures request headers
|
||||
* @params headers {string} an object containing desired headers
|
||||
*
|
||||
*/
|
||||
async configureRequestHeaders(headers: Record<string, string>) {
|
||||
await this.configureHeaders('syntheticsRequestHeaders', headers);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Configures response headers
|
||||
* @params headers {string} an object containing desired headers
|
||||
*
|
||||
*/
|
||||
async configureResponseHeaders(headers: Record<string, string>) {
|
||||
await this.configureHeaders('syntheticsResponseHeaders', headers);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Configures headers
|
||||
* @params testSubj {string} test subj
|
||||
* @params headers {string} an object containing desired headers
|
||||
*
|
||||
*/
|
||||
async configureHeaders(testSubj: string, headers: Record<string, string>) {
|
||||
const headersContainer = await testSubjects.find(testSubj);
|
||||
const addHeaderButton = await testSubjects.find(`${testSubj}__button`);
|
||||
const keys = Object.keys(headers);
|
||||
|
||||
await Promise.all(
|
||||
keys.map(async (key, index) => {
|
||||
await addHeaderButton.click();
|
||||
const keyField = await headersContainer.findByCssSelector(
|
||||
`[data-test-subj="keyValuePairsKey${index}"]`
|
||||
);
|
||||
const valueField = await headersContainer.findByCssSelector(
|
||||
`[data-test-subj="keyValuePairsValue${index}"]`
|
||||
);
|
||||
await this.fillTextInput(keyField, key);
|
||||
await this.fillTextInput(valueField, headers[key]);
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Configures request body
|
||||
* @params contentType {string} contentType of the request body
|
||||
* @params value {string} value of the request body
|
||||
*
|
||||
*/
|
||||
async configureRequestBody(testSubj: string, value: string) {
|
||||
await testSubjects.click(`syntheticsRequestBodyTab__${testSubj}`);
|
||||
await this.fillCodeEditor(value);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Fills the monaco code editor
|
||||
* @params value {string} value of code input
|
||||
*
|
||||
*/
|
||||
async fillCodeEditor(value: string) {
|
||||
const codeEditorContainer = await testSubjects.find('codeEditorContainer');
|
||||
const textArea = await codeEditorContainer.findByCssSelector('textarea');
|
||||
await textArea.clearValue();
|
||||
await textArea.type(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates basic common monitor details
|
||||
* @params name {string} the name of the monitor
|
||||
* @params url {string} the url of the monitor
|
||||
*
|
||||
*/
|
||||
async createBasicMonitorDetails({ name, apmServiceName, tags }: Record<string, string>) {
|
||||
await this.fillTextInputByTestSubj('packagePolicyNameInput', name);
|
||||
await this.fillTextInputByTestSubj('syntheticsAPMServiceName', apmServiceName);
|
||||
await this.setComboBox('syntheticsTags', tags);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fills in the fields to create a basic HTTP monitor
|
||||
* @params name {string} the name of the monitor
|
||||
* @params url {string} the url of the monitor
|
||||
*
|
||||
*/
|
||||
async createBasicHTTPMonitorDetails({
|
||||
name,
|
||||
url,
|
||||
apmServiceName,
|
||||
tags,
|
||||
}: Record<string, string>) {
|
||||
await this.createBasicMonitorDetails({ name, apmServiceName, tags });
|
||||
await this.fillTextInputByTestSubj('syntheticsUrlField', url);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fills in the fields to create a basic TCP monitor
|
||||
* @params name {string} the name of the monitor
|
||||
* @params host {string} the host (and port) of the monitor
|
||||
*
|
||||
*/
|
||||
async createBasicTCPMonitorDetails({
|
||||
name,
|
||||
host,
|
||||
apmServiceName,
|
||||
tags,
|
||||
}: Record<string, string>) {
|
||||
await this.selectMonitorType('tcp');
|
||||
await this.createBasicMonitorDetails({ name, apmServiceName, tags });
|
||||
await this.fillTextInputByTestSubj('syntheticsTCPHostField', host);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a basic ICMP monitor
|
||||
* @params name {string} the name of the monitor
|
||||
* @params host {string} the host of the monitor
|
||||
*/
|
||||
async createBasicICMPMonitorDetails({
|
||||
name,
|
||||
host,
|
||||
apmServiceName,
|
||||
tags,
|
||||
}: Record<string, string>) {
|
||||
await this.selectMonitorType('icmp');
|
||||
await this.fillTextInputByTestSubj('packagePolicyNameInput', name);
|
||||
await this.createBasicMonitorDetails({ name, apmServiceName, tags });
|
||||
await this.fillTextInputByTestSubj('syntheticsICMPHostField', host);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a basic browser monitor
|
||||
* @params name {string} the name of the monitor
|
||||
* @params zipUrl {string} the zip url of the synthetics suites
|
||||
*/
|
||||
async createBasicBrowserMonitorDetails(
|
||||
{
|
||||
name,
|
||||
inlineScript,
|
||||
zipUrl,
|
||||
folder,
|
||||
params,
|
||||
username,
|
||||
password,
|
||||
apmServiceName,
|
||||
tags,
|
||||
}: Record<string, string>,
|
||||
isInline: boolean = false
|
||||
) {
|
||||
await this.selectMonitorType('browser');
|
||||
await this.fillTextInputByTestSubj('packagePolicyNameInput', name);
|
||||
await this.createBasicMonitorDetails({ name, apmServiceName, tags });
|
||||
if (isInline) {
|
||||
await testSubjects.click('syntheticsSourceTab__inline');
|
||||
await this.fillCodeEditor(inlineScript);
|
||||
return;
|
||||
} else {
|
||||
await testSubjects.click('syntheticsSourceTab__zipUrl');
|
||||
}
|
||||
await this.fillTextInputByTestSubj('syntheticsBrowserZipUrl', zipUrl);
|
||||
await this.fillTextInputByTestSubj('syntheticsBrowserZipUrlFolder', folder);
|
||||
await this.fillTextInputByTestSubj('syntheticsBrowserZipUrlUsername', username);
|
||||
await this.fillTextInputByTestSubj('syntheticsBrowserZipUrlPassword', password);
|
||||
await this.fillCodeEditor(params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables TLS
|
||||
*/
|
||||
async enableTLS() {
|
||||
const tlsSwitch = await this.findEnableTLSSwitch();
|
||||
await tlsSwitch.click();
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures TLS settings
|
||||
* @params verificationMode {string} the name of the monitor
|
||||
*/
|
||||
async configureTLSOptions({
|
||||
verificationMode,
|
||||
ca,
|
||||
cert,
|
||||
certKey,
|
||||
certKeyPassphrase,
|
||||
}: Record<string, string>) {
|
||||
await this.enableTLS();
|
||||
await testSubjects.selectValue('syntheticsTLSVerificationMode', verificationMode);
|
||||
await this.fillTextInputByTestSubj('syntheticsTLSCA', ca);
|
||||
await this.fillTextInputByTestSubj('syntheticsTLSCert', cert);
|
||||
await this.fillTextInputByTestSubj('syntheticsTLSCertKey', certKey);
|
||||
await this.fillTextInputByTestSubj('syntheticsTLSCertKeyPassphrase', certKeyPassphrase);
|
||||
},
|
||||
|
||||
/**
|
||||
* Configure http advanced settings
|
||||
*/
|
||||
async configureHTTPAdvancedOptions({
|
||||
username,
|
||||
password,
|
||||
proxyUrl,
|
||||
requestMethod,
|
||||
requestHeaders,
|
||||
responseStatusCheck,
|
||||
responseBodyCheckPositive,
|
||||
responseBodyCheckNegative,
|
||||
requestBody,
|
||||
responseHeaders,
|
||||
indexResponseBody,
|
||||
indexResponseHeaders,
|
||||
}: {
|
||||
username: string;
|
||||
password: string;
|
||||
proxyUrl: string;
|
||||
requestMethod: string;
|
||||
responseStatusCheck: string;
|
||||
responseBodyCheckPositive: string;
|
||||
responseBodyCheckNegative: string;
|
||||
requestBody: { value: string; type: string };
|
||||
requestHeaders: Record<string, string>;
|
||||
responseHeaders: Record<string, string>;
|
||||
indexResponseBody: boolean;
|
||||
indexResponseHeaders: boolean;
|
||||
}) {
|
||||
await testSubjects.click('syntheticsHTTPAdvancedFieldsAccordion');
|
||||
await this.configureResponseHeaders(responseHeaders);
|
||||
await this.configureRequestHeaders(requestHeaders);
|
||||
await this.configureRequestBody(requestBody.type, requestBody.value);
|
||||
await this.configureUsernameAndPassword({ username, password });
|
||||
await this.setComboBox('syntheticsResponseStatusCheck', responseStatusCheck);
|
||||
await this.setComboBox('syntheticsResponseBodyCheckPositive', responseBodyCheckPositive);
|
||||
await this.setComboBox('syntheticsResponseBodyCheckNegative', responseBodyCheckNegative);
|
||||
await this.fillTextInputByTestSubj('syntheticsProxyUrl', proxyUrl);
|
||||
await testSubjects.selectValue('syntheticsRequestMethod', requestMethod);
|
||||
if (!indexResponseBody) {
|
||||
const field = await testSubjects.find('syntheticsIndexResponseBody');
|
||||
const label = await field.findByCssSelector('label');
|
||||
await label.click();
|
||||
}
|
||||
if (!indexResponseHeaders) {
|
||||
const field = await testSubjects.find('syntheticsIndexResponseHeaders');
|
||||
const label = await field.findByCssSelector('label');
|
||||
await label.click();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Configure tcp advanced settings
|
||||
*/
|
||||
async configureTCPAdvancedOptions({
|
||||
proxyUrl,
|
||||
requestSendCheck,
|
||||
responseReceiveCheck,
|
||||
proxyUseLocalResolver,
|
||||
}: {
|
||||
proxyUrl: string;
|
||||
requestSendCheck: string;
|
||||
responseReceiveCheck: string;
|
||||
proxyUseLocalResolver: boolean;
|
||||
}) {
|
||||
await testSubjects.click('syntheticsTCPAdvancedFieldsAccordion');
|
||||
await this.fillTextInputByTestSubj('syntheticsProxyUrl', proxyUrl);
|
||||
await this.fillTextInputByTestSubj('syntheticsTCPRequestSendCheck', requestSendCheck);
|
||||
await this.fillTextInputByTestSubj('syntheticsTCPResponseReceiveCheck', responseReceiveCheck);
|
||||
if (proxyUseLocalResolver) {
|
||||
const field = await testSubjects.find('syntheticsUseLocalResolver');
|
||||
const label = await field.findByCssSelector('label');
|
||||
await label.click();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Configure browser advanced settings
|
||||
* @params name {string} the name of the monitor
|
||||
* @params zipUrl {string} the zip url of the synthetics suites
|
||||
*/
|
||||
async configureBrowserAdvancedOptions({
|
||||
screenshots,
|
||||
syntheticsArgs,
|
||||
isThrottlingEnabled,
|
||||
downloadSpeed,
|
||||
uploadSpeed,
|
||||
latency,
|
||||
}: {
|
||||
screenshots: string;
|
||||
syntheticsArgs: string;
|
||||
isThrottlingEnabled: boolean;
|
||||
downloadSpeed: string;
|
||||
uploadSpeed: string;
|
||||
latency: string;
|
||||
}) {
|
||||
await testSubjects.click('syntheticsBrowserAdvancedFieldsAccordion');
|
||||
|
||||
const throttleSwitch = await this.findThrottleSwitch();
|
||||
if (!isThrottlingEnabled) {
|
||||
await throttleSwitch.click();
|
||||
}
|
||||
|
||||
await testSubjects.selectValue('syntheticsBrowserScreenshots', screenshots);
|
||||
await this.setComboBox('syntheticsBrowserSyntheticsArgs', syntheticsArgs);
|
||||
|
||||
if (isThrottlingEnabled) {
|
||||
await this.fillTextInputByTestSubj('syntheticsBrowserDownloadSpeed', downloadSpeed);
|
||||
await this.fillTextInputByTestSubj('syntheticsBrowserUploadSpeed', uploadSpeed);
|
||||
await this.fillTextInputByTestSubj('syntheticsBrowserLatency', latency);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { services as kibanaFunctionalServices } from '../../../../test/functional/services';
|
||||
import { services as commonServices } from '../../common/services';
|
||||
import { UptimeProvider } from './uptime';
|
||||
|
||||
// define the name and providers for services that should be
|
||||
// available to your tests. If you don't specify anything here
|
||||
// only the built-in services will be available
|
||||
export const services = {
|
||||
...kibanaFunctionalServices,
|
||||
...commonServices,
|
||||
uptime: UptimeProvider,
|
||||
};
|
|
@ -1,8 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export { UptimeProvider } from './uptime';
|
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
PACKAGE_POLICY_SAVED_OBJECT_TYPE,
|
||||
DeletePackagePoliciesRequest,
|
||||
GetPackagePoliciesResponse,
|
||||
GetFullAgentPolicyResponse,
|
||||
GetPackagesResponse,
|
||||
GetAgentPoliciesResponse,
|
||||
} from '@kbn/fleet-plugin/common';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
const INGEST_API_ROOT = '/api/fleet';
|
||||
const INGEST_API_AGENT_POLICIES = `${INGEST_API_ROOT}/agent_policies`;
|
||||
const INGEST_API_PACKAGE_POLICIES = `${INGEST_API_ROOT}/package_policies`;
|
||||
const INGEST_API_PACKAGE_POLICIES_DELETE = `${INGEST_API_PACKAGE_POLICIES}/delete`;
|
||||
const INGEST_API_EPM_PACKAGES = `${INGEST_API_ROOT}/epm/packages`;
|
||||
|
||||
export function SyntheticsPackageProvider({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
const log = getService('log');
|
||||
const retry = getService('retry');
|
||||
|
||||
const logSupertestApiErrorAndThrow = (message: string, error: any): never => {
|
||||
const responseBody = error?.response?.body;
|
||||
const responseText = error?.response?.text;
|
||||
log.error(`Error occurred at ${Date.now()} | ${new Date().toISOString()}`);
|
||||
log.error(JSON.stringify(responseBody || responseText, null, 2));
|
||||
log.error(error);
|
||||
throw new Error(message);
|
||||
};
|
||||
const retrieveSyntheticsPackageInfo = (() => {
|
||||
// Retrieve information about the Synthetics package
|
||||
// EPM does not currently have an API to get the "lastest" information for a page given its name,
|
||||
// so we'll retrieve a list of packages and then find the package info in the list.
|
||||
let apiRequest: Promise<GetPackagesResponse['items'][0] | undefined>;
|
||||
|
||||
return () => {
|
||||
if (!apiRequest) {
|
||||
log.info(`Setting up call to retrieve Synthetics package`);
|
||||
|
||||
// Currently (as of 2020-june) the package registry used in CI is the public one and
|
||||
// at times it encounters network connection issues. We use `retry.try` below to see if
|
||||
// subsequent requests get through.
|
||||
apiRequest = retry.try(() => {
|
||||
return supertest
|
||||
.get(INGEST_API_EPM_PACKAGES)
|
||||
.query({ prerelease: true })
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.expect(200)
|
||||
.catch((error) => {
|
||||
return logSupertestApiErrorAndThrow(`Unable to retrieve packages via Ingest!`, error);
|
||||
})
|
||||
.then((response: { body: GetPackagesResponse }) => {
|
||||
const { body } = response;
|
||||
const syntheticsPackageInfo = body.items.find(
|
||||
(epmPackage) => epmPackage.name === 'synthetics'
|
||||
);
|
||||
if (!syntheticsPackageInfo) {
|
||||
throw new Error(
|
||||
`Synthetics package was not in response from ${INGEST_API_EPM_PACKAGES}`
|
||||
);
|
||||
}
|
||||
return Promise.resolve(syntheticsPackageInfo);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
log.info('Using cached retrieval of synthetics package');
|
||||
}
|
||||
return apiRequest;
|
||||
};
|
||||
})();
|
||||
|
||||
return {
|
||||
/**
|
||||
* Returns the synthetics package version for the currently installed package. This version can then
|
||||
* be used to build URLs for Fleet pages or APIs
|
||||
*/
|
||||
async getSyntheticsPackageVersion() {
|
||||
const syntheticsPackage = await retrieveSyntheticsPackageInfo()!;
|
||||
|
||||
return syntheticsPackage?.version;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the full Agent policy by id, which mirrors what the Elastic Agent would get
|
||||
* once they checkin.
|
||||
*/
|
||||
async getFullAgentPolicy(agentPolicyId: string): Promise<GetFullAgentPolicyResponse['item']> {
|
||||
let fullAgentPolicy: GetFullAgentPolicyResponse['item'];
|
||||
try {
|
||||
const apiResponse: { body: GetFullAgentPolicyResponse } = await supertest
|
||||
.get(`${INGEST_API_AGENT_POLICIES}/${agentPolicyId}/full`)
|
||||
.expect(200);
|
||||
|
||||
fullAgentPolicy = apiResponse.body.item;
|
||||
} catch (error) {
|
||||
return logSupertestApiErrorAndThrow('Unable to get full Agent policy', error);
|
||||
}
|
||||
|
||||
return fullAgentPolicy!;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves all the agent policies.
|
||||
*/
|
||||
async getAgentPolicyList(): Promise<GetAgentPoliciesResponse['items']> {
|
||||
let agentPolicyList: GetAgentPoliciesResponse['items'];
|
||||
try {
|
||||
const apiResponse: { body: GetAgentPoliciesResponse } = await supertest
|
||||
.get(INGEST_API_AGENT_POLICIES)
|
||||
.expect(200);
|
||||
|
||||
agentPolicyList = apiResponse.body.items;
|
||||
} catch (error) {
|
||||
return logSupertestApiErrorAndThrow('Unable to get full Agent policy list', error);
|
||||
}
|
||||
|
||||
return agentPolicyList!;
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes a policy (Package Policy) by using the policy name
|
||||
* @param name
|
||||
*/
|
||||
async deletePolicyByName(name: string) {
|
||||
const id = await this.getPackagePolicyIdByName(name);
|
||||
|
||||
if (id) {
|
||||
try {
|
||||
const deletePackagePolicyData: DeletePackagePoliciesRequest['body'] = {
|
||||
packagePolicyIds: [id],
|
||||
};
|
||||
await supertest
|
||||
.post(INGEST_API_PACKAGE_POLICIES_DELETE)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send(deletePackagePolicyData)
|
||||
.expect(200);
|
||||
} catch (error) {
|
||||
logSupertestApiErrorAndThrow(
|
||||
`Unable to delete Package Policy via Ingest! ${name}`,
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the policy id (Package Policy) by using the policy name
|
||||
* @param name
|
||||
*/
|
||||
async getPackagePolicyIdByName(name: string) {
|
||||
const { body: packagePoliciesResponse }: { body: GetPackagePoliciesResponse } =
|
||||
await supertest
|
||||
.get(INGEST_API_PACKAGE_POLICIES)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.query({ kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.name: ${name}` })
|
||||
.send()
|
||||
.expect(200);
|
||||
const packagePolicyList: GetPackagePoliciesResponse['items'] = packagePoliciesResponse.items;
|
||||
|
||||
if (packagePolicyList.length > 1) {
|
||||
throw new Error(`Found ${packagePolicyList.length} Policies - was expecting only one!`);
|
||||
}
|
||||
|
||||
if (packagePolicyList.length) {
|
||||
return packagePolicyList[0].id;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
import { SyntheticsPackageProvider } from './synthetics_package';
|
||||
|
||||
export function UptimeProvider(context: FtrProviderContext) {
|
||||
const syntheticsPackage = SyntheticsPackageProvider(context);
|
||||
|
||||
return {
|
||||
syntheticsPackage,
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue