[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:
Emilio Alvarez Piñeiro 2022-02-11 09:45:23 +01:00 committed by GitHub
parent 0766f1803c
commit 453e22e318
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 765 additions and 305 deletions

View 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(),
};
};

View 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;
};

View 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',
};
};

View file

@ -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 }) => {

View file

@ -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';

View 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';

View file

@ -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();
});
});

View file

@ -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}"`)))
);
});
});

View file

@ -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'));
});
});

View file

@ -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();

View file

@ -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 () => {

View file

@ -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));

View 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();
},
};
}

View file

@ -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>) {

View file

@ -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,
});

View file

@ -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"

View file

@ -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'));
});

View file

@ -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',
]);
});
});
});
};

View file

@ -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();
});
});
};

View file

@ -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);
});
});
});
};

View file

@ -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'));
});
});