datasource.jest.ts 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import _ from 'lodash';
  2. import moment from 'moment';
  3. import q from 'q';
  4. import { alignRange, PrometheusDatasource, prometheusSpecialRegexEscape, prometheusRegularEscape } from '../datasource';
  5. describe('PrometheusDatasource', () => {
  6. let ctx: any = {};
  7. let instanceSettings = {
  8. url: 'proxied',
  9. directUrl: 'direct',
  10. user: 'test',
  11. password: 'mupp',
  12. jsonData: {},
  13. };
  14. ctx.backendSrvMock = {};
  15. ctx.templateSrvMock = {
  16. replace: a => a,
  17. };
  18. ctx.timeSrvMock = {};
  19. beforeEach(() => {
  20. ctx.ds = new PrometheusDatasource(instanceSettings, q, ctx.backendSrvMock, ctx.templateSrvMock, ctx.timeSrvMock);
  21. });
  22. describe('Datasource metadata requests', () => {
  23. it('should perform a GET request with the default config', () => {
  24. ctx.backendSrvMock.datasourceRequest = jest.fn();
  25. ctx.ds.metadataRequest('/foo');
  26. expect(ctx.backendSrvMock.datasourceRequest.mock.calls.length).toBe(1);
  27. expect(ctx.backendSrvMock.datasourceRequest.mock.calls[0][0].method).toBe('GET');
  28. });
  29. it('should still perform a GET request with the DS HTTP method set to POST', () => {
  30. ctx.backendSrvMock.datasourceRequest = jest.fn();
  31. const postSettings = _.cloneDeep(instanceSettings);
  32. postSettings.jsonData.httpMethod = 'POST';
  33. const ds = new PrometheusDatasource(postSettings, q, ctx.backendSrvMock, ctx.templateSrvMock, ctx.timeSrvMock);
  34. ds.metadataRequest('/foo');
  35. expect(ctx.backendSrvMock.datasourceRequest.mock.calls.length).toBe(1);
  36. expect(ctx.backendSrvMock.datasourceRequest.mock.calls[0][0].method).toBe('GET');
  37. });
  38. });
  39. describe('When performing performSuggestQuery', () => {
  40. it('should cache response', async () => {
  41. ctx.backendSrvMock.datasourceRequest.mockReturnValue(
  42. Promise.resolve({
  43. status: 'success',
  44. data: { data: ['value1', 'value2', 'value3'] },
  45. })
  46. );
  47. let results = await ctx.ds.performSuggestQuery('value', true);
  48. expect(results).toHaveLength(3);
  49. ctx.backendSrvMock.datasourceRequest.mockReset();
  50. results = await ctx.ds.performSuggestQuery('value', true);
  51. expect(results).toHaveLength(3);
  52. });
  53. });
  54. describe('When converting prometheus histogram to heatmap format', () => {
  55. beforeEach(() => {
  56. ctx.query = {
  57. range: { from: moment(1443454528000), to: moment(1443454528000) },
  58. targets: [{ expr: 'test{job="testjob"}', format: 'heatmap', legendFormat: '{{le}}' }],
  59. interval: '1s',
  60. };
  61. });
  62. it('should convert cumullative histogram to ordinary', () => {
  63. const resultMock = [
  64. {
  65. metric: { __name__: 'metric', job: 'testjob', le: '10' },
  66. values: [[1443454528.0, '10'], [1443454528.0, '10']],
  67. },
  68. {
  69. metric: { __name__: 'metric', job: 'testjob', le: '20' },
  70. values: [[1443454528.0, '20'], [1443454528.0, '10']],
  71. },
  72. {
  73. metric: { __name__: 'metric', job: 'testjob', le: '30' },
  74. values: [[1443454528.0, '25'], [1443454528.0, '10']],
  75. },
  76. ];
  77. const responseMock = { data: { data: { result: resultMock } } };
  78. const expected = [
  79. {
  80. target: '10',
  81. datapoints: [[10, 1443454528000], [10, 1443454528000]],
  82. },
  83. {
  84. target: '20',
  85. datapoints: [[10, 1443454528000], [0, 1443454528000]],
  86. },
  87. {
  88. target: '30',
  89. datapoints: [[5, 1443454528000], [0, 1443454528000]],
  90. },
  91. ];
  92. ctx.ds.performTimeSeriesQuery = jest.fn().mockReturnValue(responseMock);
  93. return ctx.ds.query(ctx.query).then(result => {
  94. let results = result.data;
  95. return expect(results).toEqual(expected);
  96. });
  97. });
  98. it('should sort series by label value', () => {
  99. const resultMock = [
  100. {
  101. metric: { __name__: 'metric', job: 'testjob', le: '2' },
  102. values: [[1443454528.0, '10'], [1443454528.0, '10']],
  103. },
  104. {
  105. metric: { __name__: 'metric', job: 'testjob', le: '4' },
  106. values: [[1443454528.0, '20'], [1443454528.0, '10']],
  107. },
  108. {
  109. metric: { __name__: 'metric', job: 'testjob', le: '+Inf' },
  110. values: [[1443454528.0, '25'], [1443454528.0, '10']],
  111. },
  112. {
  113. metric: { __name__: 'metric', job: 'testjob', le: '1' },
  114. values: [[1443454528.0, '25'], [1443454528.0, '10']],
  115. },
  116. ];
  117. const responseMock = { data: { data: { result: resultMock } } };
  118. const expected = ['1', '2', '4', '+Inf'];
  119. ctx.ds.performTimeSeriesQuery = jest.fn().mockReturnValue(responseMock);
  120. return ctx.ds.query(ctx.query).then(result => {
  121. let seriesLabels = _.map(result.data, 'target');
  122. return expect(seriesLabels).toEqual(expected);
  123. });
  124. });
  125. });
  126. describe('alignRange', function() {
  127. it('does not modify already aligned intervals with perfect step', function() {
  128. const range = alignRange(0, 3, 3);
  129. expect(range.start).toEqual(0);
  130. expect(range.end).toEqual(3);
  131. });
  132. it('does modify end-aligned intervals to reflect number of steps possible', function() {
  133. const range = alignRange(1, 6, 3);
  134. expect(range.start).toEqual(0);
  135. expect(range.end).toEqual(6);
  136. });
  137. it('does align intervals that are a multiple of steps', function() {
  138. const range = alignRange(1, 4, 3);
  139. expect(range.start).toEqual(0);
  140. expect(range.end).toEqual(6);
  141. });
  142. it('does align intervals that are not a multiple of steps', function() {
  143. const range = alignRange(1, 5, 3);
  144. expect(range.start).toEqual(0);
  145. expect(range.end).toEqual(6);
  146. });
  147. });
  148. describe('Prometheus regular escaping', function() {
  149. it('should not escape non-string', function() {
  150. expect(prometheusRegularEscape(12)).toEqual(12);
  151. });
  152. it('should not escape simple string', function() {
  153. expect(prometheusRegularEscape('cryptodepression')).toEqual('cryptodepression');
  154. });
  155. it("should escape '", function() {
  156. expect(prometheusRegularEscape("looking'glass")).toEqual("looking\\\\'glass");
  157. });
  158. it('should escape multiple characters', function() {
  159. expect(prometheusRegularEscape("'looking'glass'")).toEqual("\\\\'looking\\\\'glass\\\\'");
  160. });
  161. });
  162. describe('Prometheus regexes escaping', function() {
  163. it('should not escape simple string', function() {
  164. expect(prometheusSpecialRegexEscape('cryptodepression')).toEqual('cryptodepression');
  165. });
  166. it('should escape $^*+?.()\\', function() {
  167. expect(prometheusSpecialRegexEscape("looking'glass")).toEqual("looking\\\\'glass");
  168. expect(prometheusSpecialRegexEscape('looking{glass')).toEqual('looking\\\\{glass');
  169. expect(prometheusSpecialRegexEscape('looking}glass')).toEqual('looking\\\\}glass');
  170. expect(prometheusSpecialRegexEscape('looking[glass')).toEqual('looking\\\\[glass');
  171. expect(prometheusSpecialRegexEscape('looking]glass')).toEqual('looking\\\\]glass');
  172. expect(prometheusSpecialRegexEscape('looking$glass')).toEqual('looking\\\\$glass');
  173. expect(prometheusSpecialRegexEscape('looking^glass')).toEqual('looking\\\\^glass');
  174. expect(prometheusSpecialRegexEscape('looking*glass')).toEqual('looking\\\\*glass');
  175. expect(prometheusSpecialRegexEscape('looking+glass')).toEqual('looking\\\\+glass');
  176. expect(prometheusSpecialRegexEscape('looking?glass')).toEqual('looking\\\\?glass');
  177. expect(prometheusSpecialRegexEscape('looking.glass')).toEqual('looking\\\\.glass');
  178. expect(prometheusSpecialRegexEscape('looking(glass')).toEqual('looking\\\\(glass');
  179. expect(prometheusSpecialRegexEscape('looking)glass')).toEqual('looking\\\\)glass');
  180. expect(prometheusSpecialRegexEscape('looking\\glass')).toEqual('looking\\\\\\\\glass');
  181. });
  182. it('should escape multiple special characters', function() {
  183. expect(prometheusSpecialRegexEscape('+looking$glass?')).toEqual('\\\\+looking\\\\$glass\\\\?');
  184. });
  185. });
  186. });