mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[ML] Tests for ML annotations feature. (#27994)
Adds unit/integration tests for various parts of the code base affected by the annotations feature.
This commit is contained in:
parent
3496dff912
commit
99f99291ef
15 changed files with 711 additions and 1 deletions
|
@ -0,0 +1,135 @@
|
||||||
|
{
|
||||||
|
"job_id": "farequote",
|
||||||
|
"job_type": "anomaly_detector",
|
||||||
|
"job_version": "7.0.0",
|
||||||
|
"description": "",
|
||||||
|
"create_time": 1546418356716,
|
||||||
|
"finished_time": 1546418359427,
|
||||||
|
"established_model_memory": 42102,
|
||||||
|
"analysis_config": {
|
||||||
|
"bucket_span": "15m",
|
||||||
|
"summary_count_field_name": "doc_count",
|
||||||
|
"detectors": [
|
||||||
|
{
|
||||||
|
"detector_description": "count",
|
||||||
|
"function": "count",
|
||||||
|
"detector_index": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"influencers": []
|
||||||
|
},
|
||||||
|
"analysis_limits": {
|
||||||
|
"model_memory_limit": "10mb",
|
||||||
|
"categorization_examples_limit": 4
|
||||||
|
},
|
||||||
|
"data_description": {
|
||||||
|
"time_field": "@timestamp",
|
||||||
|
"time_format": "epoch_ms"
|
||||||
|
},
|
||||||
|
"model_plot_config": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"model_snapshot_retention_days": 1,
|
||||||
|
"custom_settings": {
|
||||||
|
"created_by": "single-metric-wizard"
|
||||||
|
},
|
||||||
|
"model_snapshot_id": "1546418359",
|
||||||
|
"model_snapshot_min_version": "6.4.0",
|
||||||
|
"results_index_name": "shared",
|
||||||
|
"data_counts": {
|
||||||
|
"job_id": "farequote",
|
||||||
|
"processed_record_count": 479,
|
||||||
|
"processed_field_count": 479,
|
||||||
|
"input_bytes": 21554,
|
||||||
|
"input_field_count": 479,
|
||||||
|
"invalid_date_count": 0,
|
||||||
|
"missing_field_count": 0,
|
||||||
|
"out_of_order_timestamp_count": 0,
|
||||||
|
"empty_bucket_count": 0,
|
||||||
|
"sparse_bucket_count": 0,
|
||||||
|
"bucket_count": 478,
|
||||||
|
"earliest_record_timestamp": 1454804096000,
|
||||||
|
"latest_record_timestamp": 1455234298000,
|
||||||
|
"last_data_time": 1546418357578,
|
||||||
|
"input_record_count": 479
|
||||||
|
},
|
||||||
|
"model_size_stats": {
|
||||||
|
"job_id": "farequote",
|
||||||
|
"result_type": "model_size_stats",
|
||||||
|
"model_bytes": 42102,
|
||||||
|
"total_by_field_count": 3,
|
||||||
|
"total_over_field_count": 0,
|
||||||
|
"total_partition_field_count": 2,
|
||||||
|
"bucket_allocation_failures_count": 0,
|
||||||
|
"memory_status": "ok",
|
||||||
|
"log_time": 1546418359000,
|
||||||
|
"timestamp": 1455232500000
|
||||||
|
},
|
||||||
|
"datafeed_config": {
|
||||||
|
"datafeed_id": "datafeed-farequote",
|
||||||
|
"job_id": "farequote",
|
||||||
|
"query_delay": "115823ms",
|
||||||
|
"indices": [
|
||||||
|
"farequote"
|
||||||
|
],
|
||||||
|
"types": [],
|
||||||
|
"query": {
|
||||||
|
"bool": {
|
||||||
|
"must": [
|
||||||
|
{
|
||||||
|
"query_string": {
|
||||||
|
"query": "*",
|
||||||
|
"fields": [],
|
||||||
|
"type": "best_fields",
|
||||||
|
"default_operator": "or",
|
||||||
|
"max_determinized_states": 10000,
|
||||||
|
"enable_position_increments": true,
|
||||||
|
"fuzziness": "AUTO",
|
||||||
|
"fuzzy_prefix_length": 0,
|
||||||
|
"fuzzy_max_expansions": 50,
|
||||||
|
"phrase_slop": 0,
|
||||||
|
"analyze_wildcard": true,
|
||||||
|
"escape": false,
|
||||||
|
"auto_generate_synonyms_phrase_query": true,
|
||||||
|
"fuzzy_transpositions": true,
|
||||||
|
"boost": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"adjust_pure_negative": true,
|
||||||
|
"boost": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"aggregations": {
|
||||||
|
"buckets": {
|
||||||
|
"date_histogram": {
|
||||||
|
"field": "@timestamp",
|
||||||
|
"interval": 900000,
|
||||||
|
"offset": 0,
|
||||||
|
"order": {
|
||||||
|
"_key": "asc"
|
||||||
|
},
|
||||||
|
"keyed": false,
|
||||||
|
"min_doc_count": 0
|
||||||
|
},
|
||||||
|
"aggregations": {
|
||||||
|
"@timestamp": {
|
||||||
|
"max": {
|
||||||
|
"field": "@timestamp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scroll_size": 1000,
|
||||||
|
"chunking_config": {
|
||||||
|
"mode": "manual",
|
||||||
|
"time_span": "900000000ms"
|
||||||
|
},
|
||||||
|
"delayed_data_check_config": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"state": "stopped"
|
||||||
|
},
|
||||||
|
"state": "closed"
|
||||||
|
}
|
23
x-pack/plugins/ml/common/types/annotations.test.ts
Normal file
23
x-pack/plugins/ml/common/types/annotations.test.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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 { ANNOTATION_TYPE } from '../constants/annotations';
|
||||||
|
|
||||||
|
import { isAnnotation, isAnnotations } from './annotations';
|
||||||
|
|
||||||
|
describe('Types: Annotations', () => {
|
||||||
|
test('Minimal integrity check.', () => {
|
||||||
|
const annotation = {
|
||||||
|
job_id: 'id',
|
||||||
|
annotation: 'Annotation text',
|
||||||
|
timestamp: 0,
|
||||||
|
type: ANNOTATION_TYPE.ANNOTATION,
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(isAnnotation(annotation)).toBe(true);
|
||||||
|
expect(isAnnotations([annotation])).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
15
x-pack/plugins/ml/common/types/jobs.test.js
Normal file
15
x-pack/plugins/ml/common/types/jobs.test.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* 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 jobConfigFarequote from './__mocks__/job_config_farequote';
|
||||||
|
import { isMlJob, isMlJobs } from './jobs';
|
||||||
|
|
||||||
|
describe('Types: Jobs', () => {
|
||||||
|
test('Minimal integrity check.', () => {
|
||||||
|
expect(isMlJob(jobConfigFarequote)).toBe(true);
|
||||||
|
expect(isMlJobs([jobConfigFarequote])).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1455026177994,
|
||||||
|
"end_timestamp": 1455041968976,
|
||||||
|
"annotation": "Major spike.",
|
||||||
|
"job_id": "farequote",
|
||||||
|
"type": "annotation",
|
||||||
|
"create_time": 1546417097181,
|
||||||
|
"create_username": "<user unknown>",
|
||||||
|
"modified_time": 1546417097181,
|
||||||
|
"modified_username": "<user unknown>",
|
||||||
|
"_id": "KCCkDWgB_ZdQ1MFDSYPi"
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,126 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`AnnotationsTable Initialization with annotations prop. 1`] = `
|
||||||
|
<EuiInMemoryTable
|
||||||
|
className="eui-textOverflowWrap"
|
||||||
|
columns={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"field": "annotation",
|
||||||
|
"name": "Annotation",
|
||||||
|
"sortable": true,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"dataType": "date",
|
||||||
|
"field": "timestamp",
|
||||||
|
"name": "From",
|
||||||
|
"render": [Function],
|
||||||
|
"sortable": true,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"dataType": "date",
|
||||||
|
"field": "end_timestamp",
|
||||||
|
"name": "To",
|
||||||
|
"render": [Function],
|
||||||
|
"sortable": true,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"dataType": "date",
|
||||||
|
"field": "create_time",
|
||||||
|
"name": "Creation date",
|
||||||
|
"render": [Function],
|
||||||
|
"sortable": true,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"field": "create_username",
|
||||||
|
"name": "Created by",
|
||||||
|
"sortable": true,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"dataType": "date",
|
||||||
|
"field": "modified_time",
|
||||||
|
"name": "Last modified date",
|
||||||
|
"render": [Function],
|
||||||
|
"sortable": true,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"field": "modified_username",
|
||||||
|
"name": "Last modified by",
|
||||||
|
"sortable": true,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"align": "right",
|
||||||
|
"name": "View",
|
||||||
|
"render": [Function],
|
||||||
|
"width": "60px",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
compressed={true}
|
||||||
|
items={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"_id": "KCCkDWgB_ZdQ1MFDSYPi",
|
||||||
|
"annotation": "Major spike.",
|
||||||
|
"create_time": 1546417097181,
|
||||||
|
"create_username": "<user unknown>",
|
||||||
|
"end_timestamp": 1455041968976,
|
||||||
|
"job_id": "farequote",
|
||||||
|
"modified_time": 1546417097181,
|
||||||
|
"modified_username": "<user unknown>",
|
||||||
|
"timestamp": 1455026177994,
|
||||||
|
"type": "annotation",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
pagination={
|
||||||
|
Object {
|
||||||
|
"pageSizeOptions": Array [
|
||||||
|
5,
|
||||||
|
10,
|
||||||
|
25,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
responsive={true}
|
||||||
|
rowProps={[Function]}
|
||||||
|
sorting={
|
||||||
|
Object {
|
||||||
|
"sort": Object {
|
||||||
|
"direction": "asc",
|
||||||
|
"field": "timestamp",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`AnnotationsTable Initialization with job config prop. 1`] = `
|
||||||
|
<EuiFlexGroup
|
||||||
|
alignItems="stretch"
|
||||||
|
component="div"
|
||||||
|
direction="row"
|
||||||
|
gutterSize="l"
|
||||||
|
justifyContent="spaceAround"
|
||||||
|
responsive={true}
|
||||||
|
wrap={false}
|
||||||
|
>
|
||||||
|
<EuiFlexItem
|
||||||
|
component="div"
|
||||||
|
grow={false}
|
||||||
|
>
|
||||||
|
<EuiLoadingSpinner
|
||||||
|
size="l"
|
||||||
|
/>
|
||||||
|
</EuiFlexItem>
|
||||||
|
</EuiFlexGroup>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`AnnotationsTable Minimal initialization without props. 1`] = `
|
||||||
|
<EuiCallOut
|
||||||
|
color="primary"
|
||||||
|
iconType="iInCircle"
|
||||||
|
size="m"
|
||||||
|
title="No annotations created for this job"
|
||||||
|
/>
|
||||||
|
`;
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* 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 jobConfig from '../../../../common/types/__mocks__/job_config_farequote';
|
||||||
|
|
||||||
|
import ngMock from 'ng_mock';
|
||||||
|
import expect from 'expect.js';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
import { ml } from '../../../services/ml_api_service';
|
||||||
|
|
||||||
|
describe('ML - <ml-annotation-table>', () => {
|
||||||
|
let $scope;
|
||||||
|
let $compile;
|
||||||
|
|
||||||
|
beforeEach(ngMock.module('kibana'));
|
||||||
|
beforeEach(() => {
|
||||||
|
ngMock.inject(function ($injector) {
|
||||||
|
$compile = $injector.get('$compile');
|
||||||
|
const $rootScope = $injector.get('$rootScope');
|
||||||
|
$scope = $rootScope.$new();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
$scope.$destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Plain initialization doesn\'t throw an error', () => {
|
||||||
|
expect(() => {
|
||||||
|
$compile('<ml-annotation-table />')($scope);
|
||||||
|
}).to.not.throwError();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Initialization with empty annotations array doesn\'t throw an error', () => {
|
||||||
|
expect(() => {
|
||||||
|
$compile('<ml-annotation-table annotations="[]" />')($scope);
|
||||||
|
}).to.not.throwError();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Initialization with job config doesn\'t throw an error', () => {
|
||||||
|
const getAnnotationsStub = sinon.stub(ml.annotations, 'getAnnotations').resolves({ annotations: [] });
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
$scope.jobs = [jobConfig];
|
||||||
|
$compile('<ml-annotation-table jobs="jobs" />')($scope);
|
||||||
|
}).to.not.throwError();
|
||||||
|
|
||||||
|
getAnnotationsStub.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -109,7 +109,10 @@ class AnnotationsTable extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (this.props.annotations === undefined) {
|
if (
|
||||||
|
this.props.annotations === undefined &&
|
||||||
|
Array.isArray(this.props.jobs) && this.props.jobs.length > 0
|
||||||
|
) {
|
||||||
this.getAnnotations();
|
this.getAnnotations();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,6 +121,7 @@ class AnnotationsTable extends Component {
|
||||||
if (
|
if (
|
||||||
this.props.annotations === undefined &&
|
this.props.annotations === undefined &&
|
||||||
this.state.isLoading === false &&
|
this.state.isLoading === false &&
|
||||||
|
Array.isArray(this.props.jobs) && this.props.jobs.length > 0 &&
|
||||||
this.state.jobId !== this.props.jobs[0].job_id
|
this.state.jobId !== this.props.jobs[0].job_id
|
||||||
) {
|
) {
|
||||||
this.getAnnotations();
|
this.getAnnotations();
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* 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 jobConfig from '../../../common/types/__mocks__/job_config_farequote';
|
||||||
|
import mockAnnotations from './__mocks__/mock_annotations.json';
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { AnnotationsTable } from './annotations_table';
|
||||||
|
|
||||||
|
jest.mock('ui/chrome', () => ({
|
||||||
|
getBasePath: (path) => path,
|
||||||
|
addBasePath: () => {}
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('../../services/job_service', () => ({
|
||||||
|
mlJobService: {
|
||||||
|
getJob: jest.fn()
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('../../services/ml_api_service', () => ({
|
||||||
|
ml: {
|
||||||
|
annotations: {
|
||||||
|
getAnnotations: jest.fn().mockResolvedValue({ annotations: [] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('AnnotationsTable', () => {
|
||||||
|
test('Minimal initialization without props.', () => {
|
||||||
|
const wrapper = shallow(<AnnotationsTable />);
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Initialization with job config prop.', () => {
|
||||||
|
const wrapper = shallow(<AnnotationsTable jobs={[jobConfig]} />);
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Initialization with annotations prop.', () => {
|
||||||
|
const wrapper = shallow(<AnnotationsTable annotations={mockAnnotations} />);
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -19,6 +19,7 @@ describe('ML - Explorer Controller', () => {
|
||||||
const scope = $rootScope.$new();
|
const scope = $rootScope.$new();
|
||||||
$controller('MlExplorerController', { $scope: scope });
|
$controller('MlExplorerController', { $scope: scope });
|
||||||
|
|
||||||
|
expect(Array.isArray(scope.annotationsData)).to.be(true);
|
||||||
expect(Array.isArray(scope.anomalyChartRecords)).to.be(true);
|
expect(Array.isArray(scope.anomalyChartRecords)).to.be(true);
|
||||||
expect(scope.loading).to.be(true);
|
expect(scope.loading).to.be(true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`AnnotationDescriptionList Initialization with annotation. 1`] = `
|
||||||
|
<EuiDescriptionList
|
||||||
|
align="left"
|
||||||
|
className="ml-annotation-description-list"
|
||||||
|
compressed={false}
|
||||||
|
listItems={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"description": "farequote",
|
||||||
|
"title": "Job ID",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"description": "February 9th 2016, 13:56:17",
|
||||||
|
"title": "Start",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"description": "February 9th 2016, 18:19:28",
|
||||||
|
"title": "End",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"description": "January 2nd 2019, 08:18:17",
|
||||||
|
"title": "Created",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"description": "<user unknown>",
|
||||||
|
"title": "Created by",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"description": "January 2nd 2019, 08:18:17",
|
||||||
|
"title": "Last modified",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"description": "<user unknown>",
|
||||||
|
"title": "Modified by",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
textStyle="normal"
|
||||||
|
type="column"
|
||||||
|
/>
|
||||||
|
`;
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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 mockAnnotations from '../../../components/annotations_table/__mocks__/mock_annotations.json';
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import moment from 'moment-timezone';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { AnnotationDescriptionList } from './index';
|
||||||
|
|
||||||
|
describe('AnnotationDescriptionList', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
moment.tz.setDefault('UTC');
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
moment.tz.setDefault('Browser');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Initialization with annotation.', () => {
|
||||||
|
const wrapper = shallow(<AnnotationDescriptionList annotation={mockAnnotations[0]} />);
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,120 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`AnnotationFlyout Initialization. 1`] = `
|
||||||
|
<EuiFlyout
|
||||||
|
aria-labelledby="Add annotation"
|
||||||
|
closeButtonAriaLabel="Closes this dialog"
|
||||||
|
hideCloseButton={false}
|
||||||
|
maxWidth={false}
|
||||||
|
onClose={[MockFunction]}
|
||||||
|
ownFocus={false}
|
||||||
|
size="s"
|
||||||
|
>
|
||||||
|
<EuiFlyoutHeader
|
||||||
|
hasBorder={true}
|
||||||
|
>
|
||||||
|
<EuiTitle
|
||||||
|
size="s"
|
||||||
|
textTransform="none"
|
||||||
|
>
|
||||||
|
<h2
|
||||||
|
id="mlAnnotationFlyoutTitle"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
annotation
|
||||||
|
</h2>
|
||||||
|
</EuiTitle>
|
||||||
|
</EuiFlyoutHeader>
|
||||||
|
<EuiFlyoutBody>
|
||||||
|
<Component
|
||||||
|
annotation={
|
||||||
|
Object {
|
||||||
|
"_id": "KCCkDWgB_ZdQ1MFDSYPi",
|
||||||
|
"annotation": "Major spike.",
|
||||||
|
"create_time": 1546417097181,
|
||||||
|
"create_username": "<user unknown>",
|
||||||
|
"end_timestamp": 1455041968976,
|
||||||
|
"job_id": "farequote",
|
||||||
|
"modified_time": 1546417097181,
|
||||||
|
"modified_username": "<user unknown>",
|
||||||
|
"timestamp": 1455026177994,
|
||||||
|
"type": "annotation",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<EuiSpacer
|
||||||
|
size="m"
|
||||||
|
/>
|
||||||
|
<EuiFormRow
|
||||||
|
describedByIds={Array []}
|
||||||
|
fullWidth={true}
|
||||||
|
hasEmptyLabelSpace={false}
|
||||||
|
label="Annotation text"
|
||||||
|
>
|
||||||
|
<EuiTextArea
|
||||||
|
fullWidth={true}
|
||||||
|
isInvalid={false}
|
||||||
|
onChange={[MockFunction]}
|
||||||
|
placeholder="..."
|
||||||
|
resize="vertical"
|
||||||
|
value="Major spike."
|
||||||
|
/>
|
||||||
|
</EuiFormRow>
|
||||||
|
</EuiFlyoutBody>
|
||||||
|
<EuiFlyoutFooter>
|
||||||
|
<EuiFlexGroup
|
||||||
|
alignItems="stretch"
|
||||||
|
component="div"
|
||||||
|
direction="row"
|
||||||
|
gutterSize="l"
|
||||||
|
justifyContent="spaceBetween"
|
||||||
|
responsive={true}
|
||||||
|
wrap={false}
|
||||||
|
>
|
||||||
|
<EuiFlexItem
|
||||||
|
component="div"
|
||||||
|
grow={false}
|
||||||
|
>
|
||||||
|
<EuiButtonEmpty
|
||||||
|
color="primary"
|
||||||
|
flush="left"
|
||||||
|
iconSide="left"
|
||||||
|
iconType="cross"
|
||||||
|
onClick={[MockFunction]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</EuiButtonEmpty>
|
||||||
|
</EuiFlexItem>
|
||||||
|
<EuiFlexItem
|
||||||
|
component="div"
|
||||||
|
grow={false}
|
||||||
|
>
|
||||||
|
<EuiButtonEmpty
|
||||||
|
color="danger"
|
||||||
|
iconSide="left"
|
||||||
|
onClick={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</EuiButtonEmpty>
|
||||||
|
</EuiFlexItem>
|
||||||
|
<EuiFlexItem
|
||||||
|
component="div"
|
||||||
|
grow={false}
|
||||||
|
>
|
||||||
|
<EuiButton
|
||||||
|
color="primary"
|
||||||
|
fill={true}
|
||||||
|
iconSide="left"
|
||||||
|
isDisabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</EuiButton>
|
||||||
|
</EuiFlexItem>
|
||||||
|
</EuiFlexGroup>
|
||||||
|
</EuiFlyoutFooter>
|
||||||
|
</EuiFlyout>
|
||||||
|
`;
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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 mockAnnotations from '../../../components/annotations_table/__mocks__/mock_annotations.json';
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { AnnotationFlyout } from './index';
|
||||||
|
|
||||||
|
describe('AnnotationFlyout', () => {
|
||||||
|
test('Initialization.', () => {
|
||||||
|
const props = {
|
||||||
|
annotation: mockAnnotations[0],
|
||||||
|
cancelAction: jest.fn(),
|
||||||
|
controlFunc: jest.fn(),
|
||||||
|
deleteAction: jest.fn(),
|
||||||
|
saveAction: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = shallow(<AnnotationFlyout {...props} />);
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,54 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1454810815950,
|
||||||
|
"end_timestamp": 1455060155890,
|
||||||
|
"annotation": "Still learning the model.",
|
||||||
|
"job_id": "farequote",
|
||||||
|
"type": "annotation",
|
||||||
|
"create_time": 1546530633618,
|
||||||
|
"create_username": "<user unknown>",
|
||||||
|
"modified_time": 1546530633618,
|
||||||
|
"modified_username": "<user unknown>",
|
||||||
|
"_id": "6bpoFGgBrdsAtoAOt0WT",
|
||||||
|
"key": "A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1455020901845,
|
||||||
|
"end_timestamp": 1455075725930,
|
||||||
|
"annotation": "Overlapping annotation.",
|
||||||
|
"job_id": "farequote",
|
||||||
|
"type": "annotation",
|
||||||
|
"create_time": 1546530659999,
|
||||||
|
"create_username": "<user unknown>",
|
||||||
|
"modified_time": 1546530659999,
|
||||||
|
"modified_username": "<user unknown>",
|
||||||
|
"_id": "6rppFGgBrdsAtoAOHkWg",
|
||||||
|
"key": "B"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1455027864892,
|
||||||
|
"end_timestamp": 1455042003613,
|
||||||
|
"annotation": "Massive spike.",
|
||||||
|
"job_id": "farequote",
|
||||||
|
"type": "annotation",
|
||||||
|
"create_time": 1546512778313,
|
||||||
|
"create_username": "<user unknown>",
|
||||||
|
"modified_time": 1546512778313,
|
||||||
|
"modified_username": "<user unknown>",
|
||||||
|
"_id": "Gl5YE2gBBwRksc9URChP",
|
||||||
|
"key": "C"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1455063006742,
|
||||||
|
"end_timestamp": 1455230768443,
|
||||||
|
"annotation": "Learned the model.",
|
||||||
|
"job_id": "farequote",
|
||||||
|
"type": "annotation",
|
||||||
|
"create_time": 1546530615480,
|
||||||
|
"create_username": "<user unknown>",
|
||||||
|
"modified_time": 1546530615480,
|
||||||
|
"modified_username": "<user unknown>",
|
||||||
|
"_id": "6LpoFGgBrdsAtoAOcEW7",
|
||||||
|
"key": "D"
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* 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 mockAnnotationsOverlap from './__mocks__/mock_annotations_overlap.json';
|
||||||
|
|
||||||
|
import { getAnnotationLevels } from './timeseries_chart_annotations';
|
||||||
|
|
||||||
|
describe('Timeseries Chart Annotations: getAnnotationLevels()', () => {
|
||||||
|
test('getAnnotationLevels()', () => {
|
||||||
|
const levels = getAnnotationLevels(mockAnnotationsOverlap);
|
||||||
|
expect(levels).toEqual({ A: 0, B: 1, C: 2, D: 2 });
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue