datasource.test.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import { of, throwError } from 'rxjs';
  2. import { createFetchResponse } from 'test/helpers/createFetchResponse';
  3. import { DataSourceInstanceSettings, toUtc } from '@grafana/data';
  4. import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
  5. import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
  6. import { TemplateSrv } from 'app/features/templating/template_srv';
  7. import { initialCustomVariableModelState } from '../../../../features/variables/custom/reducer';
  8. import { CustomVariableModel } from '../../../../features/variables/types';
  9. import CloudMonitoringDataSource from '../datasource';
  10. import { CloudMonitoringOptions } from '../types';
  11. jest.mock('@grafana/runtime', () => ({
  12. ...(jest.requireActual('@grafana/runtime') as unknown as object),
  13. getBackendSrv: () => backendSrv,
  14. }));
  15. type Args = { response?: any; throws?: boolean; templateSrv?: TemplateSrv };
  16. const fetchMock = jest.spyOn(backendSrv, 'fetch');
  17. function getTestcontext({ response = {}, throws = false, templateSrv = new TemplateSrv() }: Args = {}) {
  18. jest.clearAllMocks();
  19. const instanceSettings = {
  20. jsonData: {
  21. defaultProject: 'testproject',
  22. },
  23. } as unknown as DataSourceInstanceSettings<CloudMonitoringOptions>;
  24. const timeSrv = {
  25. timeRange: () => ({
  26. from: toUtc('2017-08-22T20:00:00Z'),
  27. to: toUtc('2017-08-22T23:59:00Z'),
  28. }),
  29. } as TimeSrv;
  30. throws
  31. ? fetchMock.mockImplementation(() => throwError(response))
  32. : fetchMock.mockImplementation(() => of(createFetchResponse(response)));
  33. const ds = new CloudMonitoringDataSource(instanceSettings, templateSrv, timeSrv);
  34. return { ds };
  35. }
  36. describe('CloudMonitoringDataSource', () => {
  37. describe('When performing query', () => {
  38. describe('and no time series data is returned', () => {
  39. it('should return a list of datapoints', async () => {
  40. const options = {
  41. range: {
  42. from: toUtc('2017-08-22T20:00:00Z'),
  43. to: toUtc('2017-08-22T23:59:00Z'),
  44. },
  45. rangeRaw: {
  46. from: 'now-4h',
  47. to: 'now',
  48. },
  49. targets: [
  50. {
  51. refId: 'A',
  52. },
  53. ],
  54. };
  55. const response: any = {
  56. results: {
  57. A: {
  58. refId: 'A',
  59. meta: {
  60. rawQuery: 'arawquerystring',
  61. },
  62. series: null,
  63. tables: null,
  64. },
  65. },
  66. };
  67. const { ds } = getTestcontext({ response });
  68. await expect(ds.query(options as any)).toEmitValuesWith((received) => {
  69. const results = received[0];
  70. expect(results.data.length).toBe(0);
  71. });
  72. });
  73. });
  74. });
  75. describe('When loading labels', () => {
  76. describe('and no aggregation was specified', () => {
  77. it('should use default values', async () => {
  78. const { ds } = getTestcontext();
  79. await ds.getLabels('cpu', 'a', 'default-proj');
  80. await expect(fetchMock.mock.calls[0][0].data.queries[0].metricQuery).toMatchObject({
  81. crossSeriesReducer: 'REDUCE_NONE',
  82. groupBys: [],
  83. metricType: 'cpu',
  84. projectName: 'default-proj',
  85. view: 'HEADERS',
  86. });
  87. });
  88. });
  89. describe('and an aggregation was specified', () => {
  90. it('should use the provided aggregation', async () => {
  91. const { ds } = getTestcontext();
  92. await ds.getLabels('sql', 'b', 'default-proj', {
  93. crossSeriesReducer: 'REDUCE_MEAN',
  94. groupBys: ['metadata.system_label.name'],
  95. });
  96. await expect(fetchMock.mock.calls[0][0].data.queries[0].metricQuery).toMatchObject({
  97. crossSeriesReducer: 'REDUCE_MEAN',
  98. groupBys: ['metadata.system_label.name'],
  99. metricType: 'sql',
  100. projectName: 'default-proj',
  101. view: 'HEADERS',
  102. });
  103. });
  104. });
  105. });
  106. describe('when interpolating a template variable for the filter', () => {
  107. describe('and is single value variable', () => {
  108. it('should replace the variable with the value', () => {
  109. const templateSrv = initTemplateSrv('filtervalue1');
  110. const { ds } = getTestcontext({ templateSrv });
  111. const interpolated = ds.interpolateFilters(['resource.label.zone', '=~', '${test}'], {});
  112. expect(interpolated.length).toBe(3);
  113. expect(interpolated[2]).toBe('filtervalue1');
  114. });
  115. });
  116. describe('and is single value variable for the label part', () => {
  117. it('should replace the variable with the value and not with regex formatting', () => {
  118. const templateSrv = initTemplateSrv('resource.label.zone');
  119. const { ds } = getTestcontext({ templateSrv });
  120. const interpolated = ds.interpolateFilters(['${test}', '=~', 'europe-north-1a'], {});
  121. expect(interpolated.length).toBe(3);
  122. expect(interpolated[0]).toBe('resource.label.zone');
  123. });
  124. });
  125. describe('and is multi value variable', () => {
  126. it('should replace the variable with a regex expression', () => {
  127. const templateSrv = initTemplateSrv(['filtervalue1', 'filtervalue2'], true);
  128. const { ds } = getTestcontext({ templateSrv });
  129. const interpolated = ds.interpolateFilters(['resource.label.zone', '=~', '[[test]]'], {});
  130. expect(interpolated[2]).toBe('(filtervalue1|filtervalue2)');
  131. });
  132. it('should not escape a regex', () => {
  133. const templateSrv = initTemplateSrv('/[a-Z]*.html', true);
  134. const { ds } = getTestcontext({ templateSrv });
  135. const interpolated = ds.interpolateFilters(['resource.label.zone', '=~', '[[test]]'], {});
  136. expect(interpolated[2]).toBe('/[a-Z]*.html');
  137. });
  138. it('should not escape an array of regexes but join them as a regex', () => {
  139. const templateSrv = initTemplateSrv(['/[a-Z]*.html', '/foo.html'], true);
  140. const { ds } = getTestcontext({ templateSrv });
  141. const interpolated = ds.interpolateFilters(['resource.label.zone', '=~', '[[test]]'], {});
  142. expect(interpolated[2]).toBe('(/[a-Z]*.html|/foo.html)');
  143. });
  144. });
  145. });
  146. describe('when interpolating a template variable for group bys', () => {
  147. describe('and is single value variable', () => {
  148. it('should replace the variable with the value', () => {
  149. const templateSrv = initTemplateSrv('groupby1');
  150. const { ds } = getTestcontext({ templateSrv });
  151. const interpolated = ds.interpolateGroupBys(['[[test]]'], {});
  152. expect(interpolated.length).toBe(1);
  153. expect(interpolated[0]).toBe('groupby1');
  154. });
  155. });
  156. describe('and is multi value variable', () => {
  157. it('should replace the variable with an array of group bys', () => {
  158. const templateSrv = initTemplateSrv(['groupby1', 'groupby2'], true);
  159. const { ds } = getTestcontext({ templateSrv });
  160. const interpolated = ds.interpolateGroupBys(['[[test]]'], {});
  161. expect(interpolated.length).toBe(2);
  162. expect(interpolated[0]).toBe('groupby1');
  163. expect(interpolated[1]).toBe('groupby2');
  164. });
  165. });
  166. });
  167. });
  168. function initTemplateSrv(values: any, multi = false) {
  169. const templateSrv = new TemplateSrv();
  170. const test: CustomVariableModel = {
  171. ...initialCustomVariableModelState,
  172. id: 'test',
  173. name: 'test',
  174. current: { value: values, text: Array.isArray(values) ? values.toString() : values, selected: true },
  175. options: [{ value: values, text: Array.isArray(values) ? values.toString() : values, selected: false }],
  176. multi,
  177. };
  178. templateSrv.init([test]);
  179. return templateSrv;
  180. }