result_transformer.test.ts 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. import { ResultTransformer } from '../result_transformer';
  2. import { DataQueryResponseData } from '@grafana/ui';
  3. describe('Prometheus Result Transformer', () => {
  4. const ctx: any = {};
  5. beforeEach(() => {
  6. ctx.templateSrv = {
  7. replace: (str: string) => str,
  8. };
  9. ctx.resultTransformer = new ResultTransformer(ctx.templateSrv);
  10. });
  11. describe('When nothing is returned', () => {
  12. test('should return empty series', () => {
  13. const response = {
  14. status: 'success',
  15. data: {
  16. resultType: '',
  17. result: null as DataQueryResponseData[],
  18. },
  19. };
  20. const series = ctx.resultTransformer.transform({ data: response }, {});
  21. expect(series).toEqual([]);
  22. });
  23. test('should return empty table', () => {
  24. const response = {
  25. status: 'success',
  26. data: {
  27. resultType: '',
  28. result: null as DataQueryResponseData[],
  29. },
  30. };
  31. const table = ctx.resultTransformer.transform({ data: response }, { format: 'table' });
  32. expect(table).toMatchObject([{ type: 'table', rows: [] }]);
  33. });
  34. });
  35. describe('When resultFormat is table', () => {
  36. const response = {
  37. status: 'success',
  38. data: {
  39. resultType: 'matrix',
  40. result: [
  41. {
  42. metric: { __name__: 'test', job: 'testjob' },
  43. values: [[1443454528, '3846']],
  44. },
  45. {
  46. metric: {
  47. __name__: 'test',
  48. instance: 'localhost:8080',
  49. job: 'otherjob',
  50. },
  51. values: [[1443454529, '3847']],
  52. },
  53. ],
  54. },
  55. };
  56. it('should return table model', () => {
  57. const table = ctx.resultTransformer.transformMetricDataToTable(response.data.result);
  58. expect(table.type).toBe('table');
  59. expect(table.rows).toEqual([
  60. [1443454528000, 'test', '', 'testjob', 3846],
  61. [1443454529000, 'test', 'localhost:8080', 'otherjob', 3847],
  62. ]);
  63. expect(table.columns).toMatchObject([
  64. { text: 'Time', type: 'time' },
  65. { text: '__name__', filterable: true },
  66. { text: 'instance', filterable: true },
  67. { text: 'job' },
  68. { text: 'Value' },
  69. ]);
  70. expect(table.columns[4].filterable).toBeUndefined();
  71. });
  72. it('should column title include refId if response count is more than 2', () => {
  73. const table = ctx.resultTransformer.transformMetricDataToTable(response.data.result, 2, 'B');
  74. expect(table.type).toBe('table');
  75. expect(table.columns).toMatchObject([
  76. { text: 'Time', type: 'time' },
  77. { text: '__name__' },
  78. { text: 'instance' },
  79. { text: 'job' },
  80. { text: 'Value #B' },
  81. ]);
  82. });
  83. });
  84. describe('When resultFormat is table and instant = true', () => {
  85. const response = {
  86. status: 'success',
  87. data: {
  88. resultType: 'vector',
  89. result: [
  90. {
  91. metric: { __name__: 'test', job: 'testjob' },
  92. value: [1443454528, '3846'],
  93. },
  94. ],
  95. },
  96. };
  97. it('should return table model', () => {
  98. const table = ctx.resultTransformer.transformMetricDataToTable(response.data.result);
  99. expect(table.type).toBe('table');
  100. expect(table.rows).toEqual([[1443454528000, 'test', 'testjob', 3846]]);
  101. expect(table.columns).toMatchObject([
  102. { text: 'Time', type: 'time' },
  103. { text: '__name__' },
  104. { text: 'job' },
  105. { text: 'Value' },
  106. ]);
  107. });
  108. });
  109. describe('When resultFormat is heatmap', () => {
  110. const response = {
  111. status: 'success',
  112. data: {
  113. resultType: 'matrix',
  114. result: [
  115. {
  116. metric: { __name__: 'test', job: 'testjob', le: '1' },
  117. values: [[1445000010, '10'], [1445000020, '10'], [1445000030, '0']],
  118. },
  119. {
  120. metric: { __name__: 'test', job: 'testjob', le: '2' },
  121. values: [[1445000010, '20'], [1445000020, '10'], [1445000030, '30']],
  122. },
  123. {
  124. metric: { __name__: 'test', job: 'testjob', le: '3' },
  125. values: [[1445000010, '30'], [1445000020, '10'], [1445000030, '40']],
  126. },
  127. ],
  128. },
  129. };
  130. it('should convert cumulative histogram to regular', () => {
  131. const options = {
  132. format: 'heatmap',
  133. start: 1445000010,
  134. end: 1445000030,
  135. legendFormat: '{{le}}',
  136. };
  137. const result = ctx.resultTransformer.transform({ data: response }, options);
  138. expect(result).toEqual([
  139. {
  140. target: '1',
  141. query: undefined,
  142. datapoints: [[10, 1445000010000], [10, 1445000020000], [0, 1445000030000]],
  143. tags: { __name__: 'test', job: 'testjob', le: '1' },
  144. },
  145. {
  146. target: '2',
  147. query: undefined,
  148. datapoints: [[10, 1445000010000], [0, 1445000020000], [30, 1445000030000]],
  149. tags: { __name__: 'test', job: 'testjob', le: '2' },
  150. },
  151. {
  152. target: '3',
  153. query: undefined,
  154. datapoints: [[10, 1445000010000], [0, 1445000020000], [10, 1445000030000]],
  155. tags: { __name__: 'test', job: 'testjob', le: '3' },
  156. },
  157. ]);
  158. });
  159. it('should handle missing datapoints', () => {
  160. const seriesList = [
  161. { datapoints: [[1, 1000], [2, 2000]] },
  162. { datapoints: [[2, 1000], [5, 2000], [1, 3000]] },
  163. { datapoints: [[3, 1000], [7, 2000]] },
  164. ];
  165. const expected = [
  166. { datapoints: [[1, 1000], [2, 2000]] },
  167. { datapoints: [[1, 1000], [3, 2000], [1, 3000]] },
  168. { datapoints: [[1, 1000], [2, 2000]] },
  169. ];
  170. const result = ctx.resultTransformer.transformToHistogramOverTime(seriesList);
  171. expect(result).toEqual(expected);
  172. });
  173. it('should throw error when data in wrong format', () => {
  174. const seriesList = [{ rows: [] as any[] }, { datapoints: [] as any[] }];
  175. expect(() => {
  176. ctx.resultTransformer.transformToHistogramOverTime(seriesList);
  177. }).toThrow();
  178. });
  179. it('should throw error when prometheus returned non-timeseries', () => {
  180. // should be { metric: {}, values: [] } for timeseries
  181. const metricData = { metric: {}, value: [] as any[] };
  182. expect(() => {
  183. ctx.resultTransformer.transformMetricData(metricData, { step: 1 }, 1000, 2000);
  184. }).toThrow();
  185. });
  186. });
  187. describe('When resultFormat is time series', () => {
  188. it('should transform matrix into timeseries', () => {
  189. const response = {
  190. status: 'success',
  191. data: {
  192. resultType: 'matrix',
  193. result: [
  194. {
  195. metric: { __name__: 'test', job: 'testjob' },
  196. values: [[0, '10'], [1, '10'], [2, '0']],
  197. },
  198. ],
  199. },
  200. };
  201. const options = {
  202. format: 'timeseries',
  203. start: 0,
  204. end: 2,
  205. };
  206. const result = ctx.resultTransformer.transform({ data: response }, options);
  207. expect(result).toEqual([
  208. {
  209. target: 'test{job="testjob"}',
  210. query: undefined,
  211. datapoints: [[10, 0], [10, 1000], [0, 2000]],
  212. tags: { job: 'testjob' },
  213. },
  214. ]);
  215. });
  216. it('should fill timeseries with null values', () => {
  217. const response = {
  218. status: 'success',
  219. data: {
  220. resultType: 'matrix',
  221. result: [
  222. {
  223. metric: { __name__: 'test', job: 'testjob' },
  224. values: [[1, '10'], [2, '0']],
  225. },
  226. ],
  227. },
  228. };
  229. const options = {
  230. format: 'timeseries',
  231. step: 1,
  232. start: 0,
  233. end: 2,
  234. };
  235. const result = ctx.resultTransformer.transform({ data: response }, options);
  236. expect(result).toEqual([
  237. {
  238. target: 'test{job="testjob"}',
  239. query: undefined,
  240. datapoints: [[null, 0], [10, 1000], [0, 2000]],
  241. tags: { job: 'testjob' },
  242. },
  243. ]);
  244. });
  245. it('should align null values with step', () => {
  246. const response = {
  247. status: 'success',
  248. data: {
  249. resultType: 'matrix',
  250. result: [
  251. {
  252. metric: { __name__: 'test', job: 'testjob' },
  253. values: [[4, '10'], [8, '10']],
  254. },
  255. ],
  256. },
  257. };
  258. const options = {
  259. format: 'timeseries',
  260. step: 2,
  261. start: 0,
  262. end: 8,
  263. };
  264. const result = ctx.resultTransformer.transform({ data: response }, options);
  265. expect(result).toEqual([
  266. {
  267. target: 'test{job="testjob"}',
  268. query: undefined,
  269. datapoints: [[null, 0], [null, 2000], [10, 4000], [null, 6000], [10, 8000]],
  270. tags: { job: 'testjob' },
  271. },
  272. ]);
  273. });
  274. });
  275. });