| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672 |
- import angular, { IQService } from 'angular';
- import { dateMath } from '@grafana/data';
- import _ from 'lodash';
- import { ElasticDatasource, getMaxConcurrenShardRequestOrDefault } from '../datasource';
- import { toUtc, dateTime } from '@grafana/data';
- import { BackendSrv } from 'app/core/services/backend_srv';
- import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
- import { TemplateSrv } from 'app/features/templating/template_srv';
- import { DataSourceInstanceSettings } from '@grafana/ui';
- import { ElasticsearchOptions } from '../types';
- describe('ElasticDatasource', function(this: any) {
- const backendSrv: any = {
- datasourceRequest: jest.fn(),
- };
- const $rootScope: any = {
- $on: jest.fn(),
- appEvent: jest.fn(),
- };
- const templateSrv: any = {
- replace: jest.fn(text => {
- if (text.startsWith('$')) {
- return `resolvedVariable`;
- } else {
- return text;
- }
- }),
- getAdhocFilters: jest.fn(() => []),
- };
- const timeSrv: any = {
- time: { from: 'now-1h', to: 'now' },
- timeRange: jest.fn(() => {
- return {
- from: dateMath.parse(timeSrv.time.from, false),
- to: dateMath.parse(timeSrv.time.to, true),
- };
- }),
- setTime: jest.fn(time => {
- this.time = time;
- }),
- };
- const ctx = {
- $rootScope,
- backendSrv,
- } as any;
- function createDatasource(instanceSettings: DataSourceInstanceSettings<ElasticsearchOptions>) {
- instanceSettings.jsonData = instanceSettings.jsonData || ({} as ElasticsearchOptions);
- ctx.ds = new ElasticDatasource(
- instanceSettings,
- {} as IQService,
- backendSrv as BackendSrv,
- templateSrv as TemplateSrv,
- timeSrv as TimeSrv
- );
- }
- describe('When testing datasource with index pattern', () => {
- beforeEach(() => {
- createDatasource({
- url: 'http://es.com',
- database: '[asd-]YYYY.MM.DD',
- jsonData: { interval: 'Daily', esVersion: 2 } as ElasticsearchOptions,
- } as DataSourceInstanceSettings<ElasticsearchOptions>);
- });
- it('should translate index pattern to current day', () => {
- let requestOptions;
- ctx.backendSrv.datasourceRequest = jest.fn(options => {
- requestOptions = options;
- return Promise.resolve({ data: {} });
- });
- ctx.ds.testDatasource();
- const today = toUtc().format('YYYY.MM.DD');
- expect(requestOptions.url).toBe('http://es.com/asd-' + today + '/_mapping');
- });
- });
- describe('When issuing metric query with interval pattern', () => {
- let requestOptions, parts, header, query, result;
- beforeEach(async () => {
- createDatasource({
- url: 'http://es.com',
- database: '[asd-]YYYY.MM.DD',
- jsonData: { interval: 'Daily', esVersion: 2 } as ElasticsearchOptions,
- } as DataSourceInstanceSettings<ElasticsearchOptions>);
- ctx.backendSrv.datasourceRequest = jest.fn(options => {
- requestOptions = options;
- return Promise.resolve({
- data: {
- responses: [
- {
- aggregations: {
- '1': {
- buckets: [
- {
- doc_count: 10,
- key: 1000,
- },
- ],
- },
- },
- },
- ],
- },
- });
- });
- query = {
- range: {
- from: toUtc([2015, 4, 30, 10]),
- to: toUtc([2015, 5, 1, 10]),
- },
- targets: [
- {
- alias: '$varAlias',
- bucketAggs: [{ type: 'date_histogram', field: '@timestamp', id: '1' }],
- metrics: [{ type: 'count', id: '1' }],
- query: 'escape\\:test',
- },
- ],
- };
- result = await ctx.ds.query(query);
- parts = requestOptions.data.split('\n');
- header = angular.fromJson(parts[0]);
- });
- it('should translate index pattern to current day', () => {
- expect(header.index).toEqual(['asd-2015.05.30', 'asd-2015.05.31', 'asd-2015.06.01']);
- });
- it('should not resolve the variable in the original alias field in the query', () => {
- expect(query.targets[0].alias).toEqual('$varAlias');
- });
- it('should resolve the alias variable for the alias/target in the result', () => {
- expect(result.data[0].target).toEqual('resolvedVariable');
- });
- it('should json escape lucene query', () => {
- const body = angular.fromJson(parts[1]);
- expect(body.query.bool.filter[1].query_string.query).toBe('escape\\:test');
- });
- });
- describe('When issuing logs query with interval pattern', () => {
- let query, queryBuilderSpy;
- beforeEach(async () => {
- createDatasource({
- url: 'http://es.com',
- database: 'mock-index',
- jsonData: { interval: 'Daily', esVersion: 2, timeField: '@timestamp' } as ElasticsearchOptions,
- } as DataSourceInstanceSettings<ElasticsearchOptions>);
- ctx.backendSrv.datasourceRequest = jest.fn(options => {
- return Promise.resolve({
- data: {
- responses: [
- {
- aggregations: {
- '2': {
- buckets: [
- {
- doc_count: 10,
- key: 1000,
- },
- {
- doc_count: 15,
- key: 2000,
- },
- ],
- },
- },
- hits: {
- hits: [
- {
- '@timestamp': ['2019-06-24T09:51:19.765Z'],
- _id: 'fdsfs',
- _type: '_doc',
- _index: 'mock-index',
- _source: {
- '@timestamp': '2019-06-24T09:51:19.765Z',
- host: 'djisaodjsoad',
- message: 'hello, i am a message',
- },
- fields: {
- '@timestamp': ['2019-06-24T09:51:19.765Z'],
- },
- },
- {
- '@timestamp': ['2019-06-24T09:52:19.765Z'],
- _id: 'kdospaidopa',
- _type: '_doc',
- _index: 'mock-index',
- _source: {
- '@timestamp': '2019-06-24T09:52:19.765Z',
- host: 'dsalkdakdop',
- message: 'hello, i am also message',
- },
- fields: {
- '@timestamp': ['2019-06-24T09:52:19.765Z'],
- },
- },
- ],
- },
- },
- ],
- },
- });
- });
- query = {
- range: {
- from: toUtc([2015, 4, 30, 10]),
- to: toUtc([2019, 7, 1, 10]),
- },
- targets: [
- {
- alias: '$varAlias',
- refId: 'A',
- bucketAggs: [{ type: 'date_histogram', settings: { interval: 'auto' }, id: '2' }],
- metrics: [{ type: 'count', id: '1' }],
- query: 'escape\\:test',
- interval: '10s',
- isLogsQuery: true,
- timeField: '@timestamp',
- },
- ],
- };
- queryBuilderSpy = jest.spyOn(ctx.ds.queryBuilder, 'getLogsQuery');
- await ctx.ds.query(query);
- });
- it('should call getLogsQuery()', () => {
- expect(queryBuilderSpy).toHaveBeenCalled();
- });
- });
- describe('When issuing document query', () => {
- let requestOptions, parts, header;
- beforeEach(() => {
- createDatasource({
- url: 'http://es.com',
- database: 'test',
- jsonData: { esVersion: 2 } as ElasticsearchOptions,
- } as DataSourceInstanceSettings<ElasticsearchOptions>);
- ctx.backendSrv.datasourceRequest = jest.fn(options => {
- requestOptions = options;
- return Promise.resolve({ data: { responses: [] } });
- });
- ctx.ds.query({
- range: {
- from: dateTime([2015, 4, 30, 10]),
- to: dateTime([2015, 5, 1, 10]),
- },
- targets: [
- {
- bucketAggs: [],
- metrics: [{ type: 'raw_document' }],
- query: 'test',
- },
- ],
- });
- parts = requestOptions.data.split('\n');
- header = angular.fromJson(parts[0]);
- });
- it('should set search type to query_then_fetch', () => {
- expect(header.search_type).toEqual('query_then_fetch');
- });
- it('should set size', () => {
- const body = angular.fromJson(parts[1]);
- expect(body.size).toBe(500);
- });
- });
- describe('When getting fields', () => {
- beforeEach(() => {
- createDatasource({
- url: 'http://es.com',
- database: 'metricbeat',
- jsonData: { esVersion: 50 } as ElasticsearchOptions,
- } as DataSourceInstanceSettings<ElasticsearchOptions>);
- ctx.backendSrv.datasourceRequest = jest.fn(options => {
- return Promise.resolve({
- data: {
- metricbeat: {
- mappings: {
- metricsets: {
- _all: {},
- properties: {
- '@timestamp': { type: 'date' },
- beat: {
- properties: {
- name: {
- fields: { raw: { type: 'keyword' } },
- type: 'string',
- },
- hostname: { type: 'string' },
- },
- },
- system: {
- properties: {
- cpu: {
- properties: {
- system: { type: 'float' },
- user: { type: 'float' },
- },
- },
- process: {
- properties: {
- cpu: {
- properties: {
- total: { type: 'float' },
- },
- },
- name: { type: 'string' },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- });
- });
- });
- it('should return nested fields', async () => {
- const fieldObjects = await ctx.ds.getFields({
- find: 'fields',
- query: '*',
- });
- const fields = _.map(fieldObjects, 'text');
- expect(fields).toEqual([
- '@timestamp',
- 'beat.name.raw',
- 'beat.name',
- 'beat.hostname',
- 'system.cpu.system',
- 'system.cpu.user',
- 'system.process.cpu.total',
- 'system.process.name',
- ]);
- });
- it('should return number fields', async () => {
- const fieldObjects = await ctx.ds.getFields({
- find: 'fields',
- query: '*',
- type: 'number',
- });
- const fields = _.map(fieldObjects, 'text');
- expect(fields).toEqual(['system.cpu.system', 'system.cpu.user', 'system.process.cpu.total']);
- });
- it('should return date fields', async () => {
- const fieldObjects = await ctx.ds.getFields({
- find: 'fields',
- query: '*',
- type: 'date',
- });
- const fields = _.map(fieldObjects, 'text');
- expect(fields).toEqual(['@timestamp']);
- });
- });
- describe('When getting fields from ES 7.0', () => {
- beforeEach(() => {
- createDatasource({
- url: 'http://es.com',
- database: 'genuine.es7._mapping.response',
- jsonData: { esVersion: 70 } as ElasticsearchOptions,
- } as DataSourceInstanceSettings<ElasticsearchOptions>);
- ctx.backendSrv.datasourceRequest = jest.fn(options => {
- return Promise.resolve({
- data: {
- 'genuine.es7._mapping.response': {
- mappings: {
- properties: {
- '@timestamp_millis': {
- type: 'date',
- format: 'epoch_millis',
- },
- classification_terms: {
- type: 'keyword',
- },
- domains: {
- type: 'keyword',
- },
- ip_address: {
- type: 'ip',
- },
- justification_blob: {
- properties: {
- criterion: {
- type: 'text',
- fields: {
- keyword: {
- type: 'keyword',
- ignore_above: 256,
- },
- },
- },
- overall_vote_score: {
- type: 'float',
- },
- shallow: {
- properties: {
- jsi: {
- properties: {
- sdb: {
- properties: {
- dsel2: {
- properties: {
- 'bootlegged-gille': {
- properties: {
- botness: {
- type: 'float',
- },
- general_algorithm_score: {
- type: 'float',
- },
- },
- },
- 'uncombed-boris': {
- properties: {
- botness: {
- type: 'float',
- },
- general_algorithm_score: {
- type: 'float',
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- overall_vote_score: {
- type: 'float',
- },
- ua_terms_long: {
- type: 'keyword',
- },
- ua_terms_short: {
- type: 'keyword',
- },
- },
- },
- },
- },
- });
- });
- });
- it('should return nested fields', async () => {
- const fieldObjects = await ctx.ds.getFields({
- find: 'fields',
- query: '*',
- });
- const fields = _.map(fieldObjects, 'text');
- expect(fields).toEqual([
- '@timestamp_millis',
- 'classification_terms',
- 'domains',
- 'ip_address',
- 'justification_blob.criterion.keyword',
- 'justification_blob.criterion',
- 'justification_blob.overall_vote_score',
- 'justification_blob.shallow.jsi.sdb.dsel2.bootlegged-gille.botness',
- 'justification_blob.shallow.jsi.sdb.dsel2.bootlegged-gille.general_algorithm_score',
- 'justification_blob.shallow.jsi.sdb.dsel2.uncombed-boris.botness',
- 'justification_blob.shallow.jsi.sdb.dsel2.uncombed-boris.general_algorithm_score',
- 'overall_vote_score',
- 'ua_terms_long',
- 'ua_terms_short',
- ]);
- });
- it('should return number fields', async () => {
- const fieldObjects = await ctx.ds.getFields({
- find: 'fields',
- query: '*',
- type: 'number',
- });
- const fields = _.map(fieldObjects, 'text');
- expect(fields).toEqual([
- 'justification_blob.overall_vote_score',
- 'justification_blob.shallow.jsi.sdb.dsel2.bootlegged-gille.botness',
- 'justification_blob.shallow.jsi.sdb.dsel2.bootlegged-gille.general_algorithm_score',
- 'justification_blob.shallow.jsi.sdb.dsel2.uncombed-boris.botness',
- 'justification_blob.shallow.jsi.sdb.dsel2.uncombed-boris.general_algorithm_score',
- 'overall_vote_score',
- ]);
- });
- it('should return date fields', async () => {
- const fieldObjects = await ctx.ds.getFields({
- find: 'fields',
- query: '*',
- type: 'date',
- });
- const fields = _.map(fieldObjects, 'text');
- expect(fields).toEqual(['@timestamp_millis']);
- });
- });
- describe('When issuing aggregation query on es5.x', () => {
- let requestOptions, parts, header;
- beforeEach(() => {
- createDatasource({
- url: 'http://es.com',
- database: 'test',
- jsonData: { esVersion: 5 } as ElasticsearchOptions,
- } as DataSourceInstanceSettings<ElasticsearchOptions>);
- ctx.backendSrv.datasourceRequest = jest.fn(options => {
- requestOptions = options;
- return Promise.resolve({ data: { responses: [] } });
- });
- ctx.ds.query({
- range: {
- from: dateTime([2015, 4, 30, 10]),
- to: dateTime([2015, 5, 1, 10]),
- },
- targets: [
- {
- bucketAggs: [{ type: 'date_histogram', field: '@timestamp', id: '2' }],
- metrics: [{ type: 'count' }],
- query: 'test',
- },
- ],
- });
- parts = requestOptions.data.split('\n');
- header = angular.fromJson(parts[0]);
- });
- it('should not set search type to count', () => {
- expect(header.search_type).not.toEqual('count');
- });
- it('should set size to 0', () => {
- const body = angular.fromJson(parts[1]);
- expect(body.size).toBe(0);
- });
- });
- describe('When issuing metricFind query on es5.x', () => {
- let requestOptions, parts, header, body, results;
- beforeEach(() => {
- createDatasource({
- url: 'http://es.com',
- database: 'test',
- jsonData: { esVersion: 5 } as ElasticsearchOptions,
- } as DataSourceInstanceSettings<ElasticsearchOptions>);
- ctx.backendSrv.datasourceRequest = jest.fn(options => {
- requestOptions = options;
- return Promise.resolve({
- data: {
- responses: [
- {
- aggregations: {
- '1': {
- buckets: [
- { doc_count: 1, key: 'test' },
- {
- doc_count: 2,
- key: 'test2',
- key_as_string: 'test2_as_string',
- },
- ],
- },
- },
- },
- ],
- },
- });
- });
- ctx.ds.metricFindQuery('{"find": "terms", "field": "test"}').then(res => {
- results = res;
- });
- parts = requestOptions.data.split('\n');
- header = angular.fromJson(parts[0]);
- body = angular.fromJson(parts[1]);
- });
- it('should get results', () => {
- expect(results.length).toEqual(2);
- });
- it('should use key or key_as_string', () => {
- expect(results[0].text).toEqual('test');
- expect(results[1].text).toEqual('test2_as_string');
- });
- it('should not set search type to count', () => {
- expect(header.search_type).not.toEqual('count');
- });
- it('should set size to 0', () => {
- expect(body.size).toBe(0);
- });
- it('should not set terms aggregation size to 0', () => {
- expect(body['aggs']['1']['terms'].size).not.toBe(0);
- });
- });
- });
- describe('getMaxConcurrenShardRequestOrDefault', () => {
- const testCases = [
- { version: 50, expectedMaxConcurrentShardRequests: 256 },
- { version: 50, maxConcurrentShardRequests: 50, expectedMaxConcurrentShardRequests: 50 },
- { version: 56, expectedMaxConcurrentShardRequests: 256 },
- { version: 56, maxConcurrentShardRequests: 256, expectedMaxConcurrentShardRequests: 256 },
- { version: 56, maxConcurrentShardRequests: 5, expectedMaxConcurrentShardRequests: 256 },
- { version: 56, maxConcurrentShardRequests: 200, expectedMaxConcurrentShardRequests: 200 },
- { version: 70, expectedMaxConcurrentShardRequests: 5 },
- { version: 70, maxConcurrentShardRequests: 256, expectedMaxConcurrentShardRequests: 5 },
- { version: 70, maxConcurrentShardRequests: 5, expectedMaxConcurrentShardRequests: 5 },
- { version: 70, maxConcurrentShardRequests: 6, expectedMaxConcurrentShardRequests: 6 },
- ];
- testCases.forEach(tc => {
- it(`version = ${tc.version}, maxConcurrentShardRequests = ${tc.maxConcurrentShardRequests}`, () => {
- const options = { esVersion: tc.version, maxConcurrentShardRequests: tc.maxConcurrentShardRequests };
- expect(getMaxConcurrenShardRequestOrDefault(options as ElasticsearchOptions)).toBe(
- tc.expectedMaxConcurrentShardRequests
- );
- });
- });
- });
|