[SIEM] Fixed timeline Epoch for zeek to not render in Epoch (#37290) (#37432)

## Summary
  * Added a few functions to test for Epoch and correct things where they can
  * Added unit tests where there were none
  * Added unit test that exercises the failure (TDD)
  * Fixed the unit test and ensured the other unit tests still run
  * https://github.com/elastic/ingest-dev/issues/280

Before fix:
<img width="1272" alt="broken" src="https://user-images.githubusercontent.com/1151048/58518929-89375000-816e-11e9-858b-21daefc8b19c.png">

After fix:
<img width="1091" alt="Screen Shot 2019-05-28 at 5 29 09 PM" src="https://user-images.githubusercontent.com/1151048/58518937-8d636d80-816e-11e9-9ba8-dfd3fd054416.png">

### Checklist

Use ~~strikethroughs~~ to remove checklist items you don't feel are applicable to this PR.

~~- [ ] This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility)~~
~~- [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md)~~
~~- [ ] [Documentation](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#writing-documentation) was added for features that require explanation or tutorials~~

- [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios

~~- [ ] This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist)~~

### For maintainers

~~- [ ] This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~~
~~- [ ] This includes a feature addition or change that requires a release note and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~~
This commit is contained in:
Frank Hassanabad 2019-05-29 18:45:49 -06:00 committed by GitHub
parent fdf128e10e
commit 57918d5b2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 211 additions and 67 deletions

View file

@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PreferenceFormattedDate rendering renders correctly against snapshot 1`] = `
exports[`formatted_date PreferenceFormattedDate rendering renders correctly against snapshot 1`] = `
<Component
value={2019-02-25T22:27:05.000Z}
/>

View file

@ -10,70 +10,200 @@ import moment from 'moment-timezone';
import * as React from 'react';
import { AppTestingFrameworkAdapter } from '../../lib/adapters/framework/testing_framework_adapter';
import { mockFrameworks } from '../../mock';
import { mockFrameworks, TestProviders } from '../../mock';
import { KibanaConfigContext, PreferenceFormattedDate } from '.';
import { KibanaConfigContext, PreferenceFormattedDate, FormattedDate, getMaybeDate } from '.';
import { getEmptyValue } from '../empty_value';
describe('PreferenceFormattedDate', () => {
describe('rendering', () => {
const isoDateString = '2019-02-25T22:27:05.000Z';
const isoDate = new Date(isoDateString);
const configFormattedDateString = (
dateString: string,
config: Partial<AppTestingFrameworkAdapter>
): string =>
moment
.tz(
dateString,
config.dateFormatTz! === 'Browser' ? config.timezone! : config.dateFormatTz!
)
.format(config.dateFormat);
describe('formatted_date', () => {
describe('PreferenceFormattedDate', () => {
describe('rendering', () => {
const isoDateString = '2019-02-25T22:27:05.000Z';
const isoDate = new Date(isoDateString);
const configFormattedDateString = (
dateString: string,
config: Partial<AppTestingFrameworkAdapter>
): string =>
moment
.tz(
dateString,
config.dateFormatTz! === 'Browser' ? config.timezone! : config.dateFormatTz!
)
.format(config.dateFormat);
test('renders correctly against snapshot', () => {
const wrapper = shallow(<PreferenceFormattedDate value={isoDate} />);
expect(toJson(wrapper)).toMatchSnapshot();
test('renders correctly against snapshot', () => {
const wrapper = shallow(<PreferenceFormattedDate value={isoDate} />);
expect(toJson(wrapper)).toMatchSnapshot();
});
test('it renders the UTC ISO8601 date string supplied when no configuration exists', () => {
const wrapper = mount(
<KibanaConfigContext.Provider value={{}}>
<PreferenceFormattedDate value={isoDate} />
</KibanaConfigContext.Provider>
);
expect(wrapper.text()).toEqual(isoDateString);
});
test('it renders the UTC ISO8601 date supplied when the default configuration exists', () => {
const wrapper = mount(
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
<PreferenceFormattedDate value={isoDate} />
</KibanaConfigContext.Provider>
);
expect(wrapper.text()).toEqual(
configFormattedDateString(isoDateString, mockFrameworks.default_UTC)
);
});
test('it renders the correct tz when the default browser configuration exists', () => {
const wrapper = mount(
<KibanaConfigContext.Provider value={mockFrameworks.default_browser}>
<PreferenceFormattedDate value={isoDate} />
</KibanaConfigContext.Provider>
);
expect(wrapper.text()).toEqual(
configFormattedDateString(isoDateString, mockFrameworks.default_browser)
);
});
test('it renders the correct tz when a non-UTC configuration exists', () => {
const wrapper = mount(
<KibanaConfigContext.Provider value={mockFrameworks.default_MT}>
<PreferenceFormattedDate value={isoDate} />
</KibanaConfigContext.Provider>
);
expect(wrapper.text()).toEqual(
configFormattedDateString(isoDateString, mockFrameworks.default_MT)
);
});
});
});
describe('FormattedDate', () => {
describe('rendering', () => {
test('it renders against a numeric epoch', () => {
const wrapper = mount(
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
<FormattedDate fieldName="@timestamp" value={1559079339000} />
</KibanaConfigContext.Provider>
);
expect(wrapper.text()).toEqual('May 28, 2019 @ 21:35:39.000');
});
test('it renders against a string epoch', () => {
const wrapper = mount(
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
<FormattedDate fieldName="@timestamp" value={'1559079339000'} />
</KibanaConfigContext.Provider>
);
expect(wrapper.text()).toEqual('May 28, 2019 @ 21:35:39.000');
});
test('it renders against a ISO string', () => {
const wrapper = mount(
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
<FormattedDate fieldName="@timestamp" value={'2019-05-28T22:04:49.957Z'} />
</KibanaConfigContext.Provider>
);
expect(wrapper.text()).toEqual('May 28, 2019 @ 22:04:49.957');
});
test('it renders against an empty string as an empty string placeholder', () => {
const wrapper = mount(
<TestProviders>
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
<FormattedDate fieldName="@timestamp" value={''} />
</KibanaConfigContext.Provider>
</TestProviders>
);
expect(wrapper.text()).toEqual('(Empty String)');
});
test('it renders against an null as a EMPTY_VALUE', () => {
const wrapper = mount(
<TestProviders>
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
<FormattedDate fieldName="@timestamp" value={null} />
</KibanaConfigContext.Provider>
</TestProviders>
);
expect(wrapper.text()).toEqual(getEmptyValue());
});
test('it renders against an undefined as a EMPTY_VALUE', () => {
const wrapper = mount(
<TestProviders>
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
<FormattedDate fieldName="@timestamp" value={undefined} />
</KibanaConfigContext.Provider>
</TestProviders>
);
expect(wrapper.text()).toEqual(getEmptyValue());
});
test('it renders against an invalid date time as just the string its self', () => {
const wrapper = mount(
<TestProviders>
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
<FormattedDate fieldName="@timestamp" value={'Rebecca Evan Braden'} />
</KibanaConfigContext.Provider>
</TestProviders>
);
expect(wrapper.text()).toEqual('Rebecca Evan Braden');
});
});
});
describe('getMaybeDate', () => {
test('returns empty string as invalid date', () => {
expect(getMaybeDate('').isValid()).toBe(false);
});
test('it renders the UTC ISO8601 date string supplied when no configuration exists', () => {
const wrapper = mount(
<KibanaConfigContext.Provider value={{}}>
<PreferenceFormattedDate value={isoDate} />
</KibanaConfigContext.Provider>
);
expect(wrapper.text()).toEqual(isoDateString);
test('returns string with empty spaces as invalid date', () => {
expect(getMaybeDate(' ').isValid()).toBe(false);
});
test('it renders the UTC ISO8601 date supplied when the default configuration exists', () => {
const wrapper = mount(
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
<PreferenceFormattedDate value={isoDate} />
</KibanaConfigContext.Provider>
);
expect(wrapper.text()).toEqual(
configFormattedDateString(isoDateString, mockFrameworks.default_UTC)
test('returns string date time as valid date', () => {
expect(getMaybeDate('2019-05-28T23:05:28.405Z').isValid()).toBe(true);
});
test('returns string date time as the date we expect', () => {
expect(getMaybeDate('2019-05-28T23:05:28.405Z').toISOString()).toBe(
'2019-05-28T23:05:28.405Z'
);
});
test('it renders the correct tz when the default browser configuration exists', () => {
const wrapper = mount(
<KibanaConfigContext.Provider value={mockFrameworks.default_browser}>
<PreferenceFormattedDate value={isoDate} />
</KibanaConfigContext.Provider>
);
expect(wrapper.text()).toEqual(
configFormattedDateString(isoDateString, mockFrameworks.default_browser)
);
test('returns plain string number as epoch as valid date', () => {
expect(getMaybeDate('1559084770612').isValid()).toBe(true);
});
test('it renders the correct tz when a non-UTC configuration exists', () => {
const wrapper = mount(
<KibanaConfigContext.Provider value={mockFrameworks.default_MT}>
<PreferenceFormattedDate value={isoDate} />
</KibanaConfigContext.Provider>
);
expect(wrapper.text()).toEqual(
configFormattedDateString(isoDateString, mockFrameworks.default_MT)
);
test('returns plain string number as the date we expect', () => {
expect(
getMaybeDate('1559084770612')
.toDate()
.toISOString()
).toBe('2019-05-28T23:06:10.612Z');
});
test('returns plain number as epoch as valid date', () => {
expect(getMaybeDate(1559084770612).isValid()).toBe(true);
});
test('returns plain number as epoch as the date we expect', () => {
expect(
getMaybeDate(1559084770612)
.toDate()
.toISOString()
).toBe('2019-05-28T23:06:10.612Z');
});
test('returns a short date time string as an epoch (sadly) so this is ambiguous', () => {
expect(
getMaybeDate('20190101')
.toDate()
.toISOString()
).toBe('1970-01-01T05:36:30.101Z');
});
});
});

View file

@ -8,6 +8,7 @@ import moment from 'moment-timezone';
import * as React from 'react';
import { pure } from 'recompose';
import { isString } from 'lodash/fp';
import { AppKibanaFrameworkAdapter } from '../../lib/adapters/framework/kibana_framework_adapter';
import { getOrEmptyTagFromValue } from '../empty_value';
import { LocalizedDateTooltip } from '../localized_date_tooltip';
@ -26,6 +27,19 @@ export const PreferenceFormattedDate = pure<{ value: Date }>(({ value }) => (
</KibanaConfigContext.Consumer>
));
export const getMaybeDate = (value: string | number): moment.Moment => {
if (isString(value) && value.trim() !== '') {
const maybeDate = moment(new Date(value));
if (maybeDate.isValid() || isNaN(+value)) {
return maybeDate;
} else {
return moment(new Date(+value));
}
} else {
return moment(new Date(value));
}
};
/**
* Renders the specified date value in a format determined by the user's preferences,
* with a tooltip that renders:
@ -37,18 +51,18 @@ export const PreferenceFormattedDate = pure<{ value: Date }>(({ value }) => (
export const FormattedDate = pure<{
fieldName: string;
value?: string | number | null;
}>(({ value, fieldName }) => {
if (value == null) {
return getOrEmptyTagFromValue(value);
}>(
({ value, fieldName }): JSX.Element => {
if (value == null) {
return getOrEmptyTagFromValue(value);
}
const maybeDate = getMaybeDate(value);
return maybeDate.isValid() ? (
<LocalizedDateTooltip date={maybeDate.toDate()} fieldName={fieldName}>
<PreferenceFormattedDate value={maybeDate.toDate()} />
</LocalizedDateTooltip>
) : (
getOrEmptyTagFromValue(value)
);
}
const maybeDate = moment(new Date(value));
return maybeDate.isValid() ? (
<LocalizedDateTooltip date={maybeDate.toDate()} fieldName={fieldName}>
<PreferenceFormattedDate value={new Date(value)} />
</LocalizedDateTooltip>
) : (
getOrEmptyTagFromValue(value)
);
});
);