datasource.test.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. import angular from 'angular';
  2. import * as dateMath from 'app/core/utils/datemath';
  3. import _ from 'lodash';
  4. import moment from 'moment';
  5. import { ElasticDatasource } from '../datasource';
  6. describe('ElasticDatasource', function(this: any) {
  7. const backendSrv = {
  8. datasourceRequest: jest.fn(),
  9. };
  10. const $rootScope = {
  11. $on: jest.fn(),
  12. appEvent: jest.fn(),
  13. };
  14. const templateSrv = {
  15. replace: jest.fn(text => {
  16. if (text.startsWith('$')) {
  17. return `resolvedVariable`;
  18. } else {
  19. return text;
  20. }
  21. }),
  22. getAdhocFilters: jest.fn(() => []),
  23. };
  24. const timeSrv = {
  25. time: { from: 'now-1h', to: 'now' },
  26. timeRange: jest.fn(() => {
  27. return {
  28. from: dateMath.parse(this.time.from, false),
  29. to: dateMath.parse(this.time.to, true),
  30. };
  31. }),
  32. setTime: jest.fn(time => {
  33. this.time = time;
  34. }),
  35. };
  36. const ctx = {
  37. $rootScope,
  38. backendSrv,
  39. } as any;
  40. function createDatasource(instanceSettings) {
  41. instanceSettings.jsonData = instanceSettings.jsonData || {};
  42. ctx.ds = new ElasticDatasource(instanceSettings, {}, backendSrv, templateSrv, timeSrv);
  43. }
  44. describe('When testing datasource with index pattern', () => {
  45. beforeEach(() => {
  46. createDatasource({
  47. url: 'http://es.com',
  48. index: '[asd-]YYYY.MM.DD',
  49. jsonData: { interval: 'Daily', esVersion: '2' },
  50. });
  51. });
  52. it('should translate index pattern to current day', () => {
  53. let requestOptions;
  54. ctx.backendSrv.datasourceRequest = jest.fn(options => {
  55. requestOptions = options;
  56. return Promise.resolve({ data: {} });
  57. });
  58. ctx.ds.testDatasource();
  59. const today = moment.utc().format('YYYY.MM.DD');
  60. expect(requestOptions.url).toBe('http://es.com/asd-' + today + '/_mapping');
  61. });
  62. });
  63. describe('When issuing metric query with interval pattern', () => {
  64. let requestOptions, parts, header, query, result;
  65. beforeEach(async () => {
  66. createDatasource({
  67. url: 'http://es.com',
  68. index: '[asd-]YYYY.MM.DD',
  69. jsonData: { interval: 'Daily', esVersion: '2' },
  70. });
  71. ctx.backendSrv.datasourceRequest = jest.fn(options => {
  72. requestOptions = options;
  73. return Promise.resolve({
  74. data: {
  75. responses: [
  76. {
  77. aggregations: {
  78. '1': {
  79. buckets: [
  80. {
  81. doc_count: 10,
  82. key: 1000,
  83. },
  84. ],
  85. },
  86. },
  87. },
  88. ],
  89. },
  90. });
  91. });
  92. query = {
  93. range: {
  94. from: moment.utc([2015, 4, 30, 10]),
  95. to: moment.utc([2015, 5, 1, 10]),
  96. },
  97. targets: [
  98. {
  99. alias: '$varAlias',
  100. bucketAggs: [{ type: 'date_histogram', field: '@timestamp', id: '1' }],
  101. metrics: [{ type: 'count', id: '1' }],
  102. query: 'escape\\:test',
  103. },
  104. ],
  105. };
  106. result = await ctx.ds.query(query);
  107. parts = requestOptions.data.split('\n');
  108. header = angular.fromJson(parts[0]);
  109. });
  110. it('should translate index pattern to current day', () => {
  111. expect(header.index).toEqual(['asd-2015.05.30', 'asd-2015.05.31', 'asd-2015.06.01']);
  112. });
  113. it('should not resolve the variable in the original alias field in the query', () => {
  114. expect(query.targets[0].alias).toEqual('$varAlias');
  115. });
  116. it('should resolve the alias variable for the alias/target in the result', () => {
  117. expect(result.data[0].target).toEqual('resolvedVariable');
  118. });
  119. it('should json escape lucene query', () => {
  120. const body = angular.fromJson(parts[1]);
  121. expect(body.query.bool.filter[1].query_string.query).toBe('escape\\:test');
  122. });
  123. });
  124. describe('When issuing document query', () => {
  125. let requestOptions, parts, header;
  126. beforeEach(() => {
  127. createDatasource({
  128. url: 'http://es.com',
  129. index: 'test',
  130. jsonData: { esVersion: '2' },
  131. });
  132. ctx.backendSrv.datasourceRequest = jest.fn(options => {
  133. requestOptions = options;
  134. return Promise.resolve({ data: { responses: [] } });
  135. });
  136. ctx.ds.query({
  137. range: {
  138. from: moment([2015, 4, 30, 10]),
  139. to: moment([2015, 5, 1, 10]),
  140. },
  141. targets: [
  142. {
  143. bucketAggs: [],
  144. metrics: [{ type: 'raw_document' }],
  145. query: 'test',
  146. },
  147. ],
  148. });
  149. parts = requestOptions.data.split('\n');
  150. header = angular.fromJson(parts[0]);
  151. });
  152. it('should set search type to query_then_fetch', () => {
  153. expect(header.search_type).toEqual('query_then_fetch');
  154. });
  155. it('should set size', () => {
  156. const body = angular.fromJson(parts[1]);
  157. expect(body.size).toBe(500);
  158. });
  159. });
  160. describe('When getting fields', () => {
  161. beforeEach(() => {
  162. createDatasource({ url: 'http://es.com', index: 'metricbeat' });
  163. ctx.backendSrv.datasourceRequest = jest.fn(options => {
  164. return Promise.resolve({
  165. data: {
  166. metricbeat: {
  167. mappings: {
  168. metricsets: {
  169. _all: {},
  170. properties: {
  171. '@timestamp': { type: 'date' },
  172. beat: {
  173. properties: {
  174. name: {
  175. fields: { raw: { type: 'keyword' } },
  176. type: 'string',
  177. },
  178. hostname: { type: 'string' },
  179. },
  180. },
  181. system: {
  182. properties: {
  183. cpu: {
  184. properties: {
  185. system: { type: 'float' },
  186. user: { type: 'float' },
  187. },
  188. },
  189. process: {
  190. properties: {
  191. cpu: {
  192. properties: {
  193. total: { type: 'float' },
  194. },
  195. },
  196. name: { type: 'string' },
  197. },
  198. },
  199. },
  200. },
  201. },
  202. },
  203. },
  204. },
  205. },
  206. });
  207. });
  208. });
  209. it('should return nested fields', () => {
  210. ctx.ds
  211. .getFields({
  212. find: 'fields',
  213. query: '*',
  214. })
  215. .then(fieldObjects => {
  216. const fields = _.map(fieldObjects, 'text');
  217. expect(fields).toEqual([
  218. '@timestamp',
  219. 'beat.name.raw',
  220. 'beat.name',
  221. 'beat.hostname',
  222. 'system.cpu.system',
  223. 'system.cpu.user',
  224. 'system.process.cpu.total',
  225. 'system.process.name',
  226. ]);
  227. });
  228. });
  229. it('should return fields related to query type', () => {
  230. ctx.ds
  231. .getFields({
  232. find: 'fields',
  233. query: '*',
  234. type: 'number',
  235. })
  236. .then(fieldObjects => {
  237. const fields = _.map(fieldObjects, 'text');
  238. expect(fields).toEqual(['system.cpu.system', 'system.cpu.user', 'system.process.cpu.total']);
  239. });
  240. ctx.ds
  241. .getFields({
  242. find: 'fields',
  243. query: '*',
  244. type: 'date',
  245. })
  246. .then(fieldObjects => {
  247. const fields = _.map(fieldObjects, 'text');
  248. expect(fields).toEqual(['@timestamp']);
  249. });
  250. });
  251. });
  252. describe('When issuing aggregation query on es5.x', () => {
  253. let requestOptions, parts, header;
  254. beforeEach(() => {
  255. createDatasource({
  256. url: 'http://es.com',
  257. index: 'test',
  258. jsonData: { esVersion: '5' },
  259. });
  260. ctx.backendSrv.datasourceRequest = jest.fn(options => {
  261. requestOptions = options;
  262. return Promise.resolve({ data: { responses: [] } });
  263. });
  264. ctx.ds.query({
  265. range: {
  266. from: moment([2015, 4, 30, 10]),
  267. to: moment([2015, 5, 1, 10]),
  268. },
  269. targets: [
  270. {
  271. bucketAggs: [{ type: 'date_histogram', field: '@timestamp', id: '2' }],
  272. metrics: [{ type: 'count' }],
  273. query: 'test',
  274. },
  275. ],
  276. });
  277. parts = requestOptions.data.split('\n');
  278. header = angular.fromJson(parts[0]);
  279. });
  280. it('should not set search type to count', () => {
  281. expect(header.search_type).not.toEqual('count');
  282. });
  283. it('should set size to 0', () => {
  284. const body = angular.fromJson(parts[1]);
  285. expect(body.size).toBe(0);
  286. });
  287. });
  288. describe('When issuing metricFind query on es5.x', () => {
  289. let requestOptions, parts, header, body, results;
  290. beforeEach(() => {
  291. createDatasource({
  292. url: 'http://es.com',
  293. index: 'test',
  294. jsonData: { esVersion: '5' },
  295. });
  296. ctx.backendSrv.datasourceRequest = jest.fn(options => {
  297. requestOptions = options;
  298. return Promise.resolve({
  299. data: {
  300. responses: [
  301. {
  302. aggregations: {
  303. '1': {
  304. buckets: [
  305. { doc_count: 1, key: 'test' },
  306. {
  307. doc_count: 2,
  308. key: 'test2',
  309. key_as_string: 'test2_as_string',
  310. },
  311. ],
  312. },
  313. },
  314. },
  315. ],
  316. },
  317. });
  318. });
  319. ctx.ds.metricFindQuery('{"find": "terms", "field": "test"}').then(res => {
  320. results = res;
  321. });
  322. parts = requestOptions.data.split('\n');
  323. header = angular.fromJson(parts[0]);
  324. body = angular.fromJson(parts[1]);
  325. });
  326. it('should get results', () => {
  327. expect(results.length).toEqual(2);
  328. });
  329. it('should use key or key_as_string', () => {
  330. expect(results[0].text).toEqual('test');
  331. expect(results[1].text).toEqual('test2_as_string');
  332. });
  333. it('should not set search type to count', () => {
  334. expect(header.search_type).not.toEqual('count');
  335. });
  336. it('should set size to 0', () => {
  337. expect(body.size).toBe(0);
  338. });
  339. it('should not set terms aggregation size to 0', () => {
  340. expect(body['aggs']['1']['terms'].size).not.toBe(0);
  341. });
  342. });
  343. });