datasource_specs.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. import { describe, beforeEach, it, expect, angularMocks } from 'test/lib/common';
  2. import moment from 'moment';
  3. import $ from 'jquery';
  4. import helpers from 'test/specs/helpers';
  5. import { PrometheusDatasource } from '../datasource';
  6. const SECOND = 1000;
  7. const MINUTE = 60 * SECOND;
  8. const HOUR = 60 * MINUTE;
  9. const time = ({ hours = 0, seconds = 0, minutes = 0 }) => moment(hours * HOUR + minutes * MINUTE + seconds * SECOND);
  10. describe('PrometheusDatasource', function() {
  11. var ctx = new helpers.ServiceTestContext();
  12. var instanceSettings = {
  13. url: 'proxied',
  14. directUrl: 'direct',
  15. user: 'test',
  16. password: 'mupp',
  17. jsonData: { httpMethod: 'GET' },
  18. };
  19. beforeEach(angularMocks.module('grafana.core'));
  20. beforeEach(angularMocks.module('grafana.services'));
  21. beforeEach(ctx.providePhase(['timeSrv']));
  22. beforeEach(
  23. angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) {
  24. ctx.$q = $q;
  25. ctx.$httpBackend = $httpBackend;
  26. ctx.$rootScope = $rootScope;
  27. ctx.ds = $injector.instantiate(PrometheusDatasource, {
  28. instanceSettings: instanceSettings,
  29. });
  30. $httpBackend.when('GET', /\.html$/).respond('');
  31. })
  32. );
  33. describe('When querying prometheus with one target using query editor target spec', function() {
  34. var results;
  35. var query = {
  36. range: { from: time({ seconds: 63 }), to: time({ seconds: 183 }) },
  37. targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }],
  38. interval: '60s',
  39. };
  40. // Interval alignment with step
  41. var urlExpected =
  42. 'proxied/api/v1/query_range?query=' + encodeURIComponent('test{job="testjob"}') + '&start=60&end=240&step=60';
  43. var response = {
  44. status: 'success',
  45. data: {
  46. resultType: 'matrix',
  47. result: [
  48. {
  49. metric: { __name__: 'test', job: 'testjob' },
  50. values: [[60, '3846']],
  51. },
  52. ],
  53. },
  54. };
  55. beforeEach(function() {
  56. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  57. ctx.ds.query(query).then(function(data) {
  58. results = data;
  59. });
  60. ctx.$httpBackend.flush();
  61. });
  62. it('should generate the correct query', function() {
  63. ctx.$httpBackend.verifyNoOutstandingExpectation();
  64. });
  65. it('should return series list', function() {
  66. expect(results.data.length).to.be(1);
  67. expect(results.data[0].target).to.be('test{job="testjob"}');
  68. });
  69. });
  70. describe('When querying prometheus with one target which return multiple series', function() {
  71. var results;
  72. var start = 60;
  73. var end = 360;
  74. var step = 60;
  75. var urlExpected =
  76. 'proxied/api/v1/query_range?query=' +
  77. encodeURIComponent('test{job="testjob"}') +
  78. '&start=' +
  79. start +
  80. '&end=' +
  81. end +
  82. '&step=' +
  83. step;
  84. var query = {
  85. range: { from: time({ seconds: start }), to: time({ seconds: end }) },
  86. targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }],
  87. interval: '60s',
  88. };
  89. var response = {
  90. status: 'success',
  91. data: {
  92. resultType: 'matrix',
  93. result: [
  94. {
  95. metric: { __name__: 'test', job: 'testjob', series: 'series 1' },
  96. values: [[start + step * 1, '3846'], [start + step * 3, '3847'], [end - step * 1, '3848']],
  97. },
  98. {
  99. metric: { __name__: 'test', job: 'testjob', series: 'series 2' },
  100. values: [[start + step * 2, '4846']],
  101. },
  102. ],
  103. },
  104. };
  105. beforeEach(function() {
  106. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  107. ctx.ds.query(query).then(function(data) {
  108. results = data;
  109. });
  110. ctx.$httpBackend.flush();
  111. });
  112. it('should be same length', function() {
  113. expect(results.data.length).to.be(2);
  114. expect(results.data[0].datapoints.length).to.be((end - start) / step + 1);
  115. expect(results.data[1].datapoints.length).to.be((end - start) / step + 1);
  116. });
  117. it('should fill null until first datapoint in response', function() {
  118. expect(results.data[0].datapoints[0][1]).to.be(start * 1000);
  119. expect(results.data[0].datapoints[0][0]).to.be(null);
  120. expect(results.data[0].datapoints[1][1]).to.be((start + step * 1) * 1000);
  121. expect(results.data[0].datapoints[1][0]).to.be(3846);
  122. });
  123. it('should fill null after last datapoint in response', function() {
  124. var length = (end - start) / step + 1;
  125. expect(results.data[0].datapoints[length - 2][1]).to.be((end - step * 1) * 1000);
  126. expect(results.data[0].datapoints[length - 2][0]).to.be(3848);
  127. expect(results.data[0].datapoints[length - 1][1]).to.be(end * 1000);
  128. expect(results.data[0].datapoints[length - 1][0]).to.be(null);
  129. });
  130. it('should fill null at gap between series', function() {
  131. expect(results.data[0].datapoints[2][1]).to.be((start + step * 2) * 1000);
  132. expect(results.data[0].datapoints[2][0]).to.be(null);
  133. expect(results.data[1].datapoints[1][1]).to.be((start + step * 1) * 1000);
  134. expect(results.data[1].datapoints[1][0]).to.be(null);
  135. expect(results.data[1].datapoints[3][1]).to.be((start + step * 3) * 1000);
  136. expect(results.data[1].datapoints[3][0]).to.be(null);
  137. });
  138. });
  139. describe('When querying prometheus with one target and instant = true', function() {
  140. var results;
  141. var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123';
  142. var query = {
  143. range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) },
  144. targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }],
  145. interval: '60s',
  146. };
  147. var response = {
  148. status: 'success',
  149. data: {
  150. resultType: 'vector',
  151. result: [
  152. {
  153. metric: { __name__: 'test', job: 'testjob' },
  154. value: [123, '3846'],
  155. },
  156. ],
  157. },
  158. };
  159. beforeEach(function() {
  160. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  161. ctx.ds.query(query).then(function(data) {
  162. results = data;
  163. });
  164. ctx.$httpBackend.flush();
  165. });
  166. it('should generate the correct query', function() {
  167. ctx.$httpBackend.verifyNoOutstandingExpectation();
  168. });
  169. it('should return series list', function() {
  170. expect(results.data.length).to.be(1);
  171. expect(results.data[0].target).to.be('test{job="testjob"}');
  172. });
  173. });
  174. describe('When performing annotationQuery', function() {
  175. var results;
  176. var urlExpected =
  177. 'proxied/api/v1/query_range?query=' +
  178. encodeURIComponent('ALERTS{alertstate="firing"}') +
  179. '&start=60&end=180&step=60';
  180. var options = {
  181. annotation: {
  182. expr: 'ALERTS{alertstate="firing"}',
  183. tagKeys: 'job',
  184. titleFormat: '{{alertname}}',
  185. textFormat: '{{instance}}',
  186. },
  187. range: {
  188. from: time({ seconds: 63 }),
  189. to: time({ seconds: 123 }),
  190. },
  191. };
  192. var response = {
  193. status: 'success',
  194. data: {
  195. resultType: 'matrix',
  196. result: [
  197. {
  198. metric: {
  199. __name__: 'ALERTS',
  200. alertname: 'InstanceDown',
  201. alertstate: 'firing',
  202. instance: 'testinstance',
  203. job: 'testjob',
  204. },
  205. values: [[123, '1']],
  206. },
  207. ],
  208. },
  209. };
  210. beforeEach(function() {
  211. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  212. ctx.ds.annotationQuery(options).then(function(data) {
  213. results = data;
  214. });
  215. ctx.$httpBackend.flush();
  216. });
  217. it('should return annotation list', function() {
  218. ctx.$rootScope.$apply();
  219. expect(results.length).to.be(1);
  220. expect(results[0].tags).to.contain('testjob');
  221. expect(results[0].title).to.be('InstanceDown');
  222. expect(results[0].text).to.be('testinstance');
  223. expect(results[0].time).to.be(123 * 1000);
  224. });
  225. });
  226. describe('When resultFormat is table and instant = true', function() {
  227. var results;
  228. var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123';
  229. var query = {
  230. range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) },
  231. targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }],
  232. interval: '60s',
  233. };
  234. var response = {
  235. status: 'success',
  236. data: {
  237. resultType: 'vector',
  238. result: [
  239. {
  240. metric: { __name__: 'test', job: 'testjob' },
  241. value: [123, '3846'],
  242. },
  243. ],
  244. },
  245. };
  246. beforeEach(function() {
  247. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  248. ctx.ds.query(query).then(function(data) {
  249. results = data;
  250. });
  251. ctx.$httpBackend.flush();
  252. });
  253. it('should return result', () => {
  254. expect(results).not.to.be(null);
  255. });
  256. });
  257. describe('The "step" query parameter', function() {
  258. var response = {
  259. status: 'success',
  260. data: {
  261. resultType: 'matrix',
  262. result: [],
  263. },
  264. };
  265. it('should be min interval when greater than auto interval', function() {
  266. var query = {
  267. // 6 minute range
  268. range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) },
  269. targets: [
  270. {
  271. expr: 'test',
  272. interval: '10s',
  273. },
  274. ],
  275. interval: '5s',
  276. };
  277. var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=10';
  278. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  279. ctx.ds.query(query);
  280. ctx.$httpBackend.verifyNoOutstandingExpectation();
  281. });
  282. it('step should never go below 1', function() {
  283. var query = {
  284. // 6 minute range
  285. range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) },
  286. targets: [{ expr: 'test' }],
  287. interval: '100ms',
  288. };
  289. var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=1';
  290. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  291. ctx.ds.query(query);
  292. ctx.$httpBackend.verifyNoOutstandingExpectation();
  293. });
  294. it('should be auto interval when greater than min interval', function() {
  295. var query = {
  296. // 6 minute range
  297. range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) },
  298. targets: [
  299. {
  300. expr: 'test',
  301. interval: '5s',
  302. },
  303. ],
  304. interval: '10s',
  305. };
  306. var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=10';
  307. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  308. ctx.ds.query(query);
  309. ctx.$httpBackend.verifyNoOutstandingExpectation();
  310. });
  311. it('should result in querying fewer than 11000 data points', function() {
  312. var query = {
  313. // 6 hour range
  314. range: { from: time({ hours: 1 }), to: time({ hours: 7 }) },
  315. targets: [{ expr: 'test' }],
  316. interval: '1s',
  317. };
  318. var end = 7 * 60 * 60;
  319. var start = 60 * 60;
  320. var urlExpected = 'proxied/api/v1/query_range?query=test&start=' + start + '&end=' + end + '&step=2';
  321. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  322. ctx.ds.query(query);
  323. ctx.$httpBackend.verifyNoOutstandingExpectation();
  324. });
  325. it('should not apply min interval when interval * intervalFactor greater', function() {
  326. var query = {
  327. // 6 minute range
  328. range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) },
  329. targets: [
  330. {
  331. expr: 'test',
  332. interval: '10s',
  333. intervalFactor: 10,
  334. },
  335. ],
  336. interval: '5s',
  337. };
  338. // times get rounded up to interval
  339. var urlExpected = 'proxied/api/v1/query_range?query=test&start=50&end=450&step=50';
  340. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  341. ctx.ds.query(query);
  342. ctx.$httpBackend.verifyNoOutstandingExpectation();
  343. });
  344. it('should apply min interval when interval * intervalFactor smaller', function() {
  345. var query = {
  346. // 6 minute range
  347. range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) },
  348. targets: [
  349. {
  350. expr: 'test',
  351. interval: '15s',
  352. intervalFactor: 2,
  353. },
  354. ],
  355. interval: '5s',
  356. };
  357. var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=60&end=420&step=15';
  358. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  359. ctx.ds.query(query);
  360. ctx.$httpBackend.verifyNoOutstandingExpectation();
  361. });
  362. it('should apply intervalFactor to auto interval when greater', function() {
  363. var query = {
  364. // 6 minute range
  365. range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) },
  366. targets: [
  367. {
  368. expr: 'test',
  369. interval: '5s',
  370. intervalFactor: 10,
  371. },
  372. ],
  373. interval: '10s',
  374. };
  375. // times get aligned to interval
  376. var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=0&end=500&step=100';
  377. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  378. ctx.ds.query(query);
  379. ctx.$httpBackend.verifyNoOutstandingExpectation();
  380. });
  381. it('should not not be affected by the 11000 data points limit when large enough', function() {
  382. var query = {
  383. // 1 week range
  384. range: { from: time({}), to: time({ hours: 7 * 24 }) },
  385. targets: [
  386. {
  387. expr: 'test',
  388. intervalFactor: 10,
  389. },
  390. ],
  391. interval: '10s',
  392. };
  393. var end = 7 * 24 * 60 * 60;
  394. var start = 0;
  395. var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=' + start + '&end=' + end + '&step=100';
  396. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  397. ctx.ds.query(query);
  398. ctx.$httpBackend.verifyNoOutstandingExpectation();
  399. });
  400. it('should be determined by the 11000 data points limit when too small', function() {
  401. var query = {
  402. // 1 week range
  403. range: { from: time({}), to: time({ hours: 7 * 24 }) },
  404. targets: [
  405. {
  406. expr: 'test',
  407. intervalFactor: 10,
  408. },
  409. ],
  410. interval: '5s',
  411. };
  412. var end = 7 * 24 * 60 * 60;
  413. var start = 0;
  414. var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=' + start + '&end=' + end + '&step=60';
  415. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  416. ctx.ds.query(query);
  417. ctx.$httpBackend.verifyNoOutstandingExpectation();
  418. });
  419. });
  420. describe('The __interval and __interval_ms template variables', function() {
  421. var response = {
  422. status: 'success',
  423. data: {
  424. resultType: 'matrix',
  425. result: [],
  426. },
  427. };
  428. it('should be unchanged when auto interval is greater than min interval', function() {
  429. var query = {
  430. // 6 minute range
  431. range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) },
  432. targets: [
  433. {
  434. expr: 'rate(test[$__interval])',
  435. interval: '5s',
  436. },
  437. ],
  438. interval: '10s',
  439. scopedVars: {
  440. __interval: { text: '10s', value: '10s' },
  441. __interval_ms: { text: 10 * 1000, value: 10 * 1000 },
  442. },
  443. };
  444. var urlExpected =
  445. 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[10s])') + '&start=60&end=420&step=10';
  446. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  447. ctx.ds.query(query);
  448. ctx.$httpBackend.verifyNoOutstandingExpectation();
  449. expect(query.scopedVars.__interval.text).to.be('10s');
  450. expect(query.scopedVars.__interval.value).to.be('10s');
  451. expect(query.scopedVars.__interval_ms.text).to.be(10 * 1000);
  452. expect(query.scopedVars.__interval_ms.value).to.be(10 * 1000);
  453. });
  454. it('should be min interval when it is greater than auto interval', function() {
  455. var query = {
  456. // 6 minute range
  457. range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) },
  458. targets: [
  459. {
  460. expr: 'rate(test[$__interval])',
  461. interval: '10s',
  462. },
  463. ],
  464. interval: '5s',
  465. scopedVars: {
  466. __interval: { text: '5s', value: '5s' },
  467. __interval_ms: { text: 5 * 1000, value: 5 * 1000 },
  468. },
  469. };
  470. var urlExpected =
  471. 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[10s])') + '&start=60&end=420&step=10';
  472. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  473. ctx.ds.query(query);
  474. ctx.$httpBackend.verifyNoOutstandingExpectation();
  475. expect(query.scopedVars.__interval.text).to.be('5s');
  476. expect(query.scopedVars.__interval.value).to.be('5s');
  477. expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000);
  478. expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000);
  479. });
  480. it('should account for intervalFactor', function() {
  481. var query = {
  482. // 6 minute range
  483. range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) },
  484. targets: [
  485. {
  486. expr: 'rate(test[$__interval])',
  487. interval: '5s',
  488. intervalFactor: 10,
  489. },
  490. ],
  491. interval: '10s',
  492. scopedVars: {
  493. __interval: { text: '10s', value: '10s' },
  494. __interval_ms: { text: 10 * 1000, value: 10 * 1000 },
  495. },
  496. };
  497. var urlExpected =
  498. 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[100s])') + '&start=0&end=500&step=100';
  499. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  500. ctx.ds.query(query);
  501. ctx.$httpBackend.verifyNoOutstandingExpectation();
  502. expect(query.scopedVars.__interval.text).to.be('10s');
  503. expect(query.scopedVars.__interval.value).to.be('10s');
  504. expect(query.scopedVars.__interval_ms.text).to.be(10 * 1000);
  505. expect(query.scopedVars.__interval_ms.value).to.be(10 * 1000);
  506. });
  507. it('should be interval * intervalFactor when greater than min interval', function() {
  508. var query = {
  509. // 6 minute range
  510. range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) },
  511. targets: [
  512. {
  513. expr: 'rate(test[$__interval])',
  514. interval: '10s',
  515. intervalFactor: 10,
  516. },
  517. ],
  518. interval: '5s',
  519. scopedVars: {
  520. __interval: { text: '5s', value: '5s' },
  521. __interval_ms: { text: 5 * 1000, value: 5 * 1000 },
  522. },
  523. };
  524. var urlExpected =
  525. 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[50s])') + '&start=50&end=450&step=50';
  526. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  527. ctx.ds.query(query);
  528. ctx.$httpBackend.verifyNoOutstandingExpectation();
  529. expect(query.scopedVars.__interval.text).to.be('5s');
  530. expect(query.scopedVars.__interval.value).to.be('5s');
  531. expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000);
  532. expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000);
  533. });
  534. it('should be min interval when greater than interval * intervalFactor', function() {
  535. var query = {
  536. // 6 minute range
  537. range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) },
  538. targets: [
  539. {
  540. expr: 'rate(test[$__interval])',
  541. interval: '15s',
  542. intervalFactor: 2,
  543. },
  544. ],
  545. interval: '5s',
  546. scopedVars: {
  547. __interval: { text: '5s', value: '5s' },
  548. __interval_ms: { text: 5 * 1000, value: 5 * 1000 },
  549. },
  550. };
  551. var urlExpected =
  552. 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[15s])') + '&start=60&end=420&step=15';
  553. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  554. ctx.ds.query(query);
  555. ctx.$httpBackend.verifyNoOutstandingExpectation();
  556. expect(query.scopedVars.__interval.text).to.be('5s');
  557. expect(query.scopedVars.__interval.value).to.be('5s');
  558. expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000);
  559. expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000);
  560. });
  561. it('should be determined by the 11000 data points limit, accounting for intervalFactor', function() {
  562. var query = {
  563. // 1 week range
  564. range: { from: time({}), to: time({ hours: 7 * 24 }) },
  565. targets: [
  566. {
  567. expr: 'rate(test[$__interval])',
  568. intervalFactor: 10,
  569. },
  570. ],
  571. interval: '5s',
  572. scopedVars: {
  573. __interval: { text: '5s', value: '5s' },
  574. __interval_ms: { text: 5 * 1000, value: 5 * 1000 },
  575. },
  576. };
  577. var end = 7 * 24 * 60 * 60;
  578. var start = 0;
  579. var urlExpected =
  580. 'proxied/api/v1/query_range?query=' +
  581. encodeURIComponent('rate(test[60s])') +
  582. '&start=' +
  583. start +
  584. '&end=' +
  585. end +
  586. '&step=60';
  587. ctx.$httpBackend.expect('GET', urlExpected).respond(response);
  588. ctx.ds.query(query);
  589. ctx.$httpBackend.verifyNoOutstandingExpectation();
  590. expect(query.scopedVars.__interval.text).to.be('5s');
  591. expect(query.scopedVars.__interval.value).to.be('5s');
  592. expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000);
  593. expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000);
  594. });
  595. });
  596. });
  597. describe('PrometheusDatasource for POST', function() {
  598. var ctx = new helpers.ServiceTestContext();
  599. var instanceSettings = {
  600. url: 'proxied',
  601. directUrl: 'direct',
  602. user: 'test',
  603. password: 'mupp',
  604. jsonData: { httpMethod: 'POST' },
  605. };
  606. beforeEach(angularMocks.module('grafana.core'));
  607. beforeEach(angularMocks.module('grafana.services'));
  608. beforeEach(ctx.providePhase(['timeSrv']));
  609. beforeEach(
  610. angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) {
  611. ctx.$q = $q;
  612. ctx.$httpBackend = $httpBackend;
  613. ctx.$rootScope = $rootScope;
  614. ctx.ds = $injector.instantiate(PrometheusDatasource, { instanceSettings: instanceSettings });
  615. $httpBackend.when('GET', /\.html$/).respond('');
  616. })
  617. );
  618. describe('When querying prometheus with one target using query editor target spec', function() {
  619. var results;
  620. var urlExpected = 'proxied/api/v1/query_range';
  621. var dataExpected = $.param({
  622. query: 'test{job="testjob"}',
  623. start: 1 * 60,
  624. end: 3 * 60,
  625. step: 60,
  626. });
  627. var query = {
  628. range: { from: time({ minutes: 1, seconds: 3 }), to: time({ minutes: 2, seconds: 3 }) },
  629. targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }],
  630. interval: '60s',
  631. };
  632. var response = {
  633. status: 'success',
  634. data: {
  635. resultType: 'matrix',
  636. result: [
  637. {
  638. metric: { __name__: 'test', job: 'testjob' },
  639. values: [[2 * 60, '3846']],
  640. },
  641. ],
  642. },
  643. };
  644. beforeEach(function() {
  645. ctx.$httpBackend.expectPOST(urlExpected, dataExpected).respond(response);
  646. ctx.ds.query(query).then(function(data) {
  647. results = data;
  648. });
  649. ctx.$httpBackend.flush();
  650. });
  651. it('should generate the correct query', function() {
  652. ctx.$httpBackend.verifyNoOutstandingExpectation();
  653. });
  654. it('should return series list', function() {
  655. expect(results.data.length).to.be(1);
  656. expect(results.data[0].target).to.be('test{job="testjob"}');
  657. });
  658. });
  659. });