Skip to content

Commit

Permalink
[Uptime] Delete most uptime lodash references (#8)
Browse files Browse the repository at this point in the history
* Delete most uptime lodash references.

* Simplify. Clean up types.
  • Loading branch information
justinkambic authored Jun 29, 2020
1 parent 95665f0 commit 567f1e4
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import React from 'react';
import { MonitorSummary } from '../../../../../../common/runtime_types';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { IntegrationGroup } from '../actions_popover/integration_group';
import { IntegrationGroup, extractSummaryValues } from '../actions_popover/integration_group';

describe('IntegrationGroup', () => {
let summary: MonitorSummary;
Expand Down Expand Up @@ -38,4 +38,97 @@ describe('IntegrationGroup', () => {
const component = shallowWithIntl(<IntegrationGroup summary={summary} />);
expect(component).toMatchSnapshot();
});

describe('extractSummaryValues', () => {
let mockSummary: Pick<MonitorSummary, 'state'>;

beforeEach(() => {
mockSummary = {
state: {
timestamp: 'foo',
url: {},
},
};
});

it('provides defaults when values are not present', () => {
expect(extractSummaryValues(mockSummary)).toMatchInlineSnapshot(`
Object {
"containerId": undefined,
"domain": "",
"ip": undefined,
"podUid": undefined,
}
`);
});

it('finds url domain', () => {
mockSummary.state.url.domain = 'mydomain';

expect(extractSummaryValues(mockSummary)).toMatchInlineSnapshot(`
Object {
"containerId": undefined,
"domain": "mydomain",
"ip": undefined,
"podUid": undefined,
}
`);
});

it('finds pod uid', () => {
mockSummary.state.checks = [
{ kubernetes: { pod: { uid: 'myuid' } }, monitor: { status: 'up' }, timestamp: 123 },
];

expect(extractSummaryValues(mockSummary)).toMatchInlineSnapshot(`
Object {
"containerId": undefined,
"domain": "",
"ip": undefined,
"podUid": "myuid",
}
`);
});

it('does not throw for missing kubernetes fields', () => {
mockSummary.state.checks = [];

expect(extractSummaryValues(mockSummary)).toMatchInlineSnapshot(`
Object {
"containerId": undefined,
"domain": "",
"ip": undefined,
"podUid": undefined,
}
`);
});

it('finds container id', () => {
mockSummary.state.checks = [
{ container: { id: 'mycontainer' }, monitor: { status: 'up' }, timestamp: 123 },
];

expect(extractSummaryValues(mockSummary)).toMatchInlineSnapshot(`
Object {
"containerId": "mycontainer",
"domain": "",
"ip": undefined,
"podUid": undefined,
}
`);
});

it('finds ip field', () => {
mockSummary.state.checks = [{ monitor: { ip: '127.0.0.1', status: 'up' }, timestamp: 123 }];

expect(extractSummaryValues(mockSummary)).toMatchInlineSnapshot(`
Object {
"containerId": undefined,
"domain": "",
"ip": "127.0.0.1",
"podUid": undefined,
}
`);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import React, { useContext } from 'react';
import { i18n } from '@kbn/i18n';
import { get } from 'lodash';
import { FormattedMessage } from '@kbn/i18n/react';
import { IntegrationLink } from './integration_link';
import {
Expand All @@ -26,6 +25,20 @@ interface IntegrationGroupProps {
summary: MonitorSummary;
}

export const extractSummaryValues = (summary: Pick<MonitorSummary, 'state'>) => {
const domain = summary.state.url?.domain ?? '';
const podUid = summary.state.checks?.[0]?.kubernetes?.pod.uid ?? undefined;
const containerId = summary.state.checks?.[0]?.container?.id ?? undefined;
const ip = summary.state.checks?.[0]?.monitor.ip ?? undefined;

return {
domain,
podUid,
containerId,
ip,
};
};

export const IntegrationGroup = ({ summary }: IntegrationGroupProps) => {
const {
basePath,
Expand All @@ -36,10 +49,7 @@ export const IntegrationGroup = ({ summary }: IntegrationGroupProps) => {
isLogsAvailable,
} = useContext(UptimeSettingsContext);

const domain = get(summary, 'state.url.domain', '');
const podUid = get(summary, 'state.checks[0].kubernetes.pod.uid', undefined);
const containerId = get(summary, 'state.checks[0].container.id', undefined);
const ip = get(summary, 'state.checks[0].monitor.ip', undefined);
const { domain, podUid, containerId, ip } = extractSummaryValues(summary);

return isApmAvailable || isInfraAvailable || isLogsAvailable ? (
<EuiFlexGroup direction="column">
Expand Down Expand Up @@ -97,7 +107,7 @@ export const IntegrationGroup = ({ summary }: IntegrationGroupProps) => {
{
defaultMessage: 'Check Infrastructure UI for the IP "{ip}"',
values: {
ip,
ip: Array.isArray(ip) ? ip[0] : ip,
},
}
)}
Expand Down Expand Up @@ -184,7 +194,12 @@ export const IntegrationGroup = ({ summary }: IntegrationGroupProps) => {
)}
tooltipContent={i18n.translate(
'xpack.uptime.monitorList.loggingIntegrationAction.ip.tooltip',
{ defaultMessage: 'Check Logging UI for the IP "{ip}"', values: { ip } }
{
defaultMessage: 'Check Logging UI for the IP "{ip}"',
values: {
ip: Array.isArray(ip) ? ip[0] : ip,
},
}
)}
/>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import { CoreStart } from 'src/core/public';
import React from 'react';
import ReactDOM from 'react-dom';
import { get } from 'lodash';
import { i18n as i18nFormatter } from '@kbn/i18n';
import { UptimeApp, UptimeAppProps } from '../../../uptime_app';
import { getIntegratedAppAvailability } from './capabilities_adapter';
Expand Down Expand Up @@ -38,7 +37,7 @@ export const getKibanaFrameworkAdapter = (
INTEGRATED_SOLUTIONS
);

const canSave = get(capabilities, 'uptime.save', false) as boolean;
const canSave = (capabilities.uptime.save ?? false) as boolean;

const props: UptimeAppProps = {
basePath: basePath.get(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { sortChecksBy } from '../enrich_monitor_groups';

describe('enrich monitor groups', () => {
describe('sortChecksBy', () => {
it('identifies lesser geo name', () => {
expect(
sortChecksBy(
{ observer: { geo: { name: 'less' } }, monitor: { status: 'up' } },
{ observer: { geo: { name: 'more' } }, monitor: { status: 'up' } }
)
).toBe(-1);
});

it('identifies greater geo name', () => {
expect(
sortChecksBy(
{ observer: { geo: { name: 'more' } }, monitor: { status: 'up' } },
{ observer: { geo: { name: 'less' } }, monitor: { status: 'up' } }
)
).toBe(1);
});

it('identifies equivalent geo name and sorts by lesser ip', () => {
expect(
sortChecksBy(
{ observer: { geo: { name: 'same' } }, monitor: { ip: '127.0.0.1', status: 'up' } },
{ observer: { geo: { name: 'same' } }, monitor: { ip: '127.0.0.2', status: 'up' } }
)
).toBe(-1);
});

it('identifies equivalent geo name and sorts by greater ip', () => {
expect(
sortChecksBy(
{ observer: { geo: { name: 'same' } }, monitor: { ip: '127.0.0.2', status: 'up' } },
{ observer: { geo: { name: 'same' } }, monitor: { ip: '127.0.0.1', status: 'up' } }
)
).toBe(1);
});

it('identifies equivalent geo name and sorts by equivalent ip', () => {
expect(
sortChecksBy(
{ observer: { geo: { name: 'same' } }, monitor: { ip: '127.0.0.1', status: 'up' } },
{ observer: { geo: { name: 'same' } }, monitor: { ip: '127.0.0.1', status: 'up' } }
)
).toBe(0);
});

it('handles equivalent ip arrays', () => {
expect(
sortChecksBy(
{ observer: { geo: { name: 'same' } }, monitor: { ip: ['127.0.0.1'], status: 'up' } },
{ observer: { geo: { name: 'same' } }, monitor: { ip: ['127.0.0.1'], status: 'up' } }
)
).toBe(0);
});

it('handles non-equal ip arrays', () => {
expect(
sortChecksBy(
{
observer: { geo: { name: 'same' } },
monitor: { ip: ['127.0.0.2', '127.0.0.9'], status: 'up' },
},
{
observer: { geo: { name: 'same' } },
monitor: { ip: ['127.0.0.3', '127.0.0.1'], status: 'up' },
}
)
).toBe(1);
});

it('handles undefined observer fields', () => {
expect(
sortChecksBy(
{ observer: undefined, monitor: { ip: ['127.0.0.1'], status: 'up' } },
{ observer: { geo: { name: 'same' } }, monitor: { ip: ['127.0.0.1'], status: 'up' } }
)
).toBe(-1);
});

it('handles undefined ip fields', () => {
expect(
sortChecksBy(
{ observer: { geo: { name: 'same' } }, monitor: { ip: undefined, status: 'up' } },
{ observer: { geo: { name: 'same' } }, monitor: { ip: ['127.0.0.1'], status: 'up' } }
)
).toBe(-1);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { get, sortBy } from 'lodash';
import { QueryContext } from './query_context';
import {
Check,
Expand Down Expand Up @@ -245,17 +244,17 @@ export const enrichMonitorGroups: MonitorEnricher = async (

const items = await queryContext.search(params);

const monitorBuckets = get(items, 'aggregations.monitors.buckets', []);
const monitorBuckets = items?.aggregations?.monitors?.buckets ?? [];

const monitorIds: string[] = [];
const summaries: MonitorSummary[] = monitorBuckets.map((monitor: any) => {
const monitorId = get(monitor, 'key.monitor_id');
const monitorId = monitor.key.monitor_id;
monitorIds.push(monitorId);
const state: any = monitor.state?.value;
state.timestamp = state['@timestamp'];
const { checks } = state;
if (checks) {
state.checks = sortBy(checks, checksSortBy);
if (Array.isArray(checks)) {
checks.sort(sortChecksBy);
state.checks = state.checks.map((check: any) => ({
...check,
timestamp: check['@timestamp'],
Expand All @@ -276,7 +275,11 @@ export const enrichMonitorGroups: MonitorEnricher = async (
histogram: histogramMap[summary.monitor_id],
}));

const sortedResItems: any = sortBy(resItems, 'monitor_id');
const sortedResItems: any = resItems.sort((a, b) => {
if (a.monitor_id === b.monitor_id) return 0;
return a.monitor_id > b.monitor_id ? 1 : -1;
});

if (queryContext.pagination.sortOrder === SortOrder.DESC) {
sortedResItems.reverse();
}
Expand Down Expand Up @@ -378,4 +381,29 @@ const cursorDirectionToOrder = (cd: CursorDirection): 'asc' | 'desc' => {
return CursorDirection[cd] === CursorDirection.AFTER ? 'asc' : 'desc';
};

const checksSortBy = (check: Check) => [get(check, 'observer.geo.name'), get(check, 'monitor.ip')];
const getStringValue = (value: string | Array<string | null> | null | undefined): string => {
if (Array.isArray(value)) {
value.sort();
return value[0] ?? '';
}
return value ?? '';
};

export const sortChecksBy = (
a: Pick<Check, 'observer' | 'monitor'>,
b: Pick<Check, 'observer' | 'monitor'>
) => {
const nameA: string = a.observer?.geo?.name ?? '';
const nameB: string = b.observer?.geo?.name ?? '';

if (nameA === nameB) {
const ipA = getStringValue(a.monitor.ip);
const ipB = getStringValue(b.monitor.ip);

if (ipA === ipB) {
return 0;
}
return ipA > ipB ? 1 : -1;
}
return nameA > nameB ? 1 : -1;
};

0 comments on commit 567f1e4

Please sign in to comment.