datasource.test.ts 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. import StackdriverDataSource from '../datasource';
  2. import { metricDescriptors } from './testData';
  3. import { TemplateSrv } from 'app/features/templating/template_srv';
  4. import { CustomVariable } from 'app/features/templating/all';
  5. import { toUtc } from '@grafana/ui/src/utils/moment_wrapper';
  6. describe('StackdriverDataSource', () => {
  7. const instanceSettings = {
  8. jsonData: {
  9. defaultProject: 'testproject',
  10. },
  11. };
  12. const templateSrv = new TemplateSrv();
  13. const timeSrv = {};
  14. describe('when performing testDataSource', () => {
  15. describe('and call to stackdriver api succeeds', () => {
  16. let ds;
  17. let result;
  18. beforeEach(async () => {
  19. const backendSrv = {
  20. async datasourceRequest() {
  21. return Promise.resolve({ status: 200 });
  22. },
  23. };
  24. ds = new StackdriverDataSource(instanceSettings, backendSrv, templateSrv, timeSrv);
  25. result = await ds.testDatasource();
  26. });
  27. it('should return successfully', () => {
  28. expect(result.status).toBe('success');
  29. });
  30. });
  31. describe('and a list of metricDescriptors are returned', () => {
  32. let ds;
  33. let result;
  34. beforeEach(async () => {
  35. const backendSrv = {
  36. datasourceRequest: async () => Promise.resolve({ status: 200, data: metricDescriptors }),
  37. };
  38. ds = new StackdriverDataSource(instanceSettings, backendSrv, templateSrv, timeSrv);
  39. result = await ds.testDatasource();
  40. });
  41. it('should return status success', () => {
  42. expect(result.status).toBe('success');
  43. });
  44. });
  45. describe('and call to stackdriver api fails with 400 error', () => {
  46. let ds;
  47. let result;
  48. beforeEach(async () => {
  49. const backendSrv = {
  50. datasourceRequest: async () =>
  51. Promise.reject({
  52. statusText: 'Bad Request',
  53. data: {
  54. error: { code: 400, message: 'Field interval.endTime had an invalid value' },
  55. },
  56. }),
  57. };
  58. ds = new StackdriverDataSource(instanceSettings, backendSrv, templateSrv, timeSrv);
  59. result = await ds.testDatasource();
  60. });
  61. it('should return error status and a detailed error message', () => {
  62. expect(result.status).toEqual('error');
  63. expect(result.message).toBe('Stackdriver: Bad Request: 400. Field interval.endTime had an invalid value');
  64. });
  65. });
  66. });
  67. describe('When performing query', () => {
  68. const options = {
  69. range: {
  70. from: toUtc('2017-08-22T20:00:00Z'),
  71. to: toUtc('2017-08-22T23:59:00Z'),
  72. },
  73. rangeRaw: {
  74. from: 'now-4h',
  75. to: 'now',
  76. },
  77. targets: [
  78. {
  79. refId: 'A',
  80. },
  81. ],
  82. };
  83. describe('and no time series data is returned', () => {
  84. let ds;
  85. const response = {
  86. results: {
  87. A: {
  88. refId: 'A',
  89. meta: {
  90. rawQuery: 'arawquerystring',
  91. },
  92. series: null,
  93. tables: null,
  94. },
  95. },
  96. };
  97. beforeEach(() => {
  98. const backendSrv = {
  99. datasourceRequest: async () => Promise.resolve({ status: 200, data: response }),
  100. };
  101. ds = new StackdriverDataSource(instanceSettings, backendSrv, templateSrv, timeSrv);
  102. });
  103. it('should return a list of datapoints', () => {
  104. return ds.query(options).then(results => {
  105. expect(results.data.length).toBe(0);
  106. });
  107. });
  108. });
  109. });
  110. describe('when performing getMetricTypes', () => {
  111. describe('and call to stackdriver api succeeds', () => {});
  112. let ds;
  113. let result;
  114. beforeEach(async () => {
  115. const backendSrv = {
  116. async datasourceRequest() {
  117. return Promise.resolve({
  118. data: {
  119. metricDescriptors: [
  120. {
  121. displayName: 'test metric name 1',
  122. type: 'compute.googleapis.com/instance/cpu/test-metric-type-1',
  123. description: 'A description',
  124. },
  125. {
  126. type: 'logging.googleapis.com/user/logbased-metric-with-no-display-name',
  127. },
  128. ],
  129. },
  130. });
  131. },
  132. };
  133. ds = new StackdriverDataSource(instanceSettings, backendSrv, templateSrv, timeSrv);
  134. result = await ds.getMetricTypes();
  135. });
  136. it('should return successfully', () => {
  137. expect(result.length).toBe(2);
  138. expect(result[0].service).toBe('compute.googleapis.com');
  139. expect(result[0].serviceShortName).toBe('compute');
  140. expect(result[0].type).toBe('compute.googleapis.com/instance/cpu/test-metric-type-1');
  141. expect(result[0].displayName).toBe('test metric name 1');
  142. expect(result[0].description).toBe('A description');
  143. expect(result[1].type).toBe('logging.googleapis.com/user/logbased-metric-with-no-display-name');
  144. expect(result[1].displayName).toBe('logging.googleapis.com/user/logbased-metric-with-no-display-name');
  145. });
  146. });
  147. describe('when interpolating a template variable for the filter', () => {
  148. let interpolated;
  149. describe('and is single value variable', () => {
  150. beforeEach(() => {
  151. const filterTemplateSrv = initTemplateSrv('filtervalue1');
  152. const ds = new StackdriverDataSource(instanceSettings, {}, filterTemplateSrv, timeSrv);
  153. interpolated = ds.interpolateFilters(['resource.label.zone', '=~', '${test}'], {});
  154. });
  155. it('should replace the variable with the value', () => {
  156. expect(interpolated.length).toBe(3);
  157. expect(interpolated[2]).toBe('filtervalue1');
  158. });
  159. });
  160. describe('and is multi value variable', () => {
  161. beforeEach(() => {
  162. const filterTemplateSrv = initTemplateSrv(['filtervalue1', 'filtervalue2'], true);
  163. const ds = new StackdriverDataSource(instanceSettings, {}, filterTemplateSrv, timeSrv);
  164. interpolated = ds.interpolateFilters(['resource.label.zone', '=~', '[[test]]'], {});
  165. });
  166. it('should replace the variable with a regex expression', () => {
  167. expect(interpolated[2]).toBe('(filtervalue1|filtervalue2)');
  168. });
  169. });
  170. });
  171. describe('when interpolating a template variable for group bys', () => {
  172. let interpolated;
  173. describe('and is single value variable', () => {
  174. beforeEach(() => {
  175. const groupByTemplateSrv = initTemplateSrv('groupby1');
  176. const ds = new StackdriverDataSource(instanceSettings, {}, groupByTemplateSrv, timeSrv);
  177. interpolated = ds.interpolateGroupBys(['[[test]]'], {});
  178. });
  179. it('should replace the variable with the value', () => {
  180. expect(interpolated.length).toBe(1);
  181. expect(interpolated[0]).toBe('groupby1');
  182. });
  183. });
  184. describe('and is multi value variable', () => {
  185. beforeEach(() => {
  186. const groupByTemplateSrv = initTemplateSrv(['groupby1', 'groupby2'], true);
  187. const ds = new StackdriverDataSource(instanceSettings, {}, groupByTemplateSrv, timeSrv);
  188. interpolated = ds.interpolateGroupBys(['[[test]]'], {});
  189. });
  190. it('should replace the variable with an array of group bys', () => {
  191. expect(interpolated.length).toBe(2);
  192. expect(interpolated[0]).toBe('groupby1');
  193. expect(interpolated[1]).toBe('groupby2');
  194. });
  195. });
  196. });
  197. describe('unit parsing', () => {
  198. let ds, res;
  199. beforeEach(() => {
  200. ds = new StackdriverDataSource(instanceSettings, {}, templateSrv, timeSrv);
  201. });
  202. describe('when theres only one target', () => {
  203. describe('and the stackdriver unit doesnt have a corresponding grafana unit', () => {
  204. beforeEach(() => {
  205. res = ds.resolvePanelUnitFromTargets([{ unit: 'megaseconds' }]);
  206. });
  207. it('should return undefined', () => {
  208. expect(res).toBeUndefined();
  209. });
  210. });
  211. describe('and the stackdriver unit has a corresponding grafana unit', () => {
  212. beforeEach(() => {
  213. res = ds.resolvePanelUnitFromTargets([{ unit: 'bit' }]);
  214. });
  215. it('should return bits', () => {
  216. expect(res).toEqual('bits');
  217. });
  218. });
  219. });
  220. describe('when theres more than one target', () => {
  221. describe('and all target units are the same', () => {
  222. beforeEach(() => {
  223. res = ds.resolvePanelUnitFromTargets([{ unit: 'bit' }, { unit: 'bit' }]);
  224. });
  225. it('should return bits', () => {
  226. expect(res).toEqual('bits');
  227. });
  228. });
  229. describe('and all target units are the same but doesnt have grafana mappings', () => {
  230. beforeEach(() => {
  231. res = ds.resolvePanelUnitFromTargets([{ unit: 'megaseconds' }, { unit: 'megaseconds' }]);
  232. });
  233. it('should return the default value of undefined', () => {
  234. expect(res).toBeUndefined();
  235. });
  236. });
  237. describe('and all target units are not the same', () => {
  238. beforeEach(() => {
  239. res = ds.resolvePanelUnitFromTargets([{ unit: 'bit' }, { unit: 'min' }]);
  240. });
  241. it('should return the default value of undefined', () => {
  242. expect(res).toBeUndefined();
  243. });
  244. });
  245. });
  246. });
  247. });
  248. function initTemplateSrv(values: any, multi = false) {
  249. const templateSrv = new TemplateSrv();
  250. templateSrv.init([
  251. new CustomVariable(
  252. {
  253. name: 'test',
  254. current: {
  255. value: values,
  256. },
  257. multi: multi,
  258. },
  259. {}
  260. ),
  261. ]);
  262. return templateSrv;
  263. }