mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Uptime] Fix flaky monitor details tests (#124700)
* Rewrite flaky tests to e2e pipeline, add data initialization helpers, add monitor details page object
This commit is contained in:
parent
0766f1803c
commit
453e22e318
21 changed files with 765 additions and 305 deletions
182
x-pack/plugins/uptime/e2e/helpers/make_checks.ts
Normal file
182
x-pack/plugins/uptime/e2e/helpers/make_checks.ts
Normal file
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* 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 uuid from 'uuid';
|
||||
import { merge, flattenDeep } from 'lodash';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { makePing } from './make_ping';
|
||||
import { TlsProps } from './make_tls';
|
||||
|
||||
interface CheckProps {
|
||||
es: Client;
|
||||
monitorId?: string;
|
||||
numIps?: number;
|
||||
fields?: { [key: string]: any };
|
||||
mogrify?: (doc: any) => any;
|
||||
refresh?: boolean;
|
||||
tls?: boolean | TlsProps;
|
||||
isFleetManaged?: boolean;
|
||||
}
|
||||
|
||||
const getRandomMonitorId = () => {
|
||||
return 'monitor-' + Math.random().toString(36).substring(7);
|
||||
};
|
||||
export const makeCheck = async ({
|
||||
es,
|
||||
monitorId = getRandomMonitorId(),
|
||||
numIps = 1,
|
||||
fields = {},
|
||||
mogrify = (d) => d,
|
||||
refresh = true,
|
||||
tls = false,
|
||||
isFleetManaged = false,
|
||||
}: CheckProps): Promise<{ monitorId: string; docs: any }> => {
|
||||
const cgFields = {
|
||||
monitor: {
|
||||
check_group: uuid.v4(),
|
||||
},
|
||||
};
|
||||
|
||||
const docs = [];
|
||||
const summary = {
|
||||
up: 0,
|
||||
down: 0,
|
||||
};
|
||||
for (let i = 0; i < numIps; i++) {
|
||||
const pingFields = merge(fields, cgFields, {
|
||||
monitor: {
|
||||
ip: `127.0.0.${i}`,
|
||||
},
|
||||
});
|
||||
if (i === numIps - 1) {
|
||||
pingFields.summary = summary;
|
||||
}
|
||||
const doc = await makePing(
|
||||
es,
|
||||
monitorId,
|
||||
pingFields,
|
||||
mogrify,
|
||||
false,
|
||||
tls as any,
|
||||
isFleetManaged
|
||||
);
|
||||
docs.push(doc);
|
||||
// @ts-ignore
|
||||
summary[doc.monitor.status]++;
|
||||
}
|
||||
|
||||
if (refresh) {
|
||||
await es.indices.refresh();
|
||||
}
|
||||
|
||||
return { monitorId, docs };
|
||||
};
|
||||
|
||||
export const makeChecks = async (
|
||||
es: Client,
|
||||
monitorId: string,
|
||||
numChecks: number = 1,
|
||||
numIps: number = 1,
|
||||
every: number = 10000, // number of millis between checks
|
||||
fields: { [key: string]: any } = {},
|
||||
mogrify: (doc: any) => any = (d) => d,
|
||||
refresh: boolean = true,
|
||||
isFleetManaged: boolean = false
|
||||
) => {
|
||||
const checks = [];
|
||||
const oldestTime = new Date().getTime() - numChecks * every;
|
||||
let newestTime = oldestTime;
|
||||
for (let li = 0; li < numChecks; li++) {
|
||||
const checkDate = new Date(newestTime + every);
|
||||
newestTime = checkDate.getTime() + every;
|
||||
fields = merge(fields, {
|
||||
'@timestamp': checkDate.toISOString(),
|
||||
monitor: {
|
||||
timespan: {
|
||||
gte: checkDate.toISOString(),
|
||||
lt: new Date(newestTime).toISOString(),
|
||||
},
|
||||
},
|
||||
});
|
||||
const { docs } = await makeCheck({
|
||||
es,
|
||||
monitorId,
|
||||
numIps,
|
||||
fields,
|
||||
mogrify,
|
||||
refresh: false,
|
||||
isFleetManaged,
|
||||
});
|
||||
checks.push(docs);
|
||||
}
|
||||
|
||||
if (refresh) {
|
||||
await es.indices.refresh();
|
||||
}
|
||||
|
||||
return checks;
|
||||
};
|
||||
|
||||
export const makeChecksWithStatus = async (
|
||||
es: Client,
|
||||
monitorId: string,
|
||||
numChecks: number,
|
||||
numIps: number,
|
||||
every: number,
|
||||
fields: { [key: string]: any } = {},
|
||||
status: 'up' | 'down',
|
||||
mogrify: (doc: any) => any = (d) => d,
|
||||
refresh: boolean = true,
|
||||
isFleetManaged: boolean = false
|
||||
) => {
|
||||
const oppositeStatus = status === 'up' ? 'down' : 'up';
|
||||
|
||||
return await makeChecks(
|
||||
es,
|
||||
monitorId,
|
||||
numChecks,
|
||||
numIps,
|
||||
every,
|
||||
fields,
|
||||
(d) => {
|
||||
d.monitor.status = status;
|
||||
if (d.summary) {
|
||||
d.summary[status] += d.summary[oppositeStatus];
|
||||
d.summary[oppositeStatus] = 0;
|
||||
}
|
||||
|
||||
return mogrify(d);
|
||||
},
|
||||
refresh,
|
||||
isFleetManaged
|
||||
);
|
||||
};
|
||||
|
||||
// Helper for processing a list of checks to find the time picker bounds.
|
||||
export const getChecksDateRange = (checks: any[]) => {
|
||||
// Flatten 2d arrays
|
||||
const flattened = flattenDeep(checks);
|
||||
|
||||
let startTime = 1 / 0;
|
||||
let endTime = -1 / 0;
|
||||
flattened.forEach((c) => {
|
||||
const ts = Date.parse(c['@timestamp']);
|
||||
|
||||
if (ts < startTime) {
|
||||
startTime = ts;
|
||||
}
|
||||
|
||||
if (ts > endTime) {
|
||||
endTime = ts;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
start: new Date(startTime).toISOString(),
|
||||
end: new Date(endTime).toISOString(),
|
||||
};
|
||||
};
|
126
x-pack/plugins/uptime/e2e/helpers/make_ping.ts
Normal file
126
x-pack/plugins/uptime/e2e/helpers/make_ping.ts
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* 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 uuid from 'uuid';
|
||||
import { merge } from 'lodash';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { makeTls, TlsProps } from './make_tls';
|
||||
|
||||
const DEFAULT_INDEX_NAME = 'heartbeat-8-full-test';
|
||||
const DATA_STREAM_INDEX_NAME = 'synthetics-http-default';
|
||||
|
||||
export const makePing = async (
|
||||
es: Client,
|
||||
monitorId: string,
|
||||
fields: { [key: string]: any },
|
||||
mogrify: (doc: any) => any,
|
||||
refresh: boolean = true,
|
||||
tls: boolean | TlsProps = false,
|
||||
isFleetManaged: boolean | undefined = false
|
||||
) => {
|
||||
const timestamp = new Date();
|
||||
const baseDoc: any = {
|
||||
tcp: {
|
||||
rtt: {
|
||||
connect: {
|
||||
us: 14687,
|
||||
},
|
||||
},
|
||||
},
|
||||
observer: {
|
||||
geo: {
|
||||
name: 'mpls',
|
||||
location: '37.926868, -78.024902',
|
||||
},
|
||||
hostname: 'avc-x1e',
|
||||
},
|
||||
agent: {
|
||||
hostname: 'avc-x1e',
|
||||
id: '10730a1a-4cb7-45ce-8524-80c4820476ab',
|
||||
type: 'heartbeat',
|
||||
ephemeral_id: '0d9a8dc6-f604-49e3-86a0-d8f9d6f2cbad',
|
||||
version: '8.0.0',
|
||||
},
|
||||
'@timestamp': timestamp.toISOString(),
|
||||
resolve: {
|
||||
rtt: {
|
||||
us: 350,
|
||||
},
|
||||
ip: '127.0.0.1',
|
||||
},
|
||||
ecs: {
|
||||
version: '1.1.0',
|
||||
},
|
||||
host: {
|
||||
name: 'avc-x1e',
|
||||
},
|
||||
http: {
|
||||
rtt: {
|
||||
response_header: {
|
||||
us: 19349,
|
||||
},
|
||||
total: {
|
||||
us: 48954,
|
||||
},
|
||||
write_request: {
|
||||
us: 33,
|
||||
},
|
||||
content: {
|
||||
us: 51,
|
||||
},
|
||||
validate: {
|
||||
us: 19400,
|
||||
},
|
||||
},
|
||||
response: {
|
||||
status_code: 200,
|
||||
body: {
|
||||
bytes: 3,
|
||||
hash: '27badc983df1780b60c2b3fa9d3a19a00e46aac798451f0febdca52920faaddf',
|
||||
},
|
||||
},
|
||||
},
|
||||
monitor: {
|
||||
duration: {
|
||||
us: 49347,
|
||||
},
|
||||
ip: '127.0.0.1',
|
||||
id: monitorId,
|
||||
check_group: uuid.v4(),
|
||||
type: 'http',
|
||||
status: 'up',
|
||||
timespan: {
|
||||
gte: timestamp.toISOString(),
|
||||
lt: new Date(timestamp.getTime() + 5000).toISOString,
|
||||
},
|
||||
},
|
||||
event: {
|
||||
dataset: 'uptime',
|
||||
},
|
||||
url: {
|
||||
path: '/pattern',
|
||||
scheme: 'http',
|
||||
port: 5678,
|
||||
domain: 'localhost',
|
||||
query: 'r=200x5,500x1',
|
||||
full: 'http://localhost:5678/pattern?r=200x5,500x1',
|
||||
},
|
||||
};
|
||||
|
||||
if (tls) {
|
||||
baseDoc.tls = makeTls(tls as any);
|
||||
}
|
||||
|
||||
const doc = mogrify(merge(baseDoc, fields));
|
||||
|
||||
await es.index({
|
||||
index: isFleetManaged ? DATA_STREAM_INDEX_NAME : DEFAULT_INDEX_NAME,
|
||||
refresh,
|
||||
body: doc,
|
||||
});
|
||||
return doc;
|
||||
};
|
68
x-pack/plugins/uptime/e2e/helpers/make_tls.ts
Normal file
68
x-pack/plugins/uptime/e2e/helpers/make_tls.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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 moment from 'moment';
|
||||
import crypto from 'crypto';
|
||||
|
||||
export interface TlsProps {
|
||||
valid?: boolean;
|
||||
commonName?: string;
|
||||
expiry?: string;
|
||||
sha256?: string;
|
||||
}
|
||||
|
||||
type Props = TlsProps & boolean;
|
||||
|
||||
// Note This is just a mock sha256 value, this doesn't actually generate actually sha 256 val
|
||||
export const getSha256 = () => {
|
||||
return crypto.randomBytes(64).toString('hex').toUpperCase();
|
||||
};
|
||||
|
||||
export const makeTls = ({ valid = true, commonName = '*.elastic.co', expiry, sha256 }: Props) => {
|
||||
const expiryDate =
|
||||
expiry ??
|
||||
moment()
|
||||
.add(valid ? 2 : -2, 'months')
|
||||
.toISOString();
|
||||
|
||||
return {
|
||||
version: '1.3',
|
||||
cipher: 'TLS-AES-128-GCM-SHA256',
|
||||
certificate_not_valid_before: '2020-03-01T00:00:00.000Z',
|
||||
certificate_not_valid_after: expiryDate,
|
||||
server: {
|
||||
x509: {
|
||||
not_before: '2020-03-01T00:00:00.000Z',
|
||||
not_after: expiryDate,
|
||||
issuer: {
|
||||
distinguished_name:
|
||||
'CN=DigiCert SHA2 High Assurance Server CA,OU=www.digicert.com,O=DigiCert Inc,C=US',
|
||||
common_name: 'DigiCert SHA2 High Assurance Server CA',
|
||||
},
|
||||
subject: {
|
||||
common_name: commonName,
|
||||
distinguished_name: 'CN=*.facebook.com,O=Facebook Inc.,L=Menlo Park,ST=California,C=US',
|
||||
},
|
||||
serial_number: '10043199409725537507026285099403602396',
|
||||
signature_algorithm: 'SHA256-RSA',
|
||||
public_key_algorithm: 'ECDSA',
|
||||
public_key_curve: 'P-256',
|
||||
},
|
||||
hash: {
|
||||
sha256: sha256 ?? '1a48f1db13c3bd1482ba1073441e74a1bb1308dc445c88749e0dc4f1889a88a4',
|
||||
sha1: '23291c758d925b9f4bb3584de3763317e94c6ce9',
|
||||
},
|
||||
},
|
||||
established: true,
|
||||
rtt: {
|
||||
handshake: {
|
||||
us: 33103,
|
||||
},
|
||||
},
|
||||
version_protocol: 'tls',
|
||||
};
|
||||
};
|
|
@ -6,8 +6,7 @@
|
|||
*/
|
||||
|
||||
import { journey, step, expect, before } from '@elastic/synthetics';
|
||||
import { loginToKibana, waitForLoadingToFinish } from './utils';
|
||||
import { byTestId } from './uptime.journey';
|
||||
import { byTestId, loginToKibana, waitForLoadingToFinish } from './utils';
|
||||
import { callKibana } from '../../../apm/scripts/create_apm_users_and_roles/helpers/call_kibana';
|
||||
|
||||
journey('DataViewPermissions', async ({ page, params }) => {
|
||||
|
|
|
@ -12,3 +12,4 @@ export * from './alerts';
|
|||
export * from './read_only_user';
|
||||
export * from './monitor_name.journey';
|
||||
export * from './monitor_management.journey';
|
||||
export * from './monitor_details';
|
||||
|
|
10
x-pack/plugins/uptime/e2e/journeys/monitor_details/index.ts
Normal file
10
x-pack/plugins/uptime/e2e/journeys/monitor_details/index.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* 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 * from './monitor_details.journey';
|
||||
export * from './monitor_alerts.journey';
|
||||
export * from './ping_redirects.journey';
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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 { journey, step, expect, before, Page } from '@elastic/synthetics';
|
||||
import { noop } from 'lodash';
|
||||
import { monitorDetailsPageProvider } from '../../page_objects/monitor_details';
|
||||
import { byTestId, delay } from '../utils';
|
||||
|
||||
const dateRangeStart = '2019-09-10T12:40:08.078Z';
|
||||
const dateRangeEnd = '2019-09-11T19:40:08.078Z';
|
||||
const monitorId = '0000-intermittent';
|
||||
|
||||
const alertId = 'uptime-anomaly-alert';
|
||||
const alertThreshold = 'major';
|
||||
|
||||
journey('MonitorAlerts', async ({ page, params }: { page: Page; params: any }) => {
|
||||
const monitorDetails = monitorDetailsPageProvider({ page, kibanaUrl: params.kibanaUrl });
|
||||
|
||||
before(async () => {
|
||||
await monitorDetails.waitForLoadingToFinish();
|
||||
});
|
||||
|
||||
step('go to overview', async () => {
|
||||
await monitorDetails.navigateToOverviewPage({ dateRangeEnd, dateRangeStart });
|
||||
});
|
||||
|
||||
step('login to Kibana', async () => {
|
||||
await monitorDetails.loginToKibana();
|
||||
});
|
||||
|
||||
step('go to monitor details', async () => {
|
||||
await monitorDetails.navigateToMonitorDetails(monitorId);
|
||||
await monitorDetails.waitForLoadingToFinish();
|
||||
});
|
||||
|
||||
step('clean previous data if available', async () => {
|
||||
// Should only happen locally
|
||||
await monitorDetails.disableAnomalyDetectionAlert().catch(noop);
|
||||
await monitorDetails.disableAnomalyDetection().catch(noop);
|
||||
});
|
||||
|
||||
step('open anomaly detection flyout', async () => {
|
||||
await monitorDetails.waitAndRefresh(5000);
|
||||
await monitorDetails.enableAnomalyDetection();
|
||||
await monitorDetails.ensureAnomalyDetectionFlyoutIsOpen();
|
||||
});
|
||||
|
||||
step('can create job', async () => {
|
||||
const canCreateJob = await monitorDetails.canCreateJob();
|
||||
const missingLicense = await page
|
||||
.waitForSelector('uptimeMLLicenseInfo', { timeout: 10000 })
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
expect(canCreateJob).toBeTruthy();
|
||||
expect(missingLicense).toBeFalsy();
|
||||
});
|
||||
|
||||
step('creates ML job', async () => {
|
||||
await page.click(byTestId('uptimeMLCreateJobBtn'));
|
||||
await page.waitForSelector(byTestId('uptimeMLJobSuccessfullyCreated'), { timeout: 30000 });
|
||||
await page.click(byTestId('toastCloseButton'));
|
||||
});
|
||||
|
||||
step('close anomaly detection flyout', async () => {
|
||||
await page.click(byTestId('cancelSaveAlertButton'));
|
||||
});
|
||||
|
||||
step('open anomaly detection alert', async () => {
|
||||
await monitorDetails.waitAndRefresh(3000);
|
||||
await monitorDetails.openAnomalyDetectionMenu();
|
||||
await page.click(byTestId('uptimeEnableAnomalyAlertBtn'));
|
||||
});
|
||||
|
||||
step('update anomaly detection alert', async () => {
|
||||
await monitorDetails.updateAlert({ id: alertId, threshold: alertThreshold });
|
||||
});
|
||||
|
||||
step('save anomaly detection alert', async () => {
|
||||
await page.click(byTestId('saveAlertButton'));
|
||||
await page.click(byTestId('confirmModalConfirmButton'));
|
||||
await page.waitForSelector(`text=Created rule "${alertId}"`);
|
||||
});
|
||||
|
||||
step('disable anomaly detection alert', async () => {
|
||||
await monitorDetails.waitAndRefresh(5000);
|
||||
await monitorDetails.disableAnomalyDetectionAlert();
|
||||
await delay(1000); // Menu has delay when closing
|
||||
await monitorDetails.disableAnomalyDetection();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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 { journey, step, before, Page } from '@elastic/synthetics';
|
||||
import { monitorDetailsPageProvider } from '../../page_objects/monitor_details';
|
||||
import { byTestId } from '../utils';
|
||||
|
||||
const dateRangeStart = '2019-09-10T12:40:08.078Z';
|
||||
const dateRangeEnd = '2019-09-11T19:40:08.078Z';
|
||||
const monitorId = '0000-intermittent';
|
||||
|
||||
journey('MonitorDetails', async ({ page, params }: { page: Page; params: any }) => {
|
||||
const monitorDetails = monitorDetailsPageProvider({ page, kibanaUrl: params.kibanaUrl });
|
||||
|
||||
before(async () => {
|
||||
await monitorDetails.waitForLoadingToFinish();
|
||||
});
|
||||
|
||||
step('go to overview', async () => {
|
||||
await monitorDetails.navigateToOverviewPage({ dateRangeEnd, dateRangeStart });
|
||||
});
|
||||
|
||||
step('login to Kibana', async () => {
|
||||
await monitorDetails.loginToKibana();
|
||||
});
|
||||
|
||||
step('go to monitor details', async () => {
|
||||
await monitorDetails.navigateToMonitorDetails(monitorId);
|
||||
await monitorDetails.waitForLoadingToFinish();
|
||||
});
|
||||
|
||||
step('should select the ping list location filter', async () => {
|
||||
await monitorDetails.selectFilterItem('Location', 'mpls');
|
||||
});
|
||||
|
||||
step('should set the status filter', async () => {
|
||||
await monitorDetails.setStatusFilterUp();
|
||||
});
|
||||
|
||||
step('displays ping data as expected', async () => {
|
||||
await Promise.all(
|
||||
[
|
||||
'XZtoHm0B0I9WX_CznN-6',
|
||||
'7ZtoHm0B0I9WX_CzJ96M',
|
||||
'pptnHm0B0I9WX_Czst5X',
|
||||
'I5tnHm0B0I9WX_CzPd46',
|
||||
'y5tmHm0B0I9WX_Czx93x',
|
||||
'XZtmHm0B0I9WX_CzUt3H',
|
||||
'-JtlHm0B0I9WX_Cz3dyX',
|
||||
'k5tlHm0B0I9WX_CzaNxm',
|
||||
'NZtkHm0B0I9WX_Cz89w9',
|
||||
'zJtkHm0B0I9WX_CzftsN',
|
||||
].map((id) => page.waitForSelector(byTestId(`"xpack.uptime.pingList.ping-${id}"`)))
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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 { journey, step, expect, before, Page } from '@elastic/synthetics';
|
||||
import { makeChecksWithStatus } from '../../helpers/make_checks';
|
||||
import { monitorDetailsPageProvider } from '../../page_objects/monitor_details';
|
||||
import { byTestId, delay } from '../utils';
|
||||
|
||||
journey('MonitorPingRedirects', async ({ page, params }: { page: Page; params: any }) => {
|
||||
const monitorDetails = monitorDetailsPageProvider({ page, kibanaUrl: params.kibanaUrl });
|
||||
const testMonitor = {
|
||||
id: '0000-intermittent',
|
||||
start: 'now-15m',
|
||||
end: 'now',
|
||||
redirects: ['http://localhost:3000/first', 'https://www.washingtonpost.com/'],
|
||||
};
|
||||
|
||||
before(async () => {
|
||||
await monitorDetails.waitForLoadingToFinish();
|
||||
await makeChecksWithStatus(
|
||||
params.getService('es'),
|
||||
testMonitor.id,
|
||||
5,
|
||||
2,
|
||||
10000,
|
||||
{
|
||||
http: {
|
||||
rtt: { total: { us: 157784 } },
|
||||
response: {
|
||||
status_code: 200,
|
||||
redirects: testMonitor.redirects,
|
||||
body: {
|
||||
bytes: 642102,
|
||||
hash: '597a8cfb33ff8e09bff16283306553c3895282aaf5386e1843d466d44979e28a',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'up'
|
||||
);
|
||||
await delay(5000);
|
||||
});
|
||||
|
||||
step('go to monitor-management', async () => {
|
||||
await monitorDetails.navigateToOverviewPage({
|
||||
dateRangeEnd: testMonitor.end,
|
||||
dateRangeStart: testMonitor.start,
|
||||
});
|
||||
});
|
||||
|
||||
step('login to Kibana', async () => {
|
||||
await monitorDetails.loginToKibana();
|
||||
});
|
||||
|
||||
step('go to monitor details', async () => {
|
||||
await monitorDetails.navigateToMonitorDetails(testMonitor.id);
|
||||
});
|
||||
|
||||
step('displays redirect info in detail panel', async () => {
|
||||
await monitorDetails.waitForLoadingToFinish();
|
||||
expect(await monitorDetails.getMonitorRedirects()).toEqual(`${testMonitor.redirects.length}`);
|
||||
});
|
||||
|
||||
step('displays redirects in ping list expand row', async () => {
|
||||
await monitorDetails.expandPingDetails();
|
||||
await monitorDetails.waitForLoadingToFinish();
|
||||
await page.waitForSelector(byTestId('uptimeMonitorPingListRedirectInfo'));
|
||||
});
|
||||
});
|
|
@ -8,6 +8,7 @@
|
|||
import { journey, step, expect, before, after, Page } from '@elastic/synthetics';
|
||||
import { monitorManagementPageProvider } from '../page_objects/monitor_management';
|
||||
import { DataStream } from '../../common/runtime_types/monitor_management';
|
||||
import { byTestId } from './utils';
|
||||
|
||||
const basicMonitorDetails = {
|
||||
location: 'US Central',
|
||||
|
@ -197,6 +198,8 @@ journey('Monitor Management breadcrumbs', async ({ page, params }: { page: Page;
|
|||
|
||||
step('edit http monitor and check breadcrumb', async () => {
|
||||
await uptime.editMonitor();
|
||||
// breadcrumb is available before edit page is loaded, make sure its edit view
|
||||
await page.waitForSelector(byTestId('monitorManagementMonitorName'));
|
||||
const breadcrumbs = await page.$$('[data-test-subj=breadcrumb]');
|
||||
expect(await breadcrumbs[1].textContent()).toEqual('Monitor management');
|
||||
const lastBreadcrumb = await (await uptime.findByTestSubj('"breadcrumb last"')).textContent();
|
||||
|
|
|
@ -6,11 +6,7 @@
|
|||
*/
|
||||
|
||||
import { journey, step, before } from '@elastic/synthetics';
|
||||
import { waitForLoadingToFinish } from './utils';
|
||||
|
||||
export const byTestId = (testId: string) => {
|
||||
return `[data-test-subj=${testId}]`;
|
||||
};
|
||||
import { byTestId, waitForLoadingToFinish } from './utils';
|
||||
|
||||
journey('uptime', ({ page, params }) => {
|
||||
before(async () => {
|
||||
|
|
|
@ -44,3 +44,11 @@ export const assertText = async ({ page, text }: { page: Page; text: string }) =
|
|||
export const assertNotText = async ({ page, text }: { page: Page; text: string }) => {
|
||||
expect(await page.$(`text=${text}`)).toBeFalsy();
|
||||
};
|
||||
|
||||
export const getQuerystring = (params: object) => {
|
||||
return Object.entries(params)
|
||||
.map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value))
|
||||
.join('&');
|
||||
};
|
||||
|
||||
export const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
|
129
x-pack/plugins/uptime/e2e/page_objects/monitor_details.tsx
Normal file
129
x-pack/plugins/uptime/e2e/page_objects/monitor_details.tsx
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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 { Page } from '@elastic/synthetics';
|
||||
import { byTestId, delay } from '../journeys/utils';
|
||||
import { monitorManagementPageProvider } from './monitor_management';
|
||||
|
||||
interface AlertType {
|
||||
id: string;
|
||||
threshold: string;
|
||||
}
|
||||
|
||||
export function monitorDetailsPageProvider({ page, kibanaUrl }: { page: Page; kibanaUrl: string }) {
|
||||
return {
|
||||
...monitorManagementPageProvider({ page, kibanaUrl }),
|
||||
|
||||
async navigateToMonitorDetails(monitorId: string) {
|
||||
await page.click(byTestId(`monitor-page-link-${monitorId}`));
|
||||
},
|
||||
|
||||
async selectFilterItem(filterType: string, itemArg: string | string[]) {
|
||||
const itemList = Array.isArray(itemArg) ? itemArg : [itemArg];
|
||||
await page.click(`[aria-label="expands filter group for ${filterType} filter"]`);
|
||||
await this.clickFilterItems(itemList);
|
||||
return this.applyFilterItems(filterType);
|
||||
},
|
||||
|
||||
async clickFilterItems(itemList: string[]) {
|
||||
for (const title of itemList) {
|
||||
await page.click(`li[title="${title}"]`);
|
||||
}
|
||||
},
|
||||
|
||||
async applyFilterItems(filterType: string) {
|
||||
await page.click(`[aria-label="Apply the selected filters for ${filterType}"]`);
|
||||
},
|
||||
|
||||
async setStatusFilterUp() {
|
||||
await page.click('[data-test-subj="xpack.uptime.filterBar.filterStatusUp"]');
|
||||
},
|
||||
|
||||
async setStatusFilterDown() {
|
||||
await page.click('[data-test-subj="xpack.uptime.filterBar.filterStatusDown"]');
|
||||
},
|
||||
|
||||
async refreshFromES() {
|
||||
await this.byTestId('superDatePickerApplyTimeButton');
|
||||
},
|
||||
|
||||
async enableAnomalyDetection() {
|
||||
await page.click(byTestId('uptimeEnableAnomalyBtn'));
|
||||
},
|
||||
|
||||
async getMonitorRedirects() {
|
||||
return await page.textContent(byTestId('uptimeMonitorRedirectInfo'));
|
||||
},
|
||||
|
||||
async expandPingDetails() {
|
||||
await page.click(byTestId('uptimePingListExpandBtn'));
|
||||
},
|
||||
|
||||
async ensureAnomalyDetectionFlyoutIsOpen() {
|
||||
await page.waitForSelector(byTestId('uptimeMLFlyout'));
|
||||
},
|
||||
|
||||
async isMLMenuVisible() {
|
||||
return await page.isVisible(byTestId('uptimeManageMLContextMenu'), {
|
||||
timeout: 3000,
|
||||
});
|
||||
},
|
||||
|
||||
async canCreateJob(): Promise<boolean> {
|
||||
await this.ensureAnomalyDetectionFlyoutIsOpen();
|
||||
const createJobBtn = await page.$(byTestId('uptimeMLCreateJobBtn'));
|
||||
return await createJobBtn!.isEnabled();
|
||||
},
|
||||
|
||||
async openAnomalyDetectionMenu() {
|
||||
const visible = await this.isMLMenuVisible();
|
||||
if (visible === false) {
|
||||
await page.click(byTestId('uptimeManageMLJobBtn'), { timeout: 5000 });
|
||||
}
|
||||
},
|
||||
|
||||
async closeAnomalyDetectionMenu() {
|
||||
if ((await this.isMLMenuVisible()) === true) {
|
||||
await page.click(byTestId('uptimeManageMLJobBtn'), { timeout: 5000 });
|
||||
}
|
||||
},
|
||||
|
||||
async waitAndRefresh(timeout?: number) {
|
||||
await delay(timeout ?? 1000);
|
||||
await this.refreshFromES();
|
||||
await this.waitForLoadingToFinish();
|
||||
},
|
||||
|
||||
async updateAlert({ id, threshold }: AlertType) {
|
||||
await this.fillByTestSubj('alertNameInput', id);
|
||||
await this.selectAlertThreshold(threshold);
|
||||
},
|
||||
|
||||
async selectAlertThreshold(threshold: string) {
|
||||
await this.clickByTestSubj('uptimeAnomalySeverity');
|
||||
await this.clickByTestSubj('anomalySeveritySelect');
|
||||
await page.click(`text=${threshold}`);
|
||||
},
|
||||
|
||||
async disableAnomalyDetection() {
|
||||
await this.openAnomalyDetectionMenu();
|
||||
await page.click(byTestId('uptimeDeleteMLJobBtn'), { timeout: 10000 });
|
||||
await page.click(byTestId('confirmModalConfirmButton'));
|
||||
await page.waitForSelector('text=Job deleted');
|
||||
await this.closeAnomalyDetectionMenu();
|
||||
},
|
||||
|
||||
async disableAnomalyDetectionAlert() {
|
||||
await this.openAnomalyDetectionMenu();
|
||||
await page.click(byTestId('uptimeManageAnomalyAlertBtn'), { timeout: 10000 });
|
||||
await page.click(byTestId('uptimeDisableAnomalyAlertBtn'));
|
||||
await page.click(byTestId('confirmModalConfirmButton'));
|
||||
await page.waitForSelector('text=Rule successfully disabled!');
|
||||
await this.closeAnomalyDetectionMenu();
|
||||
},
|
||||
};
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { Page } from '@elastic/synthetics';
|
||||
import { DataStream } from '../../common/runtime_types/monitor_management';
|
||||
import { getQuerystring } from '../journeys/utils';
|
||||
import { loginPageProvider } from './login';
|
||||
import { utilsPageProvider } from './utils';
|
||||
|
||||
|
@ -46,8 +47,8 @@ export function monitorManagementPageProvider({
|
|||
});
|
||||
},
|
||||
|
||||
async navigateToOverviewPage() {
|
||||
await page.goto(overview, {
|
||||
async navigateToOverviewPage(options?: object) {
|
||||
await page.goto(`${overview}${options ? `?${getQuerystring(options)}` : ''}`, {
|
||||
waitUntil: 'networkidle',
|
||||
});
|
||||
},
|
||||
|
@ -62,7 +63,7 @@ export function monitorManagementPageProvider({
|
|||
},
|
||||
|
||||
async editMonitor() {
|
||||
await this.clickByTestSubj('monitorManagementEditMonitor');
|
||||
await page.click(this.byTestId('monitorManagementEditMonitor'), { delay: 800 });
|
||||
},
|
||||
|
||||
async findMonitorConfiguration(monitorConfig: Record<string, string>) {
|
||||
|
|
|
@ -15,26 +15,12 @@ import './journeys';
|
|||
import { createApmAndObsUsersAndRoles } from '../../apm/scripts/create_apm_users_and_roles/create_apm_users_and_roles';
|
||||
import { importMonitors } from './tasks/import_monitors';
|
||||
|
||||
const listOfJourneys = [
|
||||
'uptime',
|
||||
'StepsDuration',
|
||||
'TlsFlyoutInAlertingApp',
|
||||
'StatusFlyoutInAlertingApp',
|
||||
'DefaultEmailSettings',
|
||||
'MonitorManagement-http',
|
||||
'MonitorManagement-tcp',
|
||||
'MonitorManagement-icmp',
|
||||
'MonitorManagement-browser',
|
||||
'MonitorManagement breadcrumbs',
|
||||
'Monitor Management read only user',
|
||||
] as const;
|
||||
|
||||
export function playwrightRunTests({ headless, match }: { headless: boolean; match?: string }) {
|
||||
return async ({ getService }: any) => {
|
||||
const result = await playwrightStart(getService, headless, match);
|
||||
const results = await playwrightStart(getService, headless, match);
|
||||
|
||||
listOfJourneys.forEach((journey) => {
|
||||
if (result?.[journey] && result[journey].status !== 'succeeded') {
|
||||
Object.entries(results).forEach(([_journey, result]) => {
|
||||
if (result.status !== 'succeeded') {
|
||||
throw new Error('Tests failed');
|
||||
}
|
||||
});
|
||||
|
@ -66,7 +52,7 @@ async function playwrightStart(getService: any, headless = true, match?: string)
|
|||
});
|
||||
|
||||
const res = await playwrightRun({
|
||||
params: { kibanaUrl },
|
||||
params: { kibanaUrl, getService },
|
||||
playwrightOptions: { headless, chromiumSandbox: false, timeout: 60 * 1000 },
|
||||
match: match === 'undefined' ? '' : match,
|
||||
});
|
||||
|
|
|
@ -75,7 +75,7 @@ export const ManageMLJobComponent = ({ hasMLJob, onEnableJob, onJobDelete }: Pro
|
|||
const button = (
|
||||
<EuiButton
|
||||
data-test-subj={hasMLJob ? 'uptimeManageMLJobBtn' : 'uptimeEnableAnomalyBtn'}
|
||||
onClick={hasMLJob ? () => setIsPopOverOpen(true) : onEnableJob}
|
||||
onClick={hasMLJob ? () => setIsPopOverOpen(!isPopOverOpen) : onEnableJob}
|
||||
disabled={hasMLJob && !canDeleteMLJob}
|
||||
isLoading={showLoading}
|
||||
size="s"
|
||||
|
|
|
@ -61,10 +61,6 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => {
|
|||
loadTestFile(require.resolve('./certificates'));
|
||||
});
|
||||
|
||||
describe('with generated data but no data reset', () => {
|
||||
loadTestFile(require.resolve('./ping_redirects'));
|
||||
});
|
||||
|
||||
describe('with real-world data', () => {
|
||||
before(async () => {
|
||||
await esArchiver.unload(ARCHIVE);
|
||||
|
@ -75,7 +71,6 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => {
|
|||
after(async () => await esArchiver.unload(ARCHIVE));
|
||||
|
||||
loadTestFile(require.resolve('./overview'));
|
||||
loadTestFile(require.resolve('./monitor'));
|
||||
loadTestFile(require.resolve('./ml_anomaly'));
|
||||
loadTestFile(require.resolve('./feature_controls'));
|
||||
});
|
||||
|
|
|
@ -1,60 +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 ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const uptimeService = getService('uptime');
|
||||
const { uptime } = getPageObjects(['uptime']);
|
||||
const archive = 'x-pack/test/functional/es_archives/uptime/full_heartbeat';
|
||||
|
||||
describe('monitor page', function () {
|
||||
this.tags(['skipFirefox']);
|
||||
const dateStart = 'Sep 10, 2019 @ 12:40:08.078';
|
||||
const dateEnd = 'Sep 11, 2019 @ 19:40:08.078';
|
||||
const monitorId = '0000-intermittent';
|
||||
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded(archive);
|
||||
await uptimeService.navigation.goToUptime();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await esArchiver.unload(archive);
|
||||
});
|
||||
|
||||
describe('navigation to monitor page', () => {
|
||||
before(async () => {
|
||||
await uptime.loadDataAndGoToMonitorPage(dateStart, dateEnd, monitorId);
|
||||
});
|
||||
|
||||
it('should select the ping list location filter', async () => {
|
||||
await uptimeService.common.selectFilterItem('Location', 'mpls');
|
||||
});
|
||||
|
||||
it('should set the status filter', async () => {
|
||||
await uptimeService.common.setStatusFilterUp();
|
||||
});
|
||||
|
||||
it('displays ping data as expected', async () => {
|
||||
await uptime.checkPingListInteractions([
|
||||
'XZtoHm0B0I9WX_CznN-6',
|
||||
'7ZtoHm0B0I9WX_CzJ96M',
|
||||
'pptnHm0B0I9WX_Czst5X',
|
||||
'I5tnHm0B0I9WX_CzPd46',
|
||||
'y5tmHm0B0I9WX_Czx93x',
|
||||
'XZtmHm0B0I9WX_CzUt3H',
|
||||
'-JtlHm0B0I9WX_Cz3dyX',
|
||||
'k5tlHm0B0I9WX_CzaNxm',
|
||||
'NZtkHm0B0I9WX_Cz89w9',
|
||||
'zJtkHm0B0I9WX_CzftsN',
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,76 +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 { makeChecksWithStatus } from '../../../api_integration/apis/uptime/rest/helper/make_checks';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const { uptime: uptimePage, header } = getPageObjects(['uptime', 'header']);
|
||||
const uptime = getService('uptime');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
const archive = 'x-pack/test/functional/es_archives/uptime/blank';
|
||||
|
||||
const monitor = () => uptime.monitor;
|
||||
|
||||
// FLAKY: https://github.com/elastic/kibana/issues/118476
|
||||
describe.skip('Ping redirects', () => {
|
||||
const start = '~ 15 minutes ago';
|
||||
const end = 'now';
|
||||
|
||||
const MONITOR_ID = 'redirect-testing-id';
|
||||
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded(archive);
|
||||
});
|
||||
|
||||
after('unload', async () => {
|
||||
await esArchiver.unload(archive);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await makeChecksWithStatus(
|
||||
getService('es'),
|
||||
MONITOR_ID,
|
||||
5,
|
||||
2,
|
||||
10000,
|
||||
{
|
||||
http: {
|
||||
rtt: { total: { us: 157784 } },
|
||||
response: {
|
||||
status_code: 200,
|
||||
redirects: ['http://localhost:3000/first', 'https://www.washingtonpost.com/'],
|
||||
body: {
|
||||
bytes: 642102,
|
||||
hash: '597a8cfb33ff8e09bff16283306553c3895282aaf5386e1843d466d44979e28a',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'up'
|
||||
);
|
||||
await delay(1000);
|
||||
});
|
||||
|
||||
it('loads and goes to details page', async () => {
|
||||
await uptime.navigation.goToUptime();
|
||||
await uptimePage.loadDataAndGoToMonitorPage(start, end, MONITOR_ID);
|
||||
});
|
||||
|
||||
it('display redirect info in detail panel', async () => {
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
await monitor().hasRedirectInfo();
|
||||
});
|
||||
|
||||
it('displays redirects in ping list expand row', async () => {
|
||||
await monitor().hasRedirectInfoInPingList();
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,134 +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 { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
// FLAKY: https://github.com/elastic/kibana/issues/111667
|
||||
describe.skip('uptime anomaly alert', () => {
|
||||
const pageObjects = getPageObjects(['common', 'uptime']);
|
||||
const supertest = getService('supertest');
|
||||
const retry = getService('retry');
|
||||
|
||||
const monitorId = '0000-intermittent';
|
||||
|
||||
const uptime = getService('uptime');
|
||||
|
||||
const DEFAULT_DATE_START = 'Sep 10, 2019 @ 12:40:08.078';
|
||||
const DEFAULT_DATE_END = 'Sep 11, 2019 @ 19:40:08.078';
|
||||
let alerts: any;
|
||||
const alertId = 'uptime-anomaly-alert';
|
||||
|
||||
before(async () => {
|
||||
alerts = getService('uptime').alerts;
|
||||
|
||||
await uptime.navigation.goToUptime();
|
||||
|
||||
await uptime.navigation.loadDataAndGoToMonitorPage(
|
||||
DEFAULT_DATE_START,
|
||||
DEFAULT_DATE_END,
|
||||
monitorId
|
||||
);
|
||||
});
|
||||
|
||||
it('can delete existing job', async () => {
|
||||
if (await uptime.ml.alreadyHasJob()) {
|
||||
await uptime.ml.openMLManageMenu();
|
||||
await uptime.ml.deleteMLJob();
|
||||
await uptime.navigation.refreshApp();
|
||||
}
|
||||
});
|
||||
|
||||
it('can open ml flyout', async () => {
|
||||
await uptime.ml.openMLFlyout();
|
||||
});
|
||||
|
||||
it('has permission to create job', async () => {
|
||||
expect(uptime.ml.canCreateJob()).to.eql(true);
|
||||
expect(uptime.ml.hasNoLicenseInfo()).to.eql(false);
|
||||
});
|
||||
|
||||
it('can create job successfully', async () => {
|
||||
await uptime.ml.createMLJob();
|
||||
await pageObjects.common.closeToast();
|
||||
await uptime.ml.cancelAlertFlyout();
|
||||
});
|
||||
|
||||
it('can open ML Manage Menu', async () => {
|
||||
await uptime.ml.openMLManageMenu();
|
||||
});
|
||||
|
||||
it('can open anomaly alert flyout', async () => {
|
||||
await uptime.ml.openAlertFlyout();
|
||||
});
|
||||
|
||||
it('can set alert name', async () => {
|
||||
await alerts.setAlertName(alertId);
|
||||
});
|
||||
|
||||
it('can set alert tags', async () => {
|
||||
await alerts.setAlertTags(['uptime', 'anomaly-alert']);
|
||||
});
|
||||
|
||||
it('can change anomaly alert threshold', async () => {
|
||||
await uptime.ml.changeAlertThreshold('major');
|
||||
});
|
||||
|
||||
it('can save alert', async () => {
|
||||
await alerts.clickSaveAlertButton();
|
||||
await alerts.clickSaveAlertsConfirmButton();
|
||||
await pageObjects.common.closeToast();
|
||||
});
|
||||
|
||||
it('has created a valid alert with expected parameters', async () => {
|
||||
let alert: any;
|
||||
await retry.tryForTime(15000, async () => {
|
||||
const apiResponse = await supertest.get(`/api/alerts/_find?search=${alertId}`);
|
||||
const alertsFromThisTest = apiResponse.body.data.filter(
|
||||
({ name }: { name: string }) => name === alertId
|
||||
);
|
||||
expect(alertsFromThisTest).to.have.length(1);
|
||||
alert = alertsFromThisTest[0];
|
||||
});
|
||||
|
||||
// Ensure the parameters and other stateful data
|
||||
// on the alert match up with the values we provided
|
||||
// for our test helper to input into the flyout.
|
||||
const { actions, alertTypeId, consumer, id, params, tags } = alert;
|
||||
try {
|
||||
expect(actions).to.eql([]);
|
||||
expect(alertTypeId).to.eql('xpack.uptime.alerts.durationAnomaly');
|
||||
expect(consumer).to.eql('uptime');
|
||||
expect(tags).to.eql(['uptime', 'anomaly-alert']);
|
||||
expect(params.monitorId).to.eql(monitorId);
|
||||
expect(params.severity).to.eql(50);
|
||||
} finally {
|
||||
await supertest.delete(`/api/alerts/alert/${id}`).set('kbn-xsrf', 'true').expect(204);
|
||||
}
|
||||
});
|
||||
|
||||
it('change button to disable anomaly alert', async () => {
|
||||
await uptime.ml.openMLManageMenu();
|
||||
expect(uptime.ml.manageAnomalyAlertIsVisible()).to.eql(true);
|
||||
});
|
||||
|
||||
it('can delete job successfully', async () => {
|
||||
await uptime.ml.deleteMLJob();
|
||||
});
|
||||
|
||||
it('verifies that alert is also deleted', async () => {
|
||||
await retry.tryForTime(15000, async () => {
|
||||
const apiResponse = await supertest.get(`/api/alerts/_find?search=${alertId}`);
|
||||
const alertsFromThisTest = apiResponse.body.data.filter(
|
||||
({ name }: { name: string }) => name === alertId
|
||||
);
|
||||
expect(alertsFromThisTest).to.have.length(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -24,7 +24,6 @@ export default ({ getService, loadTestFile }: FtrProviderContext) => {
|
|||
after(async () => await esArchiver.unload(ARCHIVE));
|
||||
|
||||
loadTestFile(require.resolve('./alert_flyout'));
|
||||
loadTestFile(require.resolve('./anomaly_alert'));
|
||||
loadTestFile(require.resolve('./simple_down_alert'));
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue