Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alerting/fix flaky instance test #58994

Merged
merged 19 commits into from
Mar 11, 2020
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
cd67743
remove utc cast in hope that it explains the random 1 sec variance in…
gmmorris Mar 1, 2020
408534e
added logging to aid in identifying source of flakyness
gmmorris Mar 1, 2020
1347c73
Merge remote-tracking branch 'upstream/master'
gmmorris Mar 1, 2020
0fbb65d
Merge branch 'master' into alerting/fix-flaky-instance-test
elasticmachine Mar 2, 2020
301de05
Merge branch 'master' into alerting/fix-flaky-instance-test
elasticmachine Mar 2, 2020
d678379
move text in details header to make it testable
gmmorris Mar 2, 2020
0b3a9af
Merge branch 'master' into alerting/fix-flaky-instance-test
elasticmachine Mar 3, 2020
c8c88e9
Merge branch 'master' into alerting/fix-flaky-instance-test
elasticmachine Mar 3, 2020
29aac90
Merge branch 'master' into alerting/fix-flaky-instance-test
gmmorris Mar 3, 2020
9e9eece
Merge branch 'alerting/fix-flaky-instance-test' of github.com:gmmorri…
gmmorris Mar 3, 2020
a50bd2b
fixed test broken by BETA tag
gmmorris Mar 3, 2020
4eba31a
Merge branch 'master' into alerting/fix-flaky-instance-test
elasticmachine Mar 9, 2020
218d606
Merge branch 'master' into alerting/fix-flaky-instance-test
elasticmachine Mar 10, 2020
36be30b
expose durtion epoch on hidden field for more reliable testing
gmmorris Mar 10, 2020
ea98883
Merge branch 'alerting/fix-flaky-instance-test' of github.com:gmmorri…
gmmorris Mar 10, 2020
aa8f020
Merge branch 'master' into alerting/fix-flaky-instance-test
gmmorris Mar 10, 2020
290ecc9
fixed typo
gmmorris Mar 10, 2020
707a517
simplified duartion function
gmmorris Mar 10, 2020
078e7eb
no need for 30s window anymore
gmmorris Mar 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('alert_details', () => {
).containsMatchingElement(
<EuiTitle size="m">
<h1>
{alert.name}
<span>{alert.name}</span>
&emsp;
<EuiBetaBadge
label="Beta"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ export const AlertDetails: React.FunctionComponent<AlertDetailsProps> = ({
<EuiPageContentHeader>
<EuiPageContentHeaderSection>
<EuiTitle size="m">
<h1 data-test-subj="alertDetailsTitle">
{alert.name}
<h1>
<span data-test-subj="alertDetailsTitle">{alert.name}</span>
&emsp;
<EuiBetaBadge
label="Beta"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@
import * as React from 'react';
import uuid from 'uuid';
import { shallow } from 'enzyme';
import { AlertInstances, AlertInstanceListItem, alertInstanceToListItem } from './alert_instances';
import {
AlertInstances,
AlertInstanceListItem,
alertInstanceToListItem,
durationSince,
} from './alert_instances';
import { Alert, AlertTaskState, RawAlertInstance } from '../../../../types';
import { EuiBasicTable } from '@elastic/eui';

const fakeNow = new Date('2020-02-09T23:15:41.941Z');
const fake2MinutesAgo = new Date('2020-02-09T23:13:41.941Z');

const durationSinceEpoch = durationSince(fakeNow.getTime());

const mockAPIs = {
muteAlertInstance: jest.fn(),
unmuteAlertInstance: jest.fn(),
Expand All @@ -37,8 +44,18 @@ describe('alert_instances', () => {

const alertState = mockAlertState();
const instances: AlertInstanceListItem[] = [
alertInstanceToListItem(alert, 'first_instance', alertState.alertInstances!.first_instance),
alertInstanceToListItem(alert, 'second_instance', alertState.alertInstances!.second_instance),
alertInstanceToListItem(
durationSinceEpoch,
alert,
'first_instance',
alertState.alertInstances!.first_instance
),
alertInstanceToListItem(
durationSinceEpoch,
alert,
'second_instance',
alertState.alertInstances!.second_instance
),
];

expect(
Expand All @@ -48,6 +65,24 @@ describe('alert_instances', () => {
).toEqual(instances);
});

it('render a hidden field with durtation epoch', () => {
gmmorris marked this conversation as resolved.
Show resolved Hide resolved
const alert = mockAlert();
const alertState = mockAlertState();

expect(
shallow(
<AlertInstances
durationEpoch={fake2MinutesAgo.getTime()}
{...mockAPIs}
alert={alert}
alertState={alertState}
/>
)
.find('[name="alertInstancesDurationEpoch"]')
.prop('value')
).toEqual(fake2MinutesAgo.getTime());
});

it('render all active alert instances', () => {
const alert = mockAlert();
const instances = {
Expand Down Expand Up @@ -75,8 +110,8 @@ describe('alert_instances', () => {
.find(EuiBasicTable)
.prop('items')
).toEqual([
alertInstanceToListItem(alert, 'us-central', instances['us-central']),
alertInstanceToListItem(alert, 'us-east', instances['us-east']),
alertInstanceToListItem(durationSinceEpoch, alert, 'us-central', instances['us-central']),
alertInstanceToListItem(durationSinceEpoch, alert, 'us-east', instances['us-east']),
]);
});

Expand All @@ -98,8 +133,8 @@ describe('alert_instances', () => {
.find(EuiBasicTable)
.prop('items')
).toEqual([
alertInstanceToListItem(alert, 'us-west'),
alertInstanceToListItem(alert, 'us-east'),
alertInstanceToListItem(durationSinceEpoch, alert, 'us-west'),
alertInstanceToListItem(durationSinceEpoch, alert, 'us-east'),
]);
});
});
Expand All @@ -117,7 +152,7 @@ describe('alertInstanceToListItem', () => {
},
};

expect(alertInstanceToListItem(alert, 'id', instance)).toEqual({
expect(alertInstanceToListItem(durationSinceEpoch, alert, 'id', instance)).toEqual({
instance: 'id',
status: { label: 'Active', healthColor: 'primary' },
start,
Expand All @@ -140,7 +175,7 @@ describe('alertInstanceToListItem', () => {
},
};

expect(alertInstanceToListItem(alert, 'id', instance)).toEqual({
expect(alertInstanceToListItem(durationSinceEpoch, alert, 'id', instance)).toEqual({
instance: 'id',
status: { label: 'Active', healthColor: 'primary' },
start,
Expand All @@ -153,7 +188,7 @@ describe('alertInstanceToListItem', () => {
const alert = mockAlert();
const instance: RawAlertInstance = {};

expect(alertInstanceToListItem(alert, 'id', instance)).toEqual({
expect(alertInstanceToListItem(durationSinceEpoch, alert, 'id', instance)).toEqual({
instance: 'id',
status: { label: 'Active', healthColor: 'primary' },
start: undefined,
Expand All @@ -168,7 +203,7 @@ describe('alertInstanceToListItem', () => {
meta: {},
};

expect(alertInstanceToListItem(alert, 'id', instance)).toEqual({
expect(alertInstanceToListItem(durationSinceEpoch, alert, 'id', instance)).toEqual({
instance: 'id',
status: { label: 'Active', healthColor: 'primary' },
start: undefined,
Expand All @@ -181,7 +216,7 @@ describe('alertInstanceToListItem', () => {
const alert = mockAlert({
mutedInstanceIds: ['id'],
});
expect(alertInstanceToListItem(alert, 'id')).toEqual({
expect(alertInstanceToListItem(durationSinceEpoch, alert, 'id')).toEqual({
instance: 'id',
status: { label: 'Inactive', healthColor: 'subdued' },
start: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type AlertInstancesProps = {
alert: Alert;
alertState: AlertTaskState;
requestRefresh: () => Promise<void>;
durationEpoch?: number;
} & Pick<AlertApis, 'muteAlertInstance' | 'unmuteAlertInstance'>;

export const alertInstancesTableColumns = (
Expand Down Expand Up @@ -134,18 +135,20 @@ export function AlertInstances({
muteAlertInstance,
unmuteAlertInstance,
requestRefresh,
durationEpoch = Date.now(),
}: AlertInstancesProps) {
const [pagination, setPagination] = useState<Pagination>({
index: 0,
size: DEFAULT_SEARCH_PAGE_SIZE,
});

const durationSinceEpoch = durationSince(durationEpoch);
gmmorris marked this conversation as resolved.
Show resolved Hide resolved
const mergedAlertInstances = [
...Object.entries(alertInstances).map(([instanceId, instance]) =>
alertInstanceToListItem(alert, instanceId, instance)
alertInstanceToListItem(durationSinceEpoch, alert, instanceId, instance)
),
...difference(alert.mutedInstanceIds, Object.keys(alertInstances)).map(instanceId =>
alertInstanceToListItem(alert, instanceId)
alertInstanceToListItem(durationSinceEpoch, alert, instanceId)
),
];
const pageOfAlertInstances = getPage(mergedAlertInstances, pagination);
Expand All @@ -158,25 +161,33 @@ export function AlertInstances({
};

return (
<EuiBasicTable
items={pageOfAlertInstances}
pagination={{
pageIndex: pagination.index,
pageSize: pagination.size,
totalItemCount: mergedAlertInstances.length,
}}
onChange={({ page: changedPage }: { page: Pagination }) => {
setPagination(changedPage);
}}
rowProps={() => ({
'data-test-subj': 'alert-instance-row',
})}
cellProps={() => ({
'data-test-subj': 'cell',
})}
columns={alertInstancesTableColumns(onMuteAction)}
data-test-subj="alertInstancesList"
/>
<Fragment>
<input
type="hidden"
data-test-subj="alertInstancesDurationEpoch"
name="alertInstancesDurationEpoch"
value={durationEpoch}
/>
<EuiBasicTable
items={pageOfAlertInstances}
pagination={{
pageIndex: pagination.index,
pageSize: pagination.size,
totalItemCount: mergedAlertInstances.length,
}}
onChange={({ page: changedPage }: { page: Pagination }) => {
setPagination(changedPage);
}}
rowProps={() => ({
'data-test-subj': 'alert-instance-row',
})}
cellProps={() => ({
'data-test-subj': 'cell',
})}
columns={alertInstancesTableColumns(onMuteAction)}
data-test-subj="alertInstancesList"
/>
</Fragment>
);
}
export const AlertInstancesWithApi = withBulkAlertOperations(AlertInstances);
Expand Down Expand Up @@ -207,9 +218,11 @@ const INACTIVE_LABEL = i18n.translate(
{ defaultMessage: 'Inactive' }
);

const durationSince = (start?: Date) => (start ? Date.now() - start.getTime() : 0);
export const durationSince = (durationEpoch: number) => (startTime?: number) =>
startTime ? durationEpoch - startTime : 0;

export function alertInstanceToListItem(
durationSinceEpoch: (startTime: number) => number,
alert: Alert,
instanceId: string,
instance?: RawAlertInstance
Expand All @@ -221,7 +234,7 @@ export function alertInstanceToListItem(
? { label: ACTIVE_LABEL, healthColor: 'primary' }
: { label: INACTIVE_LABEL, healthColor: 'subdued' },
start: instance?.meta?.lastScheduledActions?.date,
duration: durationSince(instance?.meta?.lastScheduledActions?.date),
duration: durationSinceEpoch(instance?.meta?.lastScheduledActions?.date?.getTime() ?? 0),
isMuted,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
const alerting = getService('alerting');
const retry = getService('retry');

// FLAKY: https://github.com/elastic/kibana/issues/57426
describe.skip('Alert Details', function() {
describe('Alert Details', function() {
describe('Header', function() {
const testRunUuid = uuid.v4();
before(async () => {
Expand Down Expand Up @@ -206,8 +205,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});

it('renders the active alert instances', async () => {
const testBeganAt = moment().utc();

// Verify content
await testSubjects.existOrFail('alertInstancesList');

Expand All @@ -219,30 +216,42 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
meta: {
lastScheduledActions: { date },
},
}) => moment(date).utc()
}) => date
);

log.debug(`API RESULT: ${JSON.stringify(dateOnAllInstances)}`);

const instancesList = await pageObjects.alertDetailsUI.getAlertInstancesList();
expect(instancesList.map(instance => omit(instance, 'duration'))).to.eql([
{
instance: 'us-central',
status: 'Active',
start: dateOnAllInstances['us-central'].format('D MMM YYYY @ HH:mm:ss'),
start: moment(dateOnAllInstances['us-central'])
.utc()
.format('D MMM YYYY @ HH:mm:ss'),
},
{
instance: 'us-east',
status: 'Active',
start: dateOnAllInstances['us-east'].format('D MMM YYYY @ HH:mm:ss'),
start: moment(dateOnAllInstances['us-east'])
.utc()
.format('D MMM YYYY @ HH:mm:ss'),
},
{
instance: 'us-west',
status: 'Active',
start: dateOnAllInstances['us-west'].format('D MMM YYYY @ HH:mm:ss'),
start: moment(dateOnAllInstances['us-west'])
.utc()
.format('D MMM YYYY @ HH:mm:ss'),
},
]);

const durationEpoch = moment(
await pageObjects.alertDetailsUI.getAlertInstanceDurationEpoch()
).utc();

const durationFromInstanceTillPageLoad = mapValues(dateOnAllInstances, date =>
moment.duration(testBeganAt.diff(moment(date).utc()))
moment.duration(durationEpoch.diff(moment(date).utc()))
);
instancesList
.map(alertInstance => ({
Expand All @@ -258,13 +267,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
}),
}))
.forEach(({ id, duration }) => {
// make sure the duration is within a 10 second range which is
// make sure the duration is within a 30 second range which is
// good enough as the alert interval is 1m, so we know it is a fresh value
expect(duration.as('milliseconds')).to.greaterThan(
durationFromInstanceTillPageLoad[id].subtract(1000 * 10).as('milliseconds')
durationFromInstanceTillPageLoad[id].subtract(1000 * 30).as('milliseconds')
);
expect(duration.as('milliseconds')).to.lessThan(
durationFromInstanceTillPageLoad[id].add(1000 * 10).as('milliseconds')
durationFromInstanceTillPageLoad[id].add(1000 * 30).as('milliseconds')
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ export function AlertDetailsPageProvider({ getService }: FtrProviderContext) {
};
});
},
async getAlertInstanceDurationEpoch(): Promise<number> {
const alertInstancesDurationEpoch = await find.byCssSelector(
'input[data-test-subj="alertInstancesDurationEpoch"]'
);
return parseInt(await alertInstancesDurationEpoch.getAttribute('value'), 10);
},
async clickAlertInstanceMuteButton(instance: string) {
const muteAlertInstanceButton = await testSubjects.find(
`muteAlertInstanceButton_${instance}`
Expand Down