metric_find_query.test.ts 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. import 'whatwg-fetch'; // fetch polyfill needed backendSrv
  2. import { of } from 'rxjs';
  3. import { DataSourceInstanceSettings, toUtc } from '@grafana/data';
  4. import { FetchResponse } from '@grafana/runtime';
  5. import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
  6. import { PrometheusDatasource } from './datasource';
  7. import PrometheusMetricFindQuery from './metric_find_query';
  8. import { PromOptions } from './types';
  9. jest.mock('@grafana/runtime', () => ({
  10. ...(jest.requireActual('@grafana/runtime') as unknown as object),
  11. getBackendSrv: () => backendSrv,
  12. }));
  13. const fetchMock = jest.spyOn(backendSrv, 'fetch');
  14. const instanceSettings = {
  15. url: 'proxied',
  16. id: 1,
  17. directUrl: 'direct',
  18. user: 'test',
  19. password: 'mupp',
  20. jsonData: { httpMethod: 'GET' },
  21. } as unknown as DataSourceInstanceSettings<PromOptions>;
  22. const raw = {
  23. from: toUtc('2018-04-25 10:00'),
  24. to: toUtc('2018-04-25 11:00'),
  25. };
  26. jest.mock('app/features/dashboard/services/TimeSrv', () => ({
  27. __esModule: true,
  28. getTimeSrv: jest.fn().mockReturnValue({
  29. timeRange(): any {
  30. return {
  31. from: raw.from,
  32. to: raw.to,
  33. raw: raw,
  34. };
  35. },
  36. }),
  37. }));
  38. const templateSrvStub = {
  39. getAdhocFilters: jest.fn(() => [] as any[]),
  40. replace: jest.fn((a: string) => a),
  41. } as any;
  42. beforeEach(() => {
  43. jest.clearAllMocks();
  44. });
  45. describe('PrometheusMetricFindQuery', () => {
  46. let ds: PrometheusDatasource;
  47. beforeEach(() => {
  48. ds = new PrometheusDatasource(instanceSettings, templateSrvStub);
  49. });
  50. const setupMetricFindQuery = (data: any) => {
  51. fetchMock.mockImplementation(() => of({ status: 'success', data: data.response } as unknown as FetchResponse));
  52. return new PrometheusMetricFindQuery(ds, data.query);
  53. };
  54. describe('When performing metricFindQuery', () => {
  55. it('label_names() should generate label name search query', async () => {
  56. const query = setupMetricFindQuery({
  57. query: 'label_names()',
  58. response: {
  59. data: ['name1', 'name2', 'name3'],
  60. },
  61. });
  62. const results = await query.process();
  63. expect(results).toHaveLength(3);
  64. expect(fetchMock).toHaveBeenCalledTimes(1);
  65. expect(fetchMock).toHaveBeenCalledWith({
  66. method: 'GET',
  67. url: `/api/datasources/1/resources/api/v1/labels?start=${raw.from.unix()}&end=${raw.to.unix()}`,
  68. hideFromInspector: true,
  69. showErrorAlert: false,
  70. headers: {},
  71. });
  72. });
  73. it('label_values(resource) should generate label search query', async () => {
  74. const query = setupMetricFindQuery({
  75. query: 'label_values(resource)',
  76. response: {
  77. data: ['value1', 'value2', 'value3'],
  78. },
  79. });
  80. const results = await query.process();
  81. expect(results).toHaveLength(3);
  82. expect(fetchMock).toHaveBeenCalledTimes(1);
  83. expect(fetchMock).toHaveBeenCalledWith({
  84. method: 'GET',
  85. url: `/api/datasources/1/resources/api/v1/label/resource/values?start=${raw.from.unix()}&end=${raw.to.unix()}`,
  86. hideFromInspector: true,
  87. headers: {},
  88. });
  89. });
  90. it('label_values(metric, resource) should generate series query with correct time', async () => {
  91. const query = setupMetricFindQuery({
  92. query: 'label_values(metric, resource)',
  93. response: {
  94. data: [
  95. { __name__: 'metric', resource: 'value1' },
  96. { __name__: 'metric', resource: 'value2' },
  97. { __name__: 'metric', resource: 'value3' },
  98. ],
  99. },
  100. });
  101. const results = await query.process();
  102. expect(results).toHaveLength(3);
  103. expect(fetchMock).toHaveBeenCalledTimes(1);
  104. expect(fetchMock).toHaveBeenCalledWith({
  105. method: 'GET',
  106. url: `/api/datasources/1/resources/api/v1/series?match${encodeURIComponent(
  107. '[]'
  108. )}=metric&start=${raw.from.unix()}&end=${raw.to.unix()}`,
  109. hideFromInspector: true,
  110. showErrorAlert: false,
  111. headers: {},
  112. });
  113. });
  114. it('label_values(metric{label1="foo", label2="bar", label3="baz"}, resource) should generate series query with correct time', async () => {
  115. const query = setupMetricFindQuery({
  116. query: 'label_values(metric{label1="foo", label2="bar", label3="baz"}, resource)',
  117. response: {
  118. data: [
  119. { __name__: 'metric', resource: 'value1' },
  120. { __name__: 'metric', resource: 'value2' },
  121. { __name__: 'metric', resource: 'value3' },
  122. ],
  123. },
  124. });
  125. const results = await query.process();
  126. expect(results).toHaveLength(3);
  127. expect(fetchMock).toHaveBeenCalledTimes(1);
  128. expect(fetchMock).toHaveBeenCalledWith({
  129. method: 'GET',
  130. url: '/api/datasources/1/resources/api/v1/series?match%5B%5D=metric%7Blabel1%3D%22foo%22%2C%20label2%3D%22bar%22%2C%20label3%3D%22baz%22%7D&start=1524650400&end=1524654000',
  131. hideFromInspector: true,
  132. showErrorAlert: false,
  133. headers: {},
  134. });
  135. });
  136. it('label_values(metric, resource) result should not contain empty string', async () => {
  137. const query = setupMetricFindQuery({
  138. query: 'label_values(metric, resource)',
  139. response: {
  140. data: [
  141. { __name__: 'metric', resource: 'value1' },
  142. { __name__: 'metric', resource: 'value2' },
  143. { __name__: 'metric', resource: '' },
  144. ],
  145. },
  146. });
  147. const results: any = await query.process();
  148. expect(results).toHaveLength(2);
  149. expect(results[0].text).toBe('value1');
  150. expect(results[1].text).toBe('value2');
  151. expect(fetchMock).toHaveBeenCalledTimes(1);
  152. expect(fetchMock).toHaveBeenCalledWith({
  153. method: 'GET',
  154. url: `/api/datasources/1/resources/api/v1/series?match${encodeURIComponent(
  155. '[]'
  156. )}=metric&start=${raw.from.unix()}&end=${raw.to.unix()}`,
  157. hideFromInspector: true,
  158. showErrorAlert: false,
  159. headers: {},
  160. });
  161. });
  162. it('metrics(metric.*) should generate metric name query', async () => {
  163. const query = setupMetricFindQuery({
  164. query: 'metrics(metric.*)',
  165. response: {
  166. data: ['metric1', 'metric2', 'metric3', 'nomatch'],
  167. },
  168. });
  169. const results = await query.process();
  170. expect(results).toHaveLength(3);
  171. expect(fetchMock).toHaveBeenCalledTimes(1);
  172. expect(fetchMock).toHaveBeenCalledWith({
  173. method: 'GET',
  174. url: `/api/datasources/1/resources/api/v1/label/__name__/values?start=${raw.from.unix()}&end=${raw.to.unix()}`,
  175. hideFromInspector: true,
  176. headers: {},
  177. });
  178. });
  179. it('query_result(metric) should generate metric name query', async () => {
  180. const query = setupMetricFindQuery({
  181. query: 'query_result(metric)',
  182. response: {
  183. data: {
  184. resultType: 'vector',
  185. result: [
  186. {
  187. metric: { __name__: 'metric', job: 'testjob' },
  188. value: [1443454528.0, '3846'],
  189. },
  190. ],
  191. },
  192. },
  193. });
  194. const results: any = await query.process();
  195. expect(results).toHaveLength(1);
  196. expect(results[0].text).toBe('metric{job="testjob"} 3846 1443454528000');
  197. expect(fetchMock).toHaveBeenCalledTimes(1);
  198. expect(fetchMock).toHaveBeenCalledWith({
  199. method: 'GET',
  200. url: `proxied/api/v1/query?query=metric&time=${raw.to.unix()}`,
  201. requestId: undefined,
  202. headers: {},
  203. });
  204. });
  205. it('up{job="job1"} should fallback using generate series query', async () => {
  206. const query = setupMetricFindQuery({
  207. query: 'up{job="job1"}',
  208. response: {
  209. data: [
  210. { __name__: 'up', instance: '127.0.0.1:1234', job: 'job1' },
  211. { __name__: 'up', instance: '127.0.0.1:5678', job: 'job1' },
  212. { __name__: 'up', instance: '127.0.0.1:9102', job: 'job1' },
  213. ],
  214. },
  215. });
  216. const results: any = await query.process();
  217. expect(results).toHaveLength(3);
  218. expect(results[0].text).toBe('up{instance="127.0.0.1:1234",job="job1"}');
  219. expect(results[1].text).toBe('up{instance="127.0.0.1:5678",job="job1"}');
  220. expect(results[2].text).toBe('up{instance="127.0.0.1:9102",job="job1"}');
  221. expect(fetchMock).toHaveBeenCalledTimes(1);
  222. expect(fetchMock).toHaveBeenCalledWith({
  223. method: 'GET',
  224. url: `/api/datasources/1/resources/api/v1/series?match${encodeURIComponent('[]')}=${encodeURIComponent(
  225. 'up{job="job1"}'
  226. )}&start=${raw.from.unix()}&end=${raw.to.unix()}`,
  227. hideFromInspector: true,
  228. showErrorAlert: false,
  229. headers: {},
  230. });
  231. });
  232. });
  233. });