Skip to content

Commit

Permalink
[Uptime] Fix flaky monitor details tests (#124700)
Browse files Browse the repository at this point in the history
* Rewrite flaky tests to e2e pipeline, add data initialization helpers, add monitor details page object
  • Loading branch information
emilioalvap authored Feb 11, 2022
1 parent 0766f18 commit 453e22e
Show file tree
Hide file tree
Showing 21 changed files with 765 additions and 305 deletions.
182 changes: 182 additions & 0 deletions x-pack/plugins/uptime/e2e/helpers/make_checks.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 126 additions & 0 deletions x-pack/plugins/uptime/e2e/helpers/make_ping.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 68 additions & 0 deletions x-pack/plugins/uptime/e2e/helpers/make_tls.ts
Original file line number Diff line number Diff line change
@@ -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',
};
};
3 changes: 1 addition & 2 deletions x-pack/plugins/uptime/e2e/journeys/data_view_permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => {
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/uptime/e2e/journeys/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Loading

0 comments on commit 453e22e

Please sign in to comment.