variable_srv_specs.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
  2. import '../all';
  3. import moment from 'moment';
  4. import helpers from 'test/specs/helpers';
  5. import {Emitter} from 'app/core/core';
  6. describe('VariableSrv', function() {
  7. var ctx = new helpers.ControllerTestContext();
  8. beforeEach(angularMocks.module('grafana.core'));
  9. beforeEach(angularMocks.module('grafana.controllers'));
  10. beforeEach(angularMocks.module('grafana.services'));
  11. beforeEach(ctx.providePhase(['datasourceSrv', 'timeSrv', 'templateSrv', '$location']));
  12. beforeEach(angularMocks.inject(($rootScope, $q, $location, $injector) => {
  13. ctx.$q = $q;
  14. ctx.$rootScope = $rootScope;
  15. ctx.$location = $location;
  16. ctx.variableSrv = $injector.get('variableSrv');
  17. ctx.variableSrv.init({
  18. templating: {list: []},
  19. events: new Emitter(),
  20. updateSubmenuVisibility: sinon.stub(),
  21. });
  22. ctx.$rootScope.$digest();
  23. }));
  24. function describeUpdateVariable(desc, fn) {
  25. describe(desc, function() {
  26. var scenario: any = {};
  27. scenario.setup = function(setupFn) {
  28. scenario.setupFn = setupFn;
  29. };
  30. beforeEach(function() {
  31. scenario.setupFn();
  32. var ds: any = {};
  33. ds.metricFindQuery = sinon.stub().returns(ctx.$q.when(scenario.queryResult));
  34. ctx.datasourceSrv.get = sinon.stub().returns(ctx.$q.when(ds));
  35. ctx.datasourceSrv.getMetricSources = sinon.stub().returns(scenario.metricSources);
  36. scenario.variable = ctx.variableSrv.createVariableFromModel(scenario.variableModel);
  37. ctx.variableSrv.addVariable(scenario.variable);
  38. ctx.variableSrv.updateOptions(scenario.variable);
  39. ctx.$rootScope.$digest();
  40. });
  41. fn(scenario);
  42. });
  43. }
  44. describeUpdateVariable('interval variable without auto', scenario => {
  45. scenario.setup(() => {
  46. scenario.variableModel = {type: 'interval', query: '1s,2h,5h,1d', name: 'test'};
  47. });
  48. it('should update options array', () => {
  49. expect(scenario.variable.options.length).to.be(4);
  50. expect(scenario.variable.options[0].text).to.be('1s');
  51. expect(scenario.variable.options[0].value).to.be('1s');
  52. });
  53. });
  54. //
  55. // Interval variable update
  56. //
  57. describeUpdateVariable('interval variable with auto', scenario => {
  58. scenario.setup(() => {
  59. scenario.variableModel = {type: 'interval', query: '1s,2h,5h,1d', name: 'test', auto: true, auto_count: 10 };
  60. var range = {
  61. from: moment(new Date()).subtract(7, 'days').toDate(),
  62. to: new Date()
  63. };
  64. ctx.timeSrv.timeRange = sinon.stub().returns(range);
  65. ctx.templateSrv.setGrafanaVariable = sinon.spy();
  66. });
  67. it('should update options array', function() {
  68. expect(scenario.variable.options.length).to.be(5);
  69. expect(scenario.variable.options[0].text).to.be('auto');
  70. expect(scenario.variable.options[0].value).to.be('$__auto_interval');
  71. });
  72. it('should set $__auto_interval', function() {
  73. var call = ctx.templateSrv.setGrafanaVariable.getCall(0);
  74. expect(call.args[0]).to.be('$__auto_interval');
  75. expect(call.args[1]).to.be('12h');
  76. });
  77. });
  78. //
  79. // Query variable update
  80. //
  81. describeUpdateVariable('query variable with empty current object and refresh', function(scenario) {
  82. scenario.setup(function() {
  83. scenario.variableModel = {type: 'query', query: '', name: 'test', current: {}};
  84. scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}];
  85. });
  86. it('should set current value to first option', function() {
  87. expect(scenario.variable.options.length).to.be(2);
  88. expect(scenario.variable.current.value).to.be('backend1');
  89. });
  90. });
  91. describeUpdateVariable('query variable with multi select and new options does not contain some selected values', function(scenario) {
  92. scenario.setup(function() {
  93. scenario.variableModel = {
  94. type: 'query',
  95. query: '',
  96. name: 'test',
  97. current: {
  98. value: ['val1', 'val2', 'val3'],
  99. text: 'val1 + val2 + val3'
  100. }
  101. };
  102. scenario.queryResult = [{text: 'val2'}, {text: 'val3'}];
  103. });
  104. it('should update current value', function() {
  105. expect(scenario.variable.current.value).to.eql(['val2', 'val3']);
  106. expect(scenario.variable.current.text).to.eql('val2 + val3');
  107. });
  108. });
  109. describeUpdateVariable('query variable with multi select and new options does not contain any selected values', function(scenario) {
  110. scenario.setup(function() {
  111. scenario.variableModel = {
  112. type: 'query',
  113. query: '',
  114. name: 'test',
  115. current: {
  116. value: ['val1', 'val2', 'val3'],
  117. text: 'val1 + val2 + val3'
  118. }
  119. };
  120. scenario.queryResult = [{text: 'val5'}, {text: 'val6'}];
  121. });
  122. it('should update current value with first one', function() {
  123. expect(scenario.variable.current.value).to.eql('val5');
  124. expect(scenario.variable.current.text).to.eql('val5');
  125. });
  126. });
  127. describeUpdateVariable('query variable with multi select and $__all selected', function(scenario) {
  128. scenario.setup(function() {
  129. scenario.variableModel = {
  130. type: 'query',
  131. query: '',
  132. name: 'test',
  133. includeAll: true,
  134. current: {
  135. value: ['$__all'],
  136. text: 'All'
  137. }
  138. };
  139. scenario.queryResult = [{text: 'val5'}, {text: 'val6'}];
  140. });
  141. it('should keep current All value', function() {
  142. expect(scenario.variable.current.value).to.eql(['$__all']);
  143. expect(scenario.variable.current.text).to.eql('All');
  144. });
  145. });
  146. describeUpdateVariable('query variable with numeric results', function(scenario) {
  147. scenario.setup(function() {
  148. scenario.variableModel = { type: 'query', query: '', name: 'test', current: {} };
  149. scenario.queryResult = [{text: 12, value: 12}];
  150. });
  151. it('should set current value to first option', function() {
  152. expect(scenario.variable.current.value).to.be('12');
  153. expect(scenario.variable.options[0].value).to.be('12');
  154. expect(scenario.variable.options[0].text).to.be('12');
  155. });
  156. });
  157. describeUpdateVariable('basic query variable', function(scenario) {
  158. scenario.setup(function() {
  159. scenario.variableModel = { type: 'query', query: 'apps.*', name: 'test' };
  160. scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}];
  161. });
  162. it('should update options array', function() {
  163. expect(scenario.variable.options.length).to.be(2);
  164. expect(scenario.variable.options[0].text).to.be('backend1');
  165. expect(scenario.variable.options[0].value).to.be('backend1');
  166. expect(scenario.variable.options[1].value).to.be('backend2');
  167. });
  168. it('should select first option as value', function() {
  169. expect(scenario.variable.current.value).to.be('backend1');
  170. });
  171. });
  172. describeUpdateVariable('and existing value still exists in options', function(scenario) {
  173. scenario.setup(function() {
  174. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test'};
  175. scenario.variableModel.current = { value: 'backend2', text: 'backend2'};
  176. scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}];
  177. });
  178. it('should keep variable value', function() {
  179. expect(scenario.variable.current.text).to.be('backend2');
  180. });
  181. });
  182. describeUpdateVariable('and regex pattern exists', function(scenario) {
  183. scenario.setup(function() {
  184. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test'};
  185. scenario.variableModel.regex = '/apps.*(backend_[0-9]+)/';
  186. scenario.queryResult = [{text: 'apps.backend.backend_01.counters.req'}, {text: 'apps.backend.backend_02.counters.req'}];
  187. });
  188. it('should extract and use match group', function() {
  189. expect(scenario.variable.options[0].value).to.be('backend_01');
  190. });
  191. });
  192. describeUpdateVariable('and regex pattern exists and no match', function(scenario) {
  193. scenario.setup(function() {
  194. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test'};
  195. scenario.variableModel.regex = '/apps.*(backendasd[0-9]+)/';
  196. scenario.queryResult = [{text: 'apps.backend.backend_01.counters.req'}, {text: 'apps.backend.backend_02.counters.req'}];
  197. });
  198. it('should not add non matching items, None option should be added instead', function() {
  199. expect(scenario.variable.options.length).to.be(1);
  200. expect(scenario.variable.options[0].isNone).to.be(true);
  201. });
  202. });
  203. describeUpdateVariable('regex pattern without slashes', function(scenario) {
  204. scenario.setup(function() {
  205. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test'};
  206. scenario.variableModel.regex = 'backend_01';
  207. scenario.queryResult = [{text: 'apps.backend.backend_01.counters.req'}, {text: 'apps.backend.backend_02.counters.req'}];
  208. });
  209. it('should return matches options', function() {
  210. expect(scenario.variable.options.length).to.be(1);
  211. });
  212. });
  213. describeUpdateVariable('regex pattern remove duplicates', function(scenario) {
  214. scenario.setup(function() {
  215. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test'};
  216. scenario.variableModel.regex = '/backend_01/';
  217. scenario.queryResult = [{text: 'apps.backend.backend_01.counters.req'}, {text: 'apps.backend.backend_01.counters.req'}];
  218. });
  219. it('should return matches options', function() {
  220. expect(scenario.variable.options.length).to.be(1);
  221. });
  222. });
  223. describeUpdateVariable('with include All', function(scenario) {
  224. scenario.setup(function() {
  225. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', includeAll: true};
  226. scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}, { text: 'backend3'}];
  227. });
  228. it('should add All option', function() {
  229. expect(scenario.variable.options[0].text).to.be('All');
  230. expect(scenario.variable.options[0].value).to.be('$__all');
  231. });
  232. });
  233. describeUpdateVariable('with include all and custom value', function(scenario) {
  234. scenario.setup(function() {
  235. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', includeAll: true, allValue: '*'};
  236. scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}, { text: 'backend3'}];
  237. });
  238. it('should add All option with custom value', function() {
  239. expect(scenario.variable.options[0].value).to.be('$__all');
  240. });
  241. });
  242. describeUpdateVariable('without sort', function(scenario) {
  243. scenario.setup(function() {
  244. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', sort: 0};
  245. scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
  246. });
  247. it('should return options without sort', function() {
  248. expect(scenario.variable.options[0].text).to.be('bbb2');
  249. expect(scenario.variable.options[1].text).to.be('aaa10');
  250. expect(scenario.variable.options[2].text).to.be('ccc3');
  251. });
  252. });
  253. describeUpdateVariable('with alphabetical sort (asc)', function(scenario) {
  254. scenario.setup(function() {
  255. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', sort: 1};
  256. scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
  257. });
  258. it('should return options with alphabetical sort', function() {
  259. expect(scenario.variable.options[0].text).to.be('aaa10');
  260. expect(scenario.variable.options[1].text).to.be('bbb2');
  261. expect(scenario.variable.options[2].text).to.be('ccc3');
  262. });
  263. });
  264. describeUpdateVariable('with alphabetical sort (desc)', function(scenario) {
  265. scenario.setup(function() {
  266. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', sort: 2};
  267. scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
  268. });
  269. it('should return options with alphabetical sort', function() {
  270. expect(scenario.variable.options[0].text).to.be('ccc3');
  271. expect(scenario.variable.options[1].text).to.be('bbb2');
  272. expect(scenario.variable.options[2].text).to.be('aaa10');
  273. });
  274. });
  275. describeUpdateVariable('with numerical sort (asc)', function(scenario) {
  276. scenario.setup(function() {
  277. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', sort: 3};
  278. scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
  279. });
  280. it('should return options with numerical sort', function() {
  281. expect(scenario.variable.options[0].text).to.be('bbb2');
  282. expect(scenario.variable.options[1].text).to.be('ccc3');
  283. expect(scenario.variable.options[2].text).to.be('aaa10');
  284. });
  285. });
  286. describeUpdateVariable('with numerical sort (desc)', function(scenario) {
  287. scenario.setup(function() {
  288. scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', sort: 4};
  289. scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
  290. });
  291. it('should return options with numerical sort', function() {
  292. expect(scenario.variable.options[0].text).to.be('aaa10');
  293. expect(scenario.variable.options[1].text).to.be('ccc3');
  294. expect(scenario.variable.options[2].text).to.be('bbb2');
  295. });
  296. });
  297. //
  298. // datasource variable update
  299. //
  300. describeUpdateVariable('datasource variable with regex filter', function(scenario) {
  301. scenario.setup(function() {
  302. scenario.variableModel = {
  303. type: 'datasource',
  304. query: 'graphite',
  305. name: 'test',
  306. current: {value: 'backend4_pee', text: 'backend4_pee'},
  307. regex: '/pee$/'
  308. };
  309. scenario.metricSources = [
  310. {name: 'backend1', meta: {id: 'influx'}},
  311. {name: 'backend2_pee', meta: {id: 'graphite'}},
  312. {name: 'backend3', meta: {id: 'graphite'}},
  313. {name: 'backend4_pee', meta: {id: 'graphite'}},
  314. ];
  315. });
  316. it('should set only contain graphite ds and filtered using regex', function() {
  317. expect(scenario.variable.options.length).to.be(2);
  318. expect(scenario.variable.options[0].value).to.be('backend2_pee');
  319. expect(scenario.variable.options[1].value).to.be('backend4_pee');
  320. });
  321. it('should keep current value if available', function() {
  322. expect(scenario.variable.current.value).to.be('backend4_pee');
  323. });
  324. });
  325. //
  326. // Custom variable update
  327. //
  328. describeUpdateVariable('update custom variable', function(scenario) {
  329. scenario.setup(function() {
  330. scenario.variableModel = {type: 'custom', query: 'hej, hop, asd', name: 'test'};
  331. });
  332. it('should update options array', function() {
  333. expect(scenario.variable.options.length).to.be(3);
  334. expect(scenario.variable.options[0].text).to.be('hej');
  335. expect(scenario.variable.options[1].value).to.be('hop');
  336. });
  337. });
  338. });