mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
This adds tests to `server/models/annotation_service`. The tests include a check if the `.key` attribute of an annotation is properly removed from an annotation before indexing it.
This commit is contained in:
parent
06d9def36c
commit
c139d4ecab
5 changed files with 337 additions and 14 deletions
|
@ -0,0 +1,85 @@
|
|||
{
|
||||
"index": ".ml-annotations-read",
|
||||
"size": 500,
|
||||
"body": {
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{
|
||||
"query_string": {
|
||||
"query": "type:annotation",
|
||||
"analyze_wildcard": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"bool": {
|
||||
"must": [
|
||||
{
|
||||
"bool": {
|
||||
"must_not": [
|
||||
{
|
||||
"bool": {
|
||||
"filter": [
|
||||
{
|
||||
"range": {
|
||||
"timestamp": {
|
||||
"lte": 1454804100000,
|
||||
"format": "epoch_millis"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"end_timestamp": {
|
||||
"lte": 1454804100000,
|
||||
"format": "epoch_millis"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"bool": {
|
||||
"filter": [
|
||||
{
|
||||
"range": {
|
||||
"timestamp": {
|
||||
"gte": 1455233399999,
|
||||
"format": "epoch_millis"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"end_timestamp": {
|
||||
"gte": 1455233399999,
|
||||
"format": "epoch_millis"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"exists": {
|
||||
"field": "annotation"
|
||||
}
|
||||
},
|
||||
{
|
||||
"query_string": {
|
||||
"analyze_wildcard": false,
|
||||
"query": "job_id:jobIdMock"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"took": 1,
|
||||
"timed_out": false,
|
||||
"_shards": {
|
||||
"total": 1,
|
||||
"successful": 1,
|
||||
"skipped": 0,
|
||||
"failed": 0
|
||||
},
|
||||
"hits": {
|
||||
"total": {
|
||||
"value": 2,
|
||||
"relation": "eq"
|
||||
},
|
||||
"max_score": 0,
|
||||
"hits": [
|
||||
{
|
||||
"_index": ".ml-annotations-6",
|
||||
"_type": "doc",
|
||||
"_id": "T-CNvmgBQUJYQVn7TCPA",
|
||||
"_score": 0,
|
||||
"_source": {
|
||||
"timestamp": 1454928364298,
|
||||
"end_timestamp": 1455000642848,
|
||||
"annotation": "Annotation 1",
|
||||
"job_id": "jobIdMock",
|
||||
"type": "annotation",
|
||||
"create_time": 1549385157823,
|
||||
"create_username": "usernameMock",
|
||||
"modified_time": 1549448867514,
|
||||
"modified_username": "usernameMock"
|
||||
}
|
||||
},
|
||||
{
|
||||
"_index": ".ml-annotations-6",
|
||||
"_type": "doc",
|
||||
"_id": "3lVpvmgB5xYzd3PM-MSe",
|
||||
"_score": 0,
|
||||
"_source": {
|
||||
"timestamp": 1455024146013,
|
||||
"end_timestamp": 1455048912790,
|
||||
"annotation": "Annotation 2",
|
||||
"job_id": "jobIdMock",
|
||||
"type": "annotation",
|
||||
"create_time": 1549382842522,
|
||||
"create_username": "usernameMock",
|
||||
"modified_time": 1549448876306,
|
||||
"modified_username": "usernameMock"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* 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 getAnnotationsRequestMock from './__mocks__/get_annotations_request.json';
|
||||
import getAnnotationsResponseMock from './__mocks__/get_annotations_response.json';
|
||||
|
||||
import { ANNOTATION_TYPE } from '../../../common/constants/annotations';
|
||||
import { ML_ANNOTATIONS_INDEX_ALIAS_WRITE } from '../../../common/constants/index_patterns';
|
||||
import { Annotation, isAnnotations } from '../../../common/types/annotations';
|
||||
|
||||
import { DeleteParams, GetResponse, IndexAnnotationArgs } from './annotation';
|
||||
import { annotationServiceProvider } from './index';
|
||||
|
||||
const acknowledgedResponseMock = { acknowledged: true };
|
||||
|
||||
describe('annotation_service', () => {
|
||||
let callWithRequestSpy: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
callWithRequestSpy = jest.fn((action: string) => {
|
||||
switch (action) {
|
||||
case 'delete':
|
||||
case 'index':
|
||||
return Promise.resolve(acknowledgedResponseMock);
|
||||
case 'search':
|
||||
return Promise.resolve(getAnnotationsResponseMock);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteAnnotation()', () => {
|
||||
it('should delete annotation', async done => {
|
||||
const { deleteAnnotation } = annotationServiceProvider(callWithRequestSpy);
|
||||
|
||||
const annotationMockId = 'mockId';
|
||||
const deleteParamsMock: DeleteParams = {
|
||||
index: ML_ANNOTATIONS_INDEX_ALIAS_WRITE,
|
||||
id: annotationMockId,
|
||||
refresh: 'wait_for',
|
||||
type: 'doc',
|
||||
};
|
||||
|
||||
const response = await deleteAnnotation(annotationMockId);
|
||||
|
||||
expect(callWithRequestSpy.mock.calls[0][0]).toBe('delete');
|
||||
expect(callWithRequestSpy.mock.calls[0][1]).toEqual(deleteParamsMock);
|
||||
expect(response).toBe(acknowledgedResponseMock);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAnnotation()', () => {
|
||||
it('should get annotations for specific job', async done => {
|
||||
const { getAnnotations } = annotationServiceProvider(callWithRequestSpy);
|
||||
|
||||
const jobIdMock = 'jobIdMock';
|
||||
|
||||
const indexAnnotationArgsMock: IndexAnnotationArgs = {
|
||||
jobIds: [jobIdMock],
|
||||
earliestMs: 1454804100000,
|
||||
latestMs: 1455233399999,
|
||||
maxAnnotations: 500,
|
||||
};
|
||||
|
||||
const response: GetResponse = await getAnnotations(indexAnnotationArgsMock);
|
||||
|
||||
expect(callWithRequestSpy.mock.calls[0][0]).toBe('search');
|
||||
expect(callWithRequestSpy.mock.calls[0][1]).toEqual(getAnnotationsRequestMock);
|
||||
expect(Object.keys(response.annotations)).toHaveLength(1);
|
||||
expect(response.annotations[jobIdMock]).toHaveLength(2);
|
||||
expect(isAnnotations(response.annotations[jobIdMock])).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('indexAnnotation()', () => {
|
||||
it('should index annotation', async done => {
|
||||
const { indexAnnotation } = annotationServiceProvider(callWithRequestSpy);
|
||||
|
||||
const jobIdMock = 'jobIdMock';
|
||||
const annotationMock: Annotation = {
|
||||
annotation: 'Annotation text',
|
||||
job_id: jobIdMock,
|
||||
timestamp: 1454804100000,
|
||||
type: ANNOTATION_TYPE.ANNOTATION,
|
||||
};
|
||||
const usernameMock = 'usernameMock';
|
||||
|
||||
const response = await indexAnnotation(annotationMock, usernameMock);
|
||||
|
||||
expect(callWithRequestSpy.mock.calls[0][0]).toBe('index');
|
||||
|
||||
// test if the annotation has been correctly augmented
|
||||
const indexParamsCheck = callWithRequestSpy.mock.calls[0][1];
|
||||
const annotation = indexParamsCheck.body;
|
||||
expect(annotation.create_username).toBe(usernameMock);
|
||||
expect(annotation.modified_username).toBe(usernameMock);
|
||||
expect(typeof annotation.create_time).toBe('number');
|
||||
expect(typeof annotation.modified_time).toBe('number');
|
||||
|
||||
expect(response).toBe(acknowledgedResponseMock);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should remove ._id and .key before updating annotation', async done => {
|
||||
const { indexAnnotation } = annotationServiceProvider(callWithRequestSpy);
|
||||
|
||||
const jobIdMock = 'jobIdMock';
|
||||
const annotationMock: Annotation = {
|
||||
_id: 'mockId',
|
||||
annotation: 'Updated annotation text',
|
||||
job_id: jobIdMock,
|
||||
key: 'A',
|
||||
timestamp: 1454804100000,
|
||||
type: ANNOTATION_TYPE.ANNOTATION,
|
||||
};
|
||||
const usernameMock = 'usernameMock';
|
||||
|
||||
const response = await indexAnnotation(annotationMock, usernameMock);
|
||||
|
||||
expect(callWithRequestSpy.mock.calls[0][0]).toBe('index');
|
||||
|
||||
// test if the annotation has been correctly augmented
|
||||
const indexParamsCheck = callWithRequestSpy.mock.calls[0][1];
|
||||
const annotation = indexParamsCheck.body;
|
||||
expect(annotation.create_username).toBe(usernameMock);
|
||||
expect(annotation.modified_username).toBe(usernameMock);
|
||||
expect(typeof annotation.create_time).toBe('number');
|
||||
expect(typeof annotation.modified_time).toBe('number');
|
||||
expect(typeof annotation._id).toBe('undefined');
|
||||
expect(typeof annotation.key).toBe('undefined');
|
||||
|
||||
expect(response).toBe(acknowledgedResponseMock);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should update annotation text and the username for modified_username', async done => {
|
||||
const { getAnnotations, indexAnnotation } = annotationServiceProvider(callWithRequestSpy);
|
||||
|
||||
const jobIdMock = 'jobIdMock';
|
||||
|
||||
const indexAnnotationArgsMock: IndexAnnotationArgs = {
|
||||
jobIds: [jobIdMock],
|
||||
earliestMs: 1454804100000,
|
||||
latestMs: 1455233399999,
|
||||
maxAnnotations: 500,
|
||||
};
|
||||
|
||||
const response: GetResponse = await getAnnotations(indexAnnotationArgsMock);
|
||||
|
||||
const annotation: Annotation = response.annotations[jobIdMock][0];
|
||||
|
||||
const originalUsernameMock = 'usernameMock';
|
||||
expect(annotation.create_username).toBe(originalUsernameMock);
|
||||
expect(annotation.modified_username).toBe(originalUsernameMock);
|
||||
|
||||
const modifiedAnnotationText = 'Modified Annotation 1';
|
||||
annotation.annotation = modifiedAnnotationText;
|
||||
|
||||
const modifiedUsernameMock = 'modifiedUsernameMock';
|
||||
|
||||
await indexAnnotation(annotation, modifiedUsernameMock);
|
||||
|
||||
expect(callWithRequestSpy.mock.calls[1][0]).toBe('index');
|
||||
// test if the annotation has been correctly updated
|
||||
const indexParamsCheck = callWithRequestSpy.mock.calls[1][1];
|
||||
const modifiedAnnotation = indexParamsCheck.body;
|
||||
expect(modifiedAnnotation.annotation).toBe(modifiedAnnotationText);
|
||||
expect(modifiedAnnotation.create_username).toBe(originalUsernameMock);
|
||||
expect(modifiedAnnotation.modified_username).toBe(modifiedUsernameMock);
|
||||
expect(typeof modifiedAnnotation.create_time).toBe('number');
|
||||
expect(typeof modifiedAnnotation.modified_time).toBe('number');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -20,32 +20,34 @@ import {
|
|||
isAnnotations,
|
||||
} from '../../../common/types/annotations';
|
||||
|
||||
// TODO All of the following interface/type definitions should
|
||||
// eventually be replaced by the proper upstream definitions
|
||||
interface EsResult {
|
||||
_source: object;
|
||||
_id: string;
|
||||
}
|
||||
|
||||
interface IndexAnnotationArgs {
|
||||
export interface IndexAnnotationArgs {
|
||||
jobIds: string[];
|
||||
earliestMs: Date;
|
||||
latestMs: Date;
|
||||
earliestMs: number;
|
||||
latestMs: number;
|
||||
maxAnnotations: number;
|
||||
}
|
||||
|
||||
interface GetParams {
|
||||
export interface GetParams {
|
||||
index: string;
|
||||
size: number;
|
||||
body: object;
|
||||
}
|
||||
|
||||
interface GetResponse {
|
||||
export interface GetResponse {
|
||||
success: true;
|
||||
annotations: {
|
||||
[key: string]: Annotations;
|
||||
};
|
||||
}
|
||||
|
||||
interface IndexParams {
|
||||
export interface IndexParams {
|
||||
index: string;
|
||||
type: string;
|
||||
body: Annotation;
|
||||
|
@ -53,16 +55,21 @@ interface IndexParams {
|
|||
id?: string;
|
||||
}
|
||||
|
||||
interface DeleteParams {
|
||||
export interface DeleteParams {
|
||||
index: string;
|
||||
type: string;
|
||||
refresh?: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export function annotationProvider(
|
||||
callWithRequest: (action: string, params: IndexParams | DeleteParams | GetParams) => Promise<any>
|
||||
) {
|
||||
type annotationProviderParams = DeleteParams | GetParams | IndexParams;
|
||||
|
||||
export type callWithRequestType = (
|
||||
action: string,
|
||||
params: annotationProviderParams
|
||||
) => Promise<any>;
|
||||
|
||||
export function annotationProvider(callWithRequest: callWithRequestType) {
|
||||
async function indexAnnotation(annotation: Annotation, username: string) {
|
||||
if (isAnnotation(annotation) === false) {
|
||||
return Promise.reject(new Error('invalid annotation format'));
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { annotationProvider, callWithRequestType } from './annotation';
|
||||
|
||||
import { annotationProvider } from './annotation';
|
||||
|
||||
export function annotationServiceProvider(callWithRequest) {
|
||||
export function annotationServiceProvider(callWithRequest: callWithRequestType) {
|
||||
return {
|
||||
...annotationProvider(callWithRequest)
|
||||
...annotationProvider(callWithRequest),
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue