datasource.test.ts 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. import _ from 'lodash';
  2. import moment from 'moment';
  3. import angular from 'angular';
  4. import { ElasticDatasource } from '../datasource';
  5. import * as dateMath from 'app/core/utils/datemath';
  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;
  65. beforeEach(() => {
  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({ data: { responses: [] } });
  74. });
  75. query = {
  76. range: {
  77. from: moment.utc([2015, 4, 30, 10]),
  78. to: moment.utc([2015, 5, 1, 10]),
  79. },
  80. targets: [
  81. {
  82. alias: '$varAlias',
  83. bucketAggs: [],
  84. metrics: [{ type: 'raw_document' }],
  85. query: 'escape\\:test',
  86. },
  87. ],
  88. };
  89. ctx.ds.query(query);
  90. parts = requestOptions.data.split('\n');
  91. header = angular.fromJson(parts[0]);
  92. });
  93. it('should translate index pattern to current day', () => {
  94. expect(header.index).toEqual(['asd-2015.05.30', 'asd-2015.05.31', 'asd-2015.06.01']);
  95. });
  96. it('should resolve the alias variable', () => {
  97. expect(query.targets[0].alias).toEqual('resolvedVariable');
  98. });
  99. it('should json escape lucene query', () => {
  100. const body = angular.fromJson(parts[1]);
  101. expect(body.query.bool.filter[1].query_string.query).toBe('escape\\:test');
  102. });
  103. });
  104. describe('When issuing document query', () => {
  105. let requestOptions, parts, header;
  106. beforeEach(() => {
  107. createDatasource({
  108. url: 'http://es.com',
  109. index: 'test',
  110. jsonData: { esVersion: '2' },
  111. });
  112. ctx.backendSrv.datasourceRequest = jest.fn(options => {
  113. requestOptions = options;
  114. return Promise.resolve({ data: { responses: [] } });
  115. });
  116. ctx.ds.query({
  117. range: {
  118. from: moment([2015, 4, 30, 10]),
  119. to: moment([2015, 5, 1, 10]),
  120. },
  121. targets: [
  122. {
  123. bucketAggs: [],
  124. metrics: [{ type: 'raw_document' }],
  125. query: 'test',
  126. },
  127. ],
  128. });
  129. parts = requestOptions.data.split('\n');
  130. header = angular.fromJson(parts[0]);
  131. });
  132. it('should set search type to query_then_fetch', () => {
  133. expect(header.search_type).toEqual('query_then_fetch');
  134. });
  135. it('should set size', () => {
  136. const body = angular.fromJson(parts[1]);
  137. expect(body.size).toBe(500);
  138. });
  139. });
  140. describe('When getting fields', () => {
  141. beforeEach(() => {
  142. createDatasource({ url: 'http://es.com', index: 'metricbeat' });
  143. ctx.backendSrv.datasourceRequest = jest.fn(options => {
  144. return Promise.resolve({
  145. data: {
  146. metricbeat: {
  147. mappings: {
  148. metricsets: {
  149. _all: {},
  150. properties: {
  151. '@timestamp': { type: 'date' },
  152. beat: {
  153. properties: {
  154. name: {
  155. fields: { raw: { type: 'keyword' } },
  156. type: 'string',
  157. },
  158. hostname: { type: 'string' },
  159. },
  160. },
  161. system: {
  162. properties: {
  163. cpu: {
  164. properties: {
  165. system: { type: 'float' },
  166. user: { type: 'float' },
  167. },
  168. },
  169. process: {
  170. properties: {
  171. cpu: {
  172. properties: {
  173. total: { type: 'float' },
  174. },
  175. },
  176. name: { type: 'string' },
  177. },
  178. },
  179. },
  180. },
  181. },
  182. },
  183. },
  184. },
  185. },
  186. });
  187. });
  188. });
  189. it('should return nested fields', () => {
  190. ctx.ds
  191. .getFields({
  192. find: 'fields',
  193. query: '*',
  194. })
  195. .then(fieldObjects => {
  196. const fields = _.map(fieldObjects, 'text');
  197. expect(fields).toEqual([
  198. '@timestamp',
  199. 'beat.name.raw',
  200. 'beat.name',
  201. 'beat.hostname',
  202. 'system.cpu.system',
  203. 'system.cpu.user',
  204. 'system.process.cpu.total',
  205. 'system.process.name',
  206. ]);
  207. });
  208. });
  209. it('should return fields related to query type', () => {
  210. ctx.ds
  211. .getFields({
  212. find: 'fields',
  213. query: '*',
  214. type: 'number',
  215. })
  216. .then(fieldObjects => {
  217. const fields = _.map(fieldObjects, 'text');
  218. expect(fields).toEqual(['system.cpu.system', 'system.cpu.user', 'system.process.cpu.total']);
  219. });
  220. ctx.ds
  221. .getFields({
  222. find: 'fields',
  223. query: '*',
  224. type: 'date',
  225. })
  226. .then(fieldObjects => {
  227. const fields = _.map(fieldObjects, 'text');
  228. expect(fields).toEqual(['@timestamp']);
  229. });
  230. });
  231. });
  232. describe('When issuing aggregation query on es5.x', () => {
  233. let requestOptions, parts, header;
  234. beforeEach(() => {
  235. createDatasource({
  236. url: 'http://es.com',
  237. index: 'test',
  238. jsonData: { esVersion: '5' },
  239. });
  240. ctx.backendSrv.datasourceRequest = jest.fn(options => {
  241. requestOptions = options;
  242. return Promise.resolve({ data: { responses: [] } });
  243. });
  244. ctx.ds.query({
  245. range: {
  246. from: moment([2015, 4, 30, 10]),
  247. to: moment([2015, 5, 1, 10]),
  248. },
  249. targets: [
  250. {
  251. bucketAggs: [{ type: 'date_histogram', field: '@timestamp', id: '2' }],
  252. metrics: [{ type: 'count' }],
  253. query: 'test',
  254. },
  255. ],
  256. });
  257. parts = requestOptions.data.split('\n');
  258. header = angular.fromJson(parts[0]);
  259. });
  260. it('should not set search type to count', () => {
  261. expect(header.search_type).not.toEqual('count');
  262. });
  263. it('should set size to 0', () => {
  264. const body = angular.fromJson(parts[1]);
  265. expect(body.size).toBe(0);
  266. });
  267. });
  268. describe('When issuing metricFind query on es5.x', () => {
  269. let requestOptions, parts, header, body, results;
  270. beforeEach(() => {
  271. createDatasource({
  272. url: 'http://es.com',
  273. index: 'test',
  274. jsonData: { esVersion: '5' },
  275. });
  276. ctx.backendSrv.datasourceRequest = jest.fn(options => {
  277. requestOptions = options;
  278. return Promise.resolve({
  279. data: {
  280. responses: [
  281. {
  282. aggregations: {
  283. '1': {
  284. buckets: [
  285. { doc_count: 1, key: 'test' },
  286. {
  287. doc_count: 2,
  288. key: 'test2',
  289. key_as_string: 'test2_as_string',
  290. },
  291. ],
  292. },
  293. },
  294. },
  295. ],
  296. },
  297. });
  298. });
  299. ctx.ds.metricFindQuery('{"find": "terms", "field": "test"}').then(res => {
  300. results = res;
  301. });
  302. parts = requestOptions.data.split('\n');
  303. header = angular.fromJson(parts[0]);
  304. body = angular.fromJson(parts[1]);
  305. });
  306. it('should get results', () => {
  307. expect(results.length).toEqual(2);
  308. });
  309. it('should use key or key_as_string', () => {
  310. expect(results[0].text).toEqual('test');
  311. expect(results[1].text).toEqual('test2_as_string');
  312. });
  313. it('should not set search type to count', () => {
  314. expect(header.search_type).not.toEqual('count');
  315. });
  316. it('should set size to 0', () => {
  317. expect(body.size).toBe(0);
  318. });
  319. it('should not set terms aggregation size to 0', () => {
  320. expect(body['aggs']['1']['terms'].size).not.toBe(0);
  321. });
  322. });
  323. });