datasource_srv.test.ts 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. import {
  2. DataSourceApi,
  3. DataSourceInstanceSettings,
  4. DataSourcePlugin,
  5. DataSourcePluginMeta,
  6. ScopedVar,
  7. } from '@grafana/data';
  8. import { DatasourceSrv } from 'app/features/plugins/datasource_srv';
  9. // Datasource variable $datasource with current value 'BBB'
  10. const templateSrv: any = {
  11. getVariables: () => [
  12. {
  13. type: 'datasource',
  14. name: 'datasource',
  15. current: {
  16. value: 'BBB',
  17. },
  18. },
  19. {
  20. type: 'datasource',
  21. name: 'datasourceDefault',
  22. current: {
  23. value: 'default',
  24. },
  25. },
  26. ],
  27. replace: (v: string, scopedVars: ScopedVar) => {
  28. if (scopedVars && scopedVars.datasource) {
  29. return v.replace('${datasource}', scopedVars.datasource.value);
  30. }
  31. let result = v.replace('${datasource}', 'BBB');
  32. result = result.replace('${datasourceDefault}', 'default');
  33. return result;
  34. },
  35. };
  36. class TestDataSource {
  37. constructor(public instanceSettings: DataSourceInstanceSettings) {}
  38. }
  39. jest.mock('../plugin_loader', () => ({
  40. importDataSourcePlugin: (meta: DataSourcePluginMeta) => {
  41. return Promise.resolve(new DataSourcePlugin(TestDataSource as any));
  42. },
  43. }));
  44. const getBackendSrvGetMock = jest.fn();
  45. jest.mock('@grafana/runtime', () => ({
  46. ...jest.requireActual('@grafana/runtime'),
  47. getBackendSrv: () => ({
  48. get: getBackendSrvGetMock,
  49. }),
  50. }));
  51. describe('datasource_srv', () => {
  52. beforeEach(() => {
  53. jest.resetModules();
  54. });
  55. const dataSourceSrv = new DatasourceSrv(templateSrv);
  56. const dataSourceInit = {
  57. mmm: {
  58. type: 'test-db',
  59. name: 'mmm',
  60. uid: 'uid-code-mmm',
  61. meta: { metrics: true, annotations: true } as any,
  62. },
  63. '-- Grafana --': {
  64. type: 'grafana',
  65. name: '-- Grafana --',
  66. meta: { builtIn: true, metrics: true, id: 'grafana' },
  67. },
  68. '-- Dashboard --': {
  69. type: 'dashboard',
  70. name: '-- Dashboard --',
  71. meta: { builtIn: true, metrics: true, id: 'dashboard' },
  72. },
  73. '-- Mixed --': {
  74. type: 'test-db',
  75. name: '-- Mixed --',
  76. meta: { builtIn: true, metrics: true, id: 'mixed' },
  77. },
  78. ZZZ: {
  79. type: 'test-db',
  80. name: 'ZZZ',
  81. uid: 'uid-code-ZZZ',
  82. meta: { metrics: true },
  83. },
  84. aaa: {
  85. type: 'test-db',
  86. name: 'aaa',
  87. uid: 'uid-code-aaa',
  88. meta: { metrics: true },
  89. },
  90. BBB: {
  91. type: 'test-db',
  92. name: 'BBB',
  93. uid: 'uid-code-BBB',
  94. meta: { metrics: true },
  95. isDefault: true,
  96. },
  97. Jaeger: {
  98. type: 'jaeger-db',
  99. name: 'Jaeger',
  100. uid: 'uid-code-Jaeger',
  101. meta: { tracing: true, id: 'jaeger' },
  102. },
  103. CannotBeQueried: {
  104. type: 'no-query',
  105. name: 'no-query',
  106. uid: 'no-query',
  107. meta: { id: 'no-query' },
  108. },
  109. };
  110. describe('Given a list of data sources', () => {
  111. beforeEach(() => {
  112. dataSourceSrv.init(dataSourceInit as any, 'BBB');
  113. });
  114. describe('when getting data source class instance', () => {
  115. it('should load plugin and create instance and set meta', async () => {
  116. const ds = (await dataSourceSrv.get('mmm')) as any;
  117. expect(ds.meta).toBe(dataSourceInit.mmm.meta);
  118. expect(ds.instanceSettings).toBe(dataSourceInit.mmm);
  119. // validate that it caches instance
  120. const ds2 = await dataSourceSrv.get('mmm');
  121. expect(ds).toBe(ds2);
  122. });
  123. it('should be able to load data source using uid as well', async () => {
  124. const dsByUid = await dataSourceSrv.get('uid-code-mmm');
  125. const dsByName = await dataSourceSrv.get('mmm');
  126. expect(dsByUid.meta).toBe(dsByName.meta);
  127. expect(dsByUid).toBe(dsByName);
  128. });
  129. it('should patch legacy datasources', async () => {
  130. expect(TestDataSource instanceof DataSourceApi).toBe(false);
  131. const instance = await dataSourceSrv.get('mmm');
  132. expect(instance.name).toBe('mmm');
  133. expect(instance.type).toBe('test-db');
  134. expect(instance.uid).toBe('uid-code-mmm');
  135. expect(instance.getRef()).toEqual({ type: 'test-db', uid: 'uid-code-mmm' });
  136. });
  137. it('Can get by variable', async () => {
  138. const ds = (await dataSourceSrv.get('${datasource}')) as any;
  139. expect(ds.meta).toBe(dataSourceInit.BBB.meta);
  140. const ds2 = await dataSourceSrv.get('${datasource}', { datasource: { text: 'Prom', value: 'uid-code-aaa' } });
  141. expect(ds2.uid).toBe(dataSourceInit.aaa.uid);
  142. });
  143. });
  144. describe('when getting instance settings', () => {
  145. it('should work by name or uid', () => {
  146. const ds = dataSourceSrv.getInstanceSettings('mmm');
  147. expect(dataSourceSrv.getInstanceSettings('uid-code-mmm')).toBe(ds);
  148. expect(dataSourceSrv.getInstanceSettings({ uid: 'uid-code-mmm' })).toBe(ds);
  149. });
  150. it('should work with variable', () => {
  151. const ds = dataSourceSrv.getInstanceSettings('${datasource}');
  152. expect(ds?.name).toBe('${datasource}');
  153. expect(ds?.uid).toBe('${datasource}');
  154. expect(ds?.rawRef).toMatchInlineSnapshot(`
  155. Object {
  156. "type": "test-db",
  157. "uid": "uid-code-BBB",
  158. }
  159. `);
  160. });
  161. it('should work with variable via scopedVars', () => {
  162. const ds = dataSourceSrv.getInstanceSettings('${datasource}', {
  163. datasource: { text: 'Prom', value: 'uid-code-aaa' },
  164. });
  165. expect(ds?.rawRef?.uid).toBe('uid-code-aaa');
  166. });
  167. it('should not set isDefault when being fetched via variable', () => {
  168. const ds = dataSourceSrv.getInstanceSettings('${datasource}');
  169. expect(ds?.isDefault).toBe(false);
  170. });
  171. it('should work with variable', () => {
  172. const ds = dataSourceSrv.getInstanceSettings('${datasourceDefault}');
  173. expect(ds?.name).toBe('${datasourceDefault}');
  174. expect(ds?.uid).toBe('${datasourceDefault}');
  175. expect(ds?.rawRef).toMatchInlineSnapshot(`
  176. Object {
  177. "type": "test-db",
  178. "uid": "uid-code-BBB",
  179. }
  180. `);
  181. });
  182. });
  183. describe('when getting external metric sources', () => {
  184. it('should return list of explore sources', () => {
  185. const externalSources = dataSourceSrv.getExternal();
  186. expect(externalSources.length).toBe(6);
  187. });
  188. });
  189. it('Should by default filter out data sources that cannot be queried', () => {
  190. const list = dataSourceSrv.getList({});
  191. expect(list.find((x) => x.name === 'no-query')).toBeUndefined();
  192. const all = dataSourceSrv.getList({ all: true });
  193. expect(all.find((x) => x.name === 'no-query')).toBeDefined();
  194. });
  195. it('Can get list of data sources with variables: true', () => {
  196. const list = dataSourceSrv.getList({ metrics: true, variables: true });
  197. expect(list[0].name).toBe('${datasourceDefault}');
  198. expect(list[1].name).toBe('${datasource}');
  199. });
  200. it('Can get list of data sources with tracing: true', () => {
  201. const list = dataSourceSrv.getList({ tracing: true });
  202. expect(list[0].name).toBe('Jaeger');
  203. });
  204. it('Can get list of data sources with annotation: true', () => {
  205. const list = dataSourceSrv.getList({ annotations: true });
  206. expect(list[0].name).toBe('mmm');
  207. });
  208. it('Can get get list and filter by pluginId', () => {
  209. const list = dataSourceSrv.getList({ pluginId: 'jaeger' });
  210. expect(list[0].name).toBe('Jaeger');
  211. expect(list.length).toBe(1);
  212. });
  213. it('Can get list of data sources with metrics: true, builtIn: true, mixed: true', () => {
  214. expect(dataSourceSrv.getList({ metrics: true, dashboard: true, mixed: true })).toMatchInlineSnapshot(`
  215. Array [
  216. Object {
  217. "meta": Object {
  218. "metrics": true,
  219. },
  220. "name": "aaa",
  221. "type": "test-db",
  222. "uid": "uid-code-aaa",
  223. },
  224. Object {
  225. "isDefault": true,
  226. "meta": Object {
  227. "metrics": true,
  228. },
  229. "name": "BBB",
  230. "type": "test-db",
  231. "uid": "uid-code-BBB",
  232. },
  233. Object {
  234. "meta": Object {
  235. "annotations": true,
  236. "metrics": true,
  237. },
  238. "name": "mmm",
  239. "type": "test-db",
  240. "uid": "uid-code-mmm",
  241. },
  242. Object {
  243. "meta": Object {
  244. "metrics": true,
  245. },
  246. "name": "ZZZ",
  247. "type": "test-db",
  248. "uid": "uid-code-ZZZ",
  249. },
  250. Object {
  251. "meta": Object {
  252. "builtIn": true,
  253. "id": "mixed",
  254. "metrics": true,
  255. },
  256. "name": "-- Mixed --",
  257. "type": "test-db",
  258. "uid": "-- Mixed --",
  259. },
  260. Object {
  261. "meta": Object {
  262. "builtIn": true,
  263. "id": "dashboard",
  264. "metrics": true,
  265. },
  266. "name": "-- Dashboard --",
  267. "type": "dashboard",
  268. "uid": "-- Dashboard --",
  269. },
  270. Object {
  271. "meta": Object {
  272. "builtIn": true,
  273. "id": "grafana",
  274. "metrics": true,
  275. },
  276. "name": "-- Grafana --",
  277. "type": "grafana",
  278. "uid": "-- Grafana --",
  279. },
  280. ]
  281. `);
  282. });
  283. it('Should reload the datasource', async () => {
  284. // arrange
  285. getBackendSrvGetMock.mockReturnValueOnce({
  286. datasources: {
  287. ...dataSourceInit,
  288. },
  289. defaultDatasource: 'aaa',
  290. });
  291. const initMock = jest.spyOn(dataSourceSrv, 'init').mockImplementation(() => {});
  292. // act
  293. await dataSourceSrv.reload();
  294. // assert
  295. expect(getBackendSrvGetMock).toHaveBeenCalledWith('/api/frontend/settings');
  296. expect(initMock).toHaveBeenCalledWith(dataSourceInit, 'aaa');
  297. });
  298. });
  299. });