datasource.test.ts 9.6 KB

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