From 3d4a346c6621c6e685d338dc95aed0221c84c541 Mon Sep 17 00:00:00 2001 From: Tobias Skarhed Date: Mon, 30 Jul 2018 13:02:08 +0200 Subject: [PATCH 1/6] Begin conversion --- .../prometheus/specs/_datasource.jest.ts | 792 ++++++++++++++++++ 1 file changed, 792 insertions(+) create mode 100644 public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts diff --git a/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts b/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts new file mode 100644 index 00000000000..384abc8f902 --- /dev/null +++ b/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts @@ -0,0 +1,792 @@ +import moment from 'moment'; +import { PrometheusDatasource } from '../datasource'; +import $q from 'q'; + +const SECOND = 1000; +const MINUTE = 60 * SECOND; +const HOUR = 60 * MINUTE; + +const time = ({ hours = 0, seconds = 0, minutes = 0 }) => moment(hours * HOUR + minutes * MINUTE + seconds * SECOND); + +let ctx = {}; +let instanceSettings = { + url: 'proxied', + directUrl: 'direct', + user: 'test', + password: 'mupp', + jsonData: { httpMethod: 'GET' }, +}; +let backendSrv = { + datasourceRequest: jest.fn(), +}; + +let templateSrv = { + replace: (target, scopedVars, format) => { + if (!target) { + return target; + } + let variable, value, fmt; + + return target.replace(scopedVars, (match, var1, var2, fmt2, var3, fmt3) => { + variable = this.index[var1 || var2 || var3]; + fmt = fmt2 || fmt3 || format; + if (scopedVars) { + value = scopedVars[var1 || var2 || var3]; + if (value) { + return this.formatValue(value.value, fmt, variable); + } + } + }); + }, +}; + +let timeSrv = { + timeRange: () => { + return { to: { diff: () => 2000 }, from: '' }; + }, +}; + +describe('PrometheusDatasource', function() { + // beforeEach(angularMocks.module('grafana.core')); + // beforeEach(angularMocks.module('grafana.services')); + // beforeEach(ctx.providePhase(['timeSrv'])); + + // beforeEach( + // angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { + // ctx.$q = $q; + // ctx.$httpBackend = $httpBackend; + // ctx.$rootScope = $rootScope; + // ctx.ds = $injector.instantiate(PrometheusDatasource, { + // instanceSettings: instanceSettings, + // }); + // $httpBackend.when('GET', /\.html$/).respond(''); + // }) + // ); + + beforeEach(() => { + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + }); + describe('When querying prometheus with one target using query editor target spec', function() { + var results; + var query = { + range: { from: time({ seconds: 63 }), to: time({ seconds: 183 }) }, + targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], + interval: '60s', + }; + // Interval alignment with step + var urlExpected = + 'proxied/api/v1/query_range?query=' + encodeURIComponent('test{job="testjob"}') + '&start=60&end=240&step=60'; + var response = { + data: { + status: 'success', + data: { + resultType: 'matrix', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + values: [[60, '3846']], + }, + ], + }, + }, + }; + beforeEach(async () => { + // ctx.$httpBackend.expect('GET', urlExpected).respond(response); + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + + await ctx.ds.query(query).then(function(data) { + results = data; + }); + // ctx.$httpBackend.flush(); + }); + it('should generate the correct query', function() { + // ctx.$httpBackend.verifyNoOutstandingExpectation(); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should return series list', function() { + expect(results.data.length).toBe(1); + expect(results.data[0].target).toBe('test{job="testjob"}'); + }); + }); + describe('When querying prometheus with one target which return multiple series', function() { + var results; + var start = 60; + var end = 360; + var step = 60; + // var urlExpected = + // 'proxied/api/v1/query_range?query=' + + // encodeURIComponent('test{job="testjob"}') + + // '&start=' + + // start + + // '&end=' + + // end + + // '&step=' + + // step; + var query = { + range: { from: time({ seconds: start }), to: time({ seconds: end }) }, + targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], + interval: '60s', + }; + var response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [ + { + metric: { __name__: 'test', job: 'testjob', series: 'series 1' }, + values: [[start + step * 1, '3846'], [start + step * 3, '3847'], [end - step * 1, '3848']], + }, + { + metric: { __name__: 'test', job: 'testjob', series: 'series 2' }, + values: [[start + step * 2, '4846']], + }, + ], + }, + }, + }; + beforeEach(async () => { + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + + await ctx.ds.query(query).then(function(data) { + results = data; + }); + }); + it('should be same length', function() { + expect(results.data.length).toBe(2); + expect(results.data[0].datapoints.length).toBe((end - start) / step + 1); + expect(results.data[1].datapoints.length).toBe((end - start) / step + 1); + }); + it('should fill null until first datapoint in response', function() { + expect(results.data[0].datapoints[0][1]).toBe(start * 1000); + expect(results.data[0].datapoints[0][0]).toBe(null); + expect(results.data[0].datapoints[1][1]).toBe((start + step * 1) * 1000); + expect(results.data[0].datapoints[1][0]).toBe(3846); + }); + it('should fill null after last datapoint in response', function() { + var length = (end - start) / step + 1; + expect(results.data[0].datapoints[length - 2][1]).toBe((end - step * 1) * 1000); + expect(results.data[0].datapoints[length - 2][0]).toBe(3848); + expect(results.data[0].datapoints[length - 1][1]).toBe(end * 1000); + expect(results.data[0].datapoints[length - 1][0]).toBe(null); + }); + it('should fill null at gap between series', function() { + expect(results.data[0].datapoints[2][1]).toBe((start + step * 2) * 1000); + expect(results.data[0].datapoints[2][0]).toBe(null); + expect(results.data[1].datapoints[1][1]).toBe((start + step * 1) * 1000); + expect(results.data[1].datapoints[1][0]).toBe(null); + expect(results.data[1].datapoints[3][1]).toBe((start + step * 3) * 1000); + expect(results.data[1].datapoints[3][0]).toBe(null); + }); + }); + describe('When querying prometheus with one target and instant = true', function() { + var results; + var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123'; + var query = { + range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) }, + targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }], + interval: '60s', + }; + var response = { + status: 'success', + data: { + data: { + resultType: 'vector', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + value: [123, '3846'], + }, + ], + }, + }, + }; + beforeEach(async () => { + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + + await ctx.ds.query(query).then(function(data) { + results = data; + }); + }); + it('should generate the correct query', function() { + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should return series list', function() { + expect(results.data.length).toBe(1); + expect(results.data[0].target).toBe('test{job="testjob"}'); + }); + }); + describe('When performing annotationQuery', function() { + var results; + // var urlExpected = + // 'proxied/api/v1/query_range?query=' + + // encodeURIComponent('ALERTS{alertstate="firing"}') + + // '&start=60&end=180&step=60'; + var options = { + annotation: { + expr: 'ALERTS{alertstate="firing"}', + tagKeys: 'job', + titleFormat: '{{alertname}}', + textFormat: '{{instance}}', + }, + range: { + from: time({ seconds: 63 }), + to: time({ seconds: 123 }), + }, + }; + var response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [ + { + metric: { + __name__: 'ALERTS', + alertname: 'InstanceDown', + alertstate: 'firing', + instance: 'testinstance', + job: 'testjob', + }, + values: [[123, '1']], + }, + ], + }, + }, + }; + beforeEach(async () => { + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + + await ctx.ds.annotationQuery(options).then(function(data) { + results = data; + }); + }); + it('should return annotation list', function() { + // ctx.$rootScope.$apply(); + expect(results.length).toBe(1); + expect(results[0].tags).toContain('testjob'); + expect(results[0].title).toBe('InstanceDown'); + expect(results[0].text).toBe('testinstance'); + expect(results[0].time).toBe(123 * 1000); + }); + }); + + describe('When resultFormat is table and instant = true', function() { + var results; + var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123'; + var query = { + range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) }, + targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }], + interval: '60s', + }; + var response = { + status: 'success', + data: { + data: { + resultType: 'vector', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + value: [123, '3846'], + }, + ], + }, + }, + }; + + beforeEach(async () => { + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query).then(function(data) { + results = data; + }); + }); + + it('should return result', () => { + expect(results).not.toBe(null); + }); + }); + + describe('The "step" query parameter', function() { + var response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [], + }, + }, + }; + + it('should be min interval when greater than auto interval', async () => { + let query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'test', + interval: '10s', + }, + ], + interval: '5s', + }; + let urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=10'; + + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + + it('step should never go below 1', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [{ expr: 'test' }], + interval: '100ms', + }; + var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=1'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + + it('should be auto interval when greater than min interval', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'test', + interval: '5s', + }, + ], + interval: '10s', + }; + var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=10'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should result in querying fewer than 11000 data points', async () => { + var query = { + // 6 hour range + range: { from: time({ hours: 1 }), to: time({ hours: 7 }) }, + targets: [{ expr: 'test' }], + interval: '1s', + }; + var end = 7 * 60 * 60; + var start = 60 * 60; + var urlExpected = 'proxied/api/v1/query_range?query=test&start=' + start + '&end=' + end + '&step=2'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should not apply min interval when interval * intervalFactor greater', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'test', + interval: '10s', + intervalFactor: 10, + }, + ], + interval: '5s', + }; + // times get rounded up to interval + var urlExpected = 'proxied/api/v1/query_range?query=test&start=50&end=450&step=50'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should apply min interval when interval * intervalFactor smaller', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'test', + interval: '15s', + intervalFactor: 2, + }, + ], + interval: '5s', + }; + var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=60&end=420&step=15'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should apply intervalFactor to auto interval when greater', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'test', + interval: '5s', + intervalFactor: 10, + }, + ], + interval: '10s', + }; + // times get aligned to interval + var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=0&end=500&step=100'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should not not be affected by the 11000 data points limit when large enough', async () => { + var query = { + // 1 week range + range: { from: time({}), to: time({ hours: 7 * 24 }) }, + targets: [ + { + expr: 'test', + intervalFactor: 10, + }, + ], + interval: '10s', + }; + var end = 7 * 24 * 60 * 60; + var start = 0; + var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=' + start + '&end=' + end + '&step=100'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should be determined by the 11000 data points limit when too small', async () => { + var query = { + // 1 week range + range: { from: time({}), to: time({ hours: 7 * 24 }) }, + targets: [ + { + expr: 'test', + intervalFactor: 10, + }, + ], + interval: '5s', + }; + var end = 7 * 24 * 60 * 60; + var start = 0; + var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=' + start + '&end=' + end + '&step=60'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + }); + + describe('The __interval and __interval_ms template variables', function() { + var response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [], + }, + }, + }; + + it('should be unchanged when auto interval is greater than min interval', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + interval: '5s', + }, + ], + interval: '10s', + scopedVars: { + __interval: { text: '10s', value: '10s' }, + __interval_ms: { text: 10 * 1000, value: 10 * 1000 }, + }, + }; + var urlExpected = + 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[10s])') + '&start=60&end=420&step=10'; + + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(query.scopedVars.__interval.text).toBe('10s'); + expect(query.scopedVars.__interval.value).toBe('10s'); + expect(query.scopedVars.__interval_ms.text).toBe(10 * 1000); + expect(query.scopedVars.__interval_ms.value).toBe(10 * 1000); + }); + it('should be min interval when it is greater than auto interval', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + interval: '10s', + }, + ], + interval: '5s', + scopedVars: { + __interval: { text: '5s', value: '5s' }, + __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, + }, + }; + var urlExpected = + 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[10s])') + '&start=60&end=420&step=10'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(query.scopedVars.__interval.text).toBe('5s'); + expect(query.scopedVars.__interval.value).toBe('5s'); + expect(query.scopedVars.__interval_ms.text).toBe(5 * 1000); + expect(query.scopedVars.__interval_ms.value).toBe(5 * 1000); + }); + it('should account for intervalFactor', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + interval: '5s', + intervalFactor: 10, + }, + ], + interval: '10s', + scopedVars: { + __interval: { text: '10s', value: '10s' }, + __interval_ms: { text: 10 * 1000, value: 10 * 1000 }, + }, + }; + var urlExpected = + 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[100s])') + '&start=0&end=500&step=100'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(query.scopedVars.__interval.text).toBe('10s'); + expect(query.scopedVars.__interval.value).toBe('10s'); + expect(query.scopedVars.__interval_ms.text).toBe(10 * 1000); + expect(query.scopedVars.__interval_ms.value).toBe(10 * 1000); + }); + it('should be interval * intervalFactor when greater than min interval', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + interval: '10s', + intervalFactor: 10, + }, + ], + interval: '5s', + scopedVars: { + __interval: { text: '5s', value: '5s' }, + __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, + }, + }; + var urlExpected = + 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[50s])') + '&start=50&end=450&step=50'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(query.scopedVars.__interval.text).toBe('5s'); + expect(query.scopedVars.__interval.value).toBe('5s'); + expect(query.scopedVars.__interval_ms.text).toBe(5 * 1000); + expect(query.scopedVars.__interval_ms.value).toBe(5 * 1000); + }); + it('should be min interval when greater than interval * intervalFactor', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + interval: '15s', + intervalFactor: 2, + }, + ], + interval: '5s', + scopedVars: { + __interval: { text: '5s', value: '5s' }, + __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, + }, + }; + var urlExpected = + 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[15s])') + '&start=60&end=420&step=15'; + + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(query.scopedVars.__interval.text).toBe('5s'); + expect(query.scopedVars.__interval.value).toBe('5s'); + expect(query.scopedVars.__interval_ms.text).toBe(5 * 1000); + expect(query.scopedVars.__interval_ms.value).toBe(5 * 1000); + }); + it('should be determined by the 11000 data points limit, accounting for intervalFactor', async () => { + var query = { + // 1 week range + range: { from: time({}), to: time({ hours: 7 * 24 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + intervalFactor: 10, + }, + ], + interval: '5s', + scopedVars: { + __interval: { text: '5s', value: '5s' }, + __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, + }, + }; + var end = 7 * 24 * 60 * 60; + var start = 0; + var urlExpected = + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[60s])') + + '&start=' + + start + + '&end=' + + end + + '&step=60'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(query.scopedVars.__interval.text).toBe('5s'); + expect(query.scopedVars.__interval.value).toBe('5s'); + expect(query.scopedVars.__interval_ms.text).toBe(5 * 1000); + expect(query.scopedVars.__interval_ms.value).toBe(5 * 1000); + }); + }); +}); + +describe('PrometheusDatasource for POST', function() { + // var ctx = new helpers.ServiceTestContext(); + let instanceSettings = { + url: 'proxied', + directUrl: 'direct', + user: 'test', + password: 'mupp', + jsonData: { httpMethod: 'POST' }, + }; + + // beforeEach(angularMocks.module('grafana.core')); + // beforeEach(angularMocks.module('grafana.services')); + // beforeEach(ctx.providePhase(['timeSrv'])); + + // beforeEach( + // // angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { + // // ctx.$q = $q; + // // ctx.$httpBackend = $httpBackend; + // // ctx.$rootScope = $rootScope; + // // ctx.ds = $injector.instantiate(PrometheusDatasource, { instanceSettings: instanceSettings }); + // // $httpBackend.when('GET', /\.html$/).respond(''); + // // }) + // ); + + describe('When querying prometheus with one target using query editor target spec', function() { + var results; + var urlExpected = 'proxied/api/v1/query_range'; + var dataExpected = { + query: 'test{job="testjob"}', + start: 1 * 60, + end: 3 * 60, + step: 60, + }; + var query = { + range: { from: time({ minutes: 1, seconds: 3 }), to: time({ minutes: 2, seconds: 3 }) }, + targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], + interval: '60s', + }; + var response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + values: [[2 * 60, '3846']], + }, + ], + }, + }, + }; + beforeEach(async () => { + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query).then(function(data) { + results = data; + }); + }); + it('should generate the correct query', function() { + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('POST'); + expect(res.url).toBe(urlExpected); + expect(res.data).toEqual(dataExpected); + }); + it('should return series list', function() { + expect(results.data.length).toBe(1); + expect(results.data[0].target).toBe('test{job="testjob"}'); + }); + }); +}); From e4c2476f3c898879fa6be89c18e1ea325bf88c13 Mon Sep 17 00:00:00 2001 From: Tobias Skarhed Date: Tue, 31 Jul 2018 09:35:08 +0200 Subject: [PATCH 2/6] Weird execution order for the tests... --- .../datasource/prometheus/datasource.ts | 7 +++++- .../prometheus/result_transformer.ts | 7 +++++- .../prometheus/specs/_datasource.jest.ts | 25 +++---------------- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 75a946d6f36..6801a9a1d59 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -175,8 +175,12 @@ export class PrometheusDatasource { responseIndex: index, refId: activeTargets[index].refId, }; - + console.log('format: ' + transformerOptions.format); + console.log('resultType: ' + response.data.data.resultType); + console.log('legendFormat: ' + transformerOptions.legendFormat); + // console.log(result); this.resultTransformer.transform(result, response, transformerOptions); + // console.log(result); }); return { data: result }; @@ -233,6 +237,7 @@ export class PrometheusDatasource { if (start > end) { throw { message: 'Invalid time range' }; } + // console.log(query.expr); var url = '/api/v1/query_range'; var data = { diff --git a/public/app/plugins/datasource/prometheus/result_transformer.ts b/public/app/plugins/datasource/prometheus/result_transformer.ts index b6d8a32af5f..4b69cb98c54 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.ts @@ -6,7 +6,9 @@ export class ResultTransformer { transform(result: any, response: any, options: any) { let prometheusResult = response.data.data.result; - + console.log(prometheusResult); + // console.log(options); + // console.log(result); if (options.format === 'table') { result.push(this.transformMetricDataToTable(prometheusResult, options.responseListLength, options.refId)); } else if (options.format === 'heatmap') { @@ -26,6 +28,7 @@ export class ResultTransformer { } } } + // console.log(result); } transformMetricData(metricData, options, start, end) { @@ -137,6 +140,7 @@ export class ResultTransformer { if (!label || label === '{}') { label = options.query; } + console.log(label); return label; } @@ -156,6 +160,7 @@ export class ResultTransformer { var labelPart = _.map(_.toPairs(labelData), function(label) { return label[0] + '="' + label[1] + '"'; }).join(','); + console.log(metricName); return metricName + '{' + labelPart + '}'; } diff --git a/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts b/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts index 384abc8f902..34f78585d76 100644 --- a/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts +++ b/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts @@ -21,23 +21,7 @@ let backendSrv = { }; let templateSrv = { - replace: (target, scopedVars, format) => { - if (!target) { - return target; - } - let variable, value, fmt; - - return target.replace(scopedVars, (match, var1, var2, fmt2, var3, fmt3) => { - variable = this.index[var1 || var2 || var3]; - fmt = fmt2 || fmt3 || format; - if (scopedVars) { - value = scopedVars[var1 || var2 || var3]; - if (value) { - return this.formatValue(value.value, fmt, variable); - } - } - }); - }, + replace: jest.fn(str => str), }; let timeSrv = { @@ -63,10 +47,7 @@ describe('PrometheusDatasource', function() { // }) // ); - beforeEach(() => { - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - }); - describe('When querying prometheus with one target using query editor target spec', function() { + describe('When querying prometheus with one target using query editor target spec', async () => { var results; var query = { range: { from: time({ seconds: 63 }), to: time({ seconds: 183 }) }, @@ -106,7 +87,7 @@ describe('PrometheusDatasource', function() { expect(res.method).toBe('GET'); expect(res.url).toBe(urlExpected); }); - it('should return series list', function() { + it('should return series list', async () => { expect(results.data.length).toBe(1); expect(results.data[0].target).toBe('test{job="testjob"}'); }); From d6158bc2935ec396f45114d736e684bb3a522c6b Mon Sep 17 00:00:00 2001 From: Tobias Skarhed Date: Wed, 1 Aug 2018 09:30:26 +0200 Subject: [PATCH 3/6] All tests passing --- .../datasource/prometheus/datasource.ts | 6 - .../prometheus/result_transformer.ts | 7 +- .../prometheus/specs/_datasource.jest.ts | 333 +++++---- .../prometheus/specs/datasource_specs.ts | 683 ------------------ 4 files changed, 196 insertions(+), 833 deletions(-) delete mode 100644 public/app/plugins/datasource/prometheus/specs/datasource_specs.ts diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 6801a9a1d59..ac8d774db59 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -175,12 +175,7 @@ export class PrometheusDatasource { responseIndex: index, refId: activeTargets[index].refId, }; - console.log('format: ' + transformerOptions.format); - console.log('resultType: ' + response.data.data.resultType); - console.log('legendFormat: ' + transformerOptions.legendFormat); - // console.log(result); this.resultTransformer.transform(result, response, transformerOptions); - // console.log(result); }); return { data: result }; @@ -237,7 +232,6 @@ export class PrometheusDatasource { if (start > end) { throw { message: 'Invalid time range' }; } - // console.log(query.expr); var url = '/api/v1/query_range'; var data = { diff --git a/public/app/plugins/datasource/prometheus/result_transformer.ts b/public/app/plugins/datasource/prometheus/result_transformer.ts index 4b69cb98c54..b6d8a32af5f 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.ts @@ -6,9 +6,7 @@ export class ResultTransformer { transform(result: any, response: any, options: any) { let prometheusResult = response.data.data.result; - console.log(prometheusResult); - // console.log(options); - // console.log(result); + if (options.format === 'table') { result.push(this.transformMetricDataToTable(prometheusResult, options.responseListLength, options.refId)); } else if (options.format === 'heatmap') { @@ -28,7 +26,6 @@ export class ResultTransformer { } } } - // console.log(result); } transformMetricData(metricData, options, start, end) { @@ -140,7 +137,6 @@ export class ResultTransformer { if (!label || label === '{}') { label = options.query; } - console.log(label); return label; } @@ -160,7 +156,6 @@ export class ResultTransformer { var labelPart = _.map(_.toPairs(labelData), function(label) { return label[0] + '="' + label[1] + '"'; }).join(','); - console.log(metricName); return metricName + '{' + labelPart + '}'; } diff --git a/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts b/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts index 34f78585d76..2deab13a101 100644 --- a/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts +++ b/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts @@ -1,6 +1,7 @@ import moment from 'moment'; import { PrometheusDatasource } from '../datasource'; import $q from 'q'; +import { angularMocks } from 'test/lib/common'; const SECOND = 1000; const MINUTE = 60 * SECOND; @@ -57,32 +58,31 @@ describe('PrometheusDatasource', function() { // Interval alignment with step var urlExpected = 'proxied/api/v1/query_range?query=' + encodeURIComponent('test{job="testjob"}') + '&start=60&end=240&step=60'; - var response = { - data: { - status: 'success', - data: { - resultType: 'matrix', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - values: [[60, '3846']], - }, - ], - }, - }, - }; + beforeEach(async () => { - // ctx.$httpBackend.expect('GET', urlExpected).respond(response); + let response = { + data: { + status: 'success', + data: { + resultType: 'matrix', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + values: [[60, '3846']], + }, + ], + }, + }, + }; backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); await ctx.ds.query(query).then(function(data) { results = data; }); - // ctx.$httpBackend.flush(); }); + it('should generate the correct query', function() { - // ctx.$httpBackend.verifyNoOutstandingExpectation(); let res = backendSrv.datasourceRequest.mock.calls[0][0]; expect(res.method).toBe('GET'); expect(res.url).toBe(urlExpected); @@ -97,39 +97,33 @@ describe('PrometheusDatasource', function() { var start = 60; var end = 360; var step = 60; - // var urlExpected = - // 'proxied/api/v1/query_range?query=' + - // encodeURIComponent('test{job="testjob"}') + - // '&start=' + - // start + - // '&end=' + - // end + - // '&step=' + - // step; + var query = { range: { from: time({ seconds: start }), to: time({ seconds: end }) }, targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], interval: '60s', }; - var response = { - status: 'success', - data: { - data: { - resultType: 'matrix', - result: [ - { - metric: { __name__: 'test', job: 'testjob', series: 'series 1' }, - values: [[start + step * 1, '3846'], [start + step * 3, '3847'], [end - step * 1, '3848']], - }, - { - metric: { __name__: 'test', job: 'testjob', series: 'series 2' }, - values: [[start + step * 2, '4846']], - }, - ], - }, - }, - }; + beforeEach(async () => { + let response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [ + { + metric: { __name__: 'test', job: 'testjob', series: 'series 1' }, + values: [[start + step * 1, '3846'], [start + step * 3, '3847'], [end - step * 1, '3848']], + }, + { + metric: { __name__: 'test', job: 'testjob', series: 'series 2' }, + values: [[start + step * 2, '4846']], + }, + ], + }, + }, + }; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); @@ -137,11 +131,13 @@ describe('PrometheusDatasource', function() { results = data; }); }); + it('should be same length', function() { expect(results.data.length).toBe(2); expect(results.data[0].datapoints.length).toBe((end - start) / step + 1); expect(results.data[1].datapoints.length).toBe((end - start) / step + 1); }); + it('should fill null until first datapoint in response', function() { expect(results.data[0].datapoints[0][1]).toBe(start * 1000); expect(results.data[0].datapoints[0][0]).toBe(null); @@ -172,21 +168,23 @@ describe('PrometheusDatasource', function() { targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }], interval: '60s', }; - var response = { - status: 'success', - data: { - data: { - resultType: 'vector', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - value: [123, '3846'], - }, - ], - }, - }, - }; + beforeEach(async () => { + let response = { + status: 'success', + data: { + data: { + resultType: 'vector', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + value: [123, '3846'], + }, + ], + }, + }, + }; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); @@ -206,10 +204,7 @@ describe('PrometheusDatasource', function() { }); describe('When performing annotationQuery', function() { var results; - // var urlExpected = - // 'proxied/api/v1/query_range?query=' + - // encodeURIComponent('ALERTS{alertstate="firing"}') + - // '&start=60&end=180&step=60'; + var options = { annotation: { expr: 'ALERTS{alertstate="firing"}', @@ -222,27 +217,29 @@ describe('PrometheusDatasource', function() { to: time({ seconds: 123 }), }, }; - var response = { - status: 'success', - data: { - data: { - resultType: 'matrix', - result: [ - { - metric: { - __name__: 'ALERTS', - alertname: 'InstanceDown', - alertstate: 'firing', - instance: 'testinstance', - job: 'testjob', - }, - values: [[123, '1']], - }, - ], - }, - }, - }; + beforeEach(async () => { + let response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [ + { + metric: { + __name__: 'ALERTS', + alertname: 'InstanceDown', + alertstate: 'firing', + instance: 'testinstance', + job: 'testjob', + }, + values: [[123, '1']], + }, + ], + }, + }, + }; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); @@ -262,28 +259,29 @@ describe('PrometheusDatasource', function() { describe('When resultFormat is table and instant = true', function() { var results; - var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123'; + // var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123'; var query = { range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) }, targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }], interval: '60s', }; - var response = { - status: 'success', - data: { - data: { - resultType: 'vector', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - value: [123, '3846'], - }, - ], - }, - }, - }; beforeEach(async () => { + let response = { + status: 'success', + data: { + data: { + resultType: 'vector', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + value: [123, '3846'], + }, + ], + }, + }, + }; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); await ctx.ds.query(query).then(function(data) { @@ -520,9 +518,13 @@ describe('PrometheusDatasource', function() { __interval_ms: { text: 10 * 1000, value: 10 * 1000 }, }, }; - var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[10s])') + '&start=60&end=420&step=10'; + var urlExpected = + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[$__interval])') + + '&start=60&end=420&step=10'; + + templateSrv.replace = jest.fn(str => str); backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); await ctx.ds.query(query); @@ -530,10 +532,16 @@ describe('PrometheusDatasource', function() { expect(res.method).toBe('GET'); expect(res.url).toBe(urlExpected); - expect(query.scopedVars.__interval.text).toBe('10s'); - expect(query.scopedVars.__interval.value).toBe('10s'); - expect(query.scopedVars.__interval_ms.text).toBe(10 * 1000); - expect(query.scopedVars.__interval_ms.value).toBe(10 * 1000); + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '10s', + value: '10s', + }, + __interval_ms: { + text: 10000, + value: 10000, + }, + }); }); it('should be min interval when it is greater than auto interval', async () => { var query = { @@ -552,18 +560,27 @@ describe('PrometheusDatasource', function() { }, }; var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[10s])') + '&start=60&end=420&step=10'; + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[$__interval])') + + '&start=60&end=420&step=10'; backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + templateSrv.replace = jest.fn(str => str); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); await ctx.ds.query(query); let res = backendSrv.datasourceRequest.mock.calls[0][0]; expect(res.method).toBe('GET'); expect(res.url).toBe(urlExpected); - expect(query.scopedVars.__interval.text).toBe('5s'); - expect(query.scopedVars.__interval.value).toBe('5s'); - expect(query.scopedVars.__interval_ms.text).toBe(5 * 1000); - expect(query.scopedVars.__interval_ms.value).toBe(5 * 1000); + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '5s', + value: '5s', + }, + __interval_ms: { + text: 5000, + value: 5000, + }, + }); }); it('should account for intervalFactor', async () => { var query = { @@ -583,14 +600,28 @@ describe('PrometheusDatasource', function() { }, }; var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[100s])') + '&start=0&end=500&step=100'; + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[$__interval])') + + '&start=0&end=500&step=100'; backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + templateSrv.replace = jest.fn(str => str); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); await ctx.ds.query(query); let res = backendSrv.datasourceRequest.mock.calls[0][0]; expect(res.method).toBe('GET'); expect(res.url).toBe(urlExpected); + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '10s', + value: '10s', + }, + __interval_ms: { + text: 10000, + value: 10000, + }, + }); + expect(query.scopedVars.__interval.text).toBe('10s'); expect(query.scopedVars.__interval.value).toBe('10s'); expect(query.scopedVars.__interval_ms.text).toBe(10 * 1000); @@ -614,7 +645,11 @@ describe('PrometheusDatasource', function() { }, }; var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[50s])') + '&start=50&end=450&step=50'; + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[$__interval])') + + '&start=50&end=450&step=50'; + + templateSrv.replace = jest.fn(str => str); backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); await ctx.ds.query(query); @@ -622,10 +657,16 @@ describe('PrometheusDatasource', function() { expect(res.method).toBe('GET'); expect(res.url).toBe(urlExpected); - expect(query.scopedVars.__interval.text).toBe('5s'); - expect(query.scopedVars.__interval.value).toBe('5s'); - expect(query.scopedVars.__interval_ms.text).toBe(5 * 1000); - expect(query.scopedVars.__interval_ms.value).toBe(5 * 1000); + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '5s', + value: '5s', + }, + __interval_ms: { + text: 5000, + value: 5000, + }, + }); }); it('should be min interval when greater than interval * intervalFactor', async () => { var query = { @@ -645,7 +686,9 @@ describe('PrometheusDatasource', function() { }, }; var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[15s])') + '&start=60&end=420&step=15'; + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[$__interval])') + + '&start=60&end=420&step=15'; backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); @@ -654,10 +697,16 @@ describe('PrometheusDatasource', function() { expect(res.method).toBe('GET'); expect(res.url).toBe(urlExpected); - expect(query.scopedVars.__interval.text).toBe('5s'); - expect(query.scopedVars.__interval.value).toBe('5s'); - expect(query.scopedVars.__interval_ms.text).toBe(5 * 1000); - expect(query.scopedVars.__interval_ms.value).toBe(5 * 1000); + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '5s', + value: '5s', + }, + __interval_ms: { + text: 5000, + value: 5000, + }, + }); }); it('should be determined by the 11000 data points limit, accounting for intervalFactor', async () => { var query = { @@ -679,23 +728,30 @@ describe('PrometheusDatasource', function() { var start = 0; var urlExpected = 'proxied/api/v1/query_range?query=' + - encodeURIComponent('rate(test[60s])') + + encodeURIComponent('rate(test[$__interval])') + '&start=' + start + '&end=' + end + '&step=60'; backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + templateSrv.replace = jest.fn(str => str); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); await ctx.ds.query(query); let res = backendSrv.datasourceRequest.mock.calls[0][0]; expect(res.method).toBe('GET'); expect(res.url).toBe(urlExpected); - expect(query.scopedVars.__interval.text).toBe('5s'); - expect(query.scopedVars.__interval.value).toBe('5s'); - expect(query.scopedVars.__interval_ms.text).toBe(5 * 1000); - expect(query.scopedVars.__interval_ms.value).toBe(5 * 1000); + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '5s', + value: '5s', + }, + __interval_ms: { + text: 5000, + value: 5000, + }, + }); }); }); }); @@ -738,21 +794,22 @@ describe('PrometheusDatasource for POST', function() { targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], interval: '60s', }; - var response = { - status: 'success', - data: { - data: { - resultType: 'matrix', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - values: [[2 * 60, '3846']], - }, - ], - }, - }, - }; + beforeEach(async () => { + let response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + values: [[2 * 60, '3846']], + }, + ], + }, + }, + }; backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); await ctx.ds.query(query).then(function(data) { diff --git a/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts b/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts deleted file mode 100644 index c5da671b757..00000000000 --- a/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts +++ /dev/null @@ -1,683 +0,0 @@ -import { describe, beforeEach, it, expect, angularMocks } from 'test/lib/common'; -import moment from 'moment'; -import $ from 'jquery'; -import helpers from 'test/specs/helpers'; -import { PrometheusDatasource } from '../datasource'; - -const SECOND = 1000; -const MINUTE = 60 * SECOND; -const HOUR = 60 * MINUTE; - -const time = ({ hours = 0, seconds = 0, minutes = 0 }) => moment(hours * HOUR + minutes * MINUTE + seconds * SECOND); - -describe('PrometheusDatasource', function() { - var ctx = new helpers.ServiceTestContext(); - var instanceSettings = { - url: 'proxied', - directUrl: 'direct', - user: 'test', - password: 'mupp', - jsonData: { httpMethod: 'GET' }, - }; - - beforeEach(angularMocks.module('grafana.core')); - beforeEach(angularMocks.module('grafana.services')); - beforeEach(ctx.providePhase(['timeSrv'])); - - beforeEach( - angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { - ctx.$q = $q; - ctx.$httpBackend = $httpBackend; - ctx.$rootScope = $rootScope; - ctx.ds = $injector.instantiate(PrometheusDatasource, { - instanceSettings: instanceSettings, - }); - $httpBackend.when('GET', /\.html$/).respond(''); - }) - ); - describe('When querying prometheus with one target using query editor target spec', function() { - var results; - var query = { - range: { from: time({ seconds: 63 }), to: time({ seconds: 183 }) }, - targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], - interval: '60s', - }; - // Interval alignment with step - var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('test{job="testjob"}') + '&start=60&end=240&step=60'; - var response = { - status: 'success', - data: { - resultType: 'matrix', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - values: [[60, '3846']], - }, - ], - }, - }; - beforeEach(function() { - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query).then(function(data) { - results = data; - }); - ctx.$httpBackend.flush(); - }); - it('should generate the correct query', function() { - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - it('should return series list', function() { - expect(results.data.length).to.be(1); - expect(results.data[0].target).to.be('test{job="testjob"}'); - }); - }); - describe('When querying prometheus with one target which return multiple series', function() { - var results; - var start = 60; - var end = 360; - var step = 60; - var urlExpected = - 'proxied/api/v1/query_range?query=' + - encodeURIComponent('test{job="testjob"}') + - '&start=' + - start + - '&end=' + - end + - '&step=' + - step; - var query = { - range: { from: time({ seconds: start }), to: time({ seconds: end }) }, - targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], - interval: '60s', - }; - var response = { - status: 'success', - data: { - resultType: 'matrix', - result: [ - { - metric: { __name__: 'test', job: 'testjob', series: 'series 1' }, - values: [[start + step * 1, '3846'], [start + step * 3, '3847'], [end - step * 1, '3848']], - }, - { - metric: { __name__: 'test', job: 'testjob', series: 'series 2' }, - values: [[start + step * 2, '4846']], - }, - ], - }, - }; - beforeEach(function() { - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query).then(function(data) { - results = data; - }); - ctx.$httpBackend.flush(); - }); - it('should be same length', function() { - expect(results.data.length).to.be(2); - expect(results.data[0].datapoints.length).to.be((end - start) / step + 1); - expect(results.data[1].datapoints.length).to.be((end - start) / step + 1); - }); - it('should fill null until first datapoint in response', function() { - expect(results.data[0].datapoints[0][1]).to.be(start * 1000); - expect(results.data[0].datapoints[0][0]).to.be(null); - expect(results.data[0].datapoints[1][1]).to.be((start + step * 1) * 1000); - expect(results.data[0].datapoints[1][0]).to.be(3846); - }); - it('should fill null after last datapoint in response', function() { - var length = (end - start) / step + 1; - expect(results.data[0].datapoints[length - 2][1]).to.be((end - step * 1) * 1000); - expect(results.data[0].datapoints[length - 2][0]).to.be(3848); - expect(results.data[0].datapoints[length - 1][1]).to.be(end * 1000); - expect(results.data[0].datapoints[length - 1][0]).to.be(null); - }); - it('should fill null at gap between series', function() { - expect(results.data[0].datapoints[2][1]).to.be((start + step * 2) * 1000); - expect(results.data[0].datapoints[2][0]).to.be(null); - expect(results.data[1].datapoints[1][1]).to.be((start + step * 1) * 1000); - expect(results.data[1].datapoints[1][0]).to.be(null); - expect(results.data[1].datapoints[3][1]).to.be((start + step * 3) * 1000); - expect(results.data[1].datapoints[3][0]).to.be(null); - }); - }); - describe('When querying prometheus with one target and instant = true', function() { - var results; - var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123'; - var query = { - range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) }, - targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }], - interval: '60s', - }; - var response = { - status: 'success', - data: { - resultType: 'vector', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - value: [123, '3846'], - }, - ], - }, - }; - beforeEach(function() { - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query).then(function(data) { - results = data; - }); - ctx.$httpBackend.flush(); - }); - it('should generate the correct query', function() { - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - it('should return series list', function() { - expect(results.data.length).to.be(1); - expect(results.data[0].target).to.be('test{job="testjob"}'); - }); - }); - describe('When performing annotationQuery', function() { - var results; - var urlExpected = - 'proxied/api/v1/query_range?query=' + - encodeURIComponent('ALERTS{alertstate="firing"}') + - '&start=60&end=180&step=60'; - var options = { - annotation: { - expr: 'ALERTS{alertstate="firing"}', - tagKeys: 'job', - titleFormat: '{{alertname}}', - textFormat: '{{instance}}', - }, - range: { - from: time({ seconds: 63 }), - to: time({ seconds: 123 }), - }, - }; - var response = { - status: 'success', - data: { - resultType: 'matrix', - result: [ - { - metric: { - __name__: 'ALERTS', - alertname: 'InstanceDown', - alertstate: 'firing', - instance: 'testinstance', - job: 'testjob', - }, - values: [[123, '1']], - }, - ], - }, - }; - beforeEach(function() { - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.annotationQuery(options).then(function(data) { - results = data; - }); - ctx.$httpBackend.flush(); - }); - it('should return annotation list', function() { - ctx.$rootScope.$apply(); - expect(results.length).to.be(1); - expect(results[0].tags).to.contain('testjob'); - expect(results[0].title).to.be('InstanceDown'); - expect(results[0].text).to.be('testinstance'); - expect(results[0].time).to.be(123 * 1000); - }); - }); - - describe('When resultFormat is table and instant = true', function() { - var results; - var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123'; - var query = { - range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) }, - targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }], - interval: '60s', - }; - var response = { - status: 'success', - data: { - resultType: 'vector', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - value: [123, '3846'], - }, - ], - }, - }; - - beforeEach(function() { - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query).then(function(data) { - results = data; - }); - ctx.$httpBackend.flush(); - }); - - it('should return result', () => { - expect(results).not.to.be(null); - }); - }); - - describe('The "step" query parameter', function() { - var response = { - status: 'success', - data: { - resultType: 'matrix', - result: [], - }, - }; - - it('should be min interval when greater than auto interval', function() { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'test', - interval: '10s', - }, - ], - interval: '5s', - }; - var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=10'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - - it('step should never go below 1', function() { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [{ expr: 'test' }], - interval: '100ms', - }; - var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=1'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - - it('should be auto interval when greater than min interval', function() { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'test', - interval: '5s', - }, - ], - interval: '10s', - }; - var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=10'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - it('should result in querying fewer than 11000 data points', function() { - var query = { - // 6 hour range - range: { from: time({ hours: 1 }), to: time({ hours: 7 }) }, - targets: [{ expr: 'test' }], - interval: '1s', - }; - var end = 7 * 60 * 60; - var start = 60 * 60; - var urlExpected = 'proxied/api/v1/query_range?query=test&start=' + start + '&end=' + end + '&step=2'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - it('should not apply min interval when interval * intervalFactor greater', function() { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'test', - interval: '10s', - intervalFactor: 10, - }, - ], - interval: '5s', - }; - // times get rounded up to interval - var urlExpected = 'proxied/api/v1/query_range?query=test&start=50&end=450&step=50'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - it('should apply min interval when interval * intervalFactor smaller', function() { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'test', - interval: '15s', - intervalFactor: 2, - }, - ], - interval: '5s', - }; - var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=60&end=420&step=15'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - it('should apply intervalFactor to auto interval when greater', function() { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'test', - interval: '5s', - intervalFactor: 10, - }, - ], - interval: '10s', - }; - // times get aligned to interval - var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=0&end=500&step=100'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - it('should not not be affected by the 11000 data points limit when large enough', function() { - var query = { - // 1 week range - range: { from: time({}), to: time({ hours: 7 * 24 }) }, - targets: [ - { - expr: 'test', - intervalFactor: 10, - }, - ], - interval: '10s', - }; - var end = 7 * 24 * 60 * 60; - var start = 0; - var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=' + start + '&end=' + end + '&step=100'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - it('should be determined by the 11000 data points limit when too small', function() { - var query = { - // 1 week range - range: { from: time({}), to: time({ hours: 7 * 24 }) }, - targets: [ - { - expr: 'test', - intervalFactor: 10, - }, - ], - interval: '5s', - }; - var end = 7 * 24 * 60 * 60; - var start = 0; - var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=' + start + '&end=' + end + '&step=60'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - }); - - describe('The __interval and __interval_ms template variables', function() { - var response = { - status: 'success', - data: { - resultType: 'matrix', - result: [], - }, - }; - - it('should be unchanged when auto interval is greater than min interval', function() { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - interval: '5s', - }, - ], - interval: '10s', - scopedVars: { - __interval: { text: '10s', value: '10s' }, - __interval_ms: { text: 10 * 1000, value: 10 * 1000 }, - }, - }; - var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[10s])') + '&start=60&end=420&step=10'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - - expect(query.scopedVars.__interval.text).to.be('10s'); - expect(query.scopedVars.__interval.value).to.be('10s'); - expect(query.scopedVars.__interval_ms.text).to.be(10 * 1000); - expect(query.scopedVars.__interval_ms.value).to.be(10 * 1000); - }); - it('should be min interval when it is greater than auto interval', function() { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - interval: '10s', - }, - ], - interval: '5s', - scopedVars: { - __interval: { text: '5s', value: '5s' }, - __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, - }, - }; - var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[10s])') + '&start=60&end=420&step=10'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - - expect(query.scopedVars.__interval.text).to.be('5s'); - expect(query.scopedVars.__interval.value).to.be('5s'); - expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000); - expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000); - }); - it('should account for intervalFactor', function() { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - interval: '5s', - intervalFactor: 10, - }, - ], - interval: '10s', - scopedVars: { - __interval: { text: '10s', value: '10s' }, - __interval_ms: { text: 10 * 1000, value: 10 * 1000 }, - }, - }; - var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[100s])') + '&start=0&end=500&step=100'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - - expect(query.scopedVars.__interval.text).to.be('10s'); - expect(query.scopedVars.__interval.value).to.be('10s'); - expect(query.scopedVars.__interval_ms.text).to.be(10 * 1000); - expect(query.scopedVars.__interval_ms.value).to.be(10 * 1000); - }); - it('should be interval * intervalFactor when greater than min interval', function() { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - interval: '10s', - intervalFactor: 10, - }, - ], - interval: '5s', - scopedVars: { - __interval: { text: '5s', value: '5s' }, - __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, - }, - }; - var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[50s])') + '&start=50&end=450&step=50'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - - expect(query.scopedVars.__interval.text).to.be('5s'); - expect(query.scopedVars.__interval.value).to.be('5s'); - expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000); - expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000); - }); - it('should be min interval when greater than interval * intervalFactor', function() { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - interval: '15s', - intervalFactor: 2, - }, - ], - interval: '5s', - scopedVars: { - __interval: { text: '5s', value: '5s' }, - __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, - }, - }; - var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[15s])') + '&start=60&end=420&step=15'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - - expect(query.scopedVars.__interval.text).to.be('5s'); - expect(query.scopedVars.__interval.value).to.be('5s'); - expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000); - expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000); - }); - it('should be determined by the 11000 data points limit, accounting for intervalFactor', function() { - var query = { - // 1 week range - range: { from: time({}), to: time({ hours: 7 * 24 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - intervalFactor: 10, - }, - ], - interval: '5s', - scopedVars: { - __interval: { text: '5s', value: '5s' }, - __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, - }, - }; - var end = 7 * 24 * 60 * 60; - var start = 0; - var urlExpected = - 'proxied/api/v1/query_range?query=' + - encodeURIComponent('rate(test[60s])') + - '&start=' + - start + - '&end=' + - end + - '&step=60'; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query); - ctx.$httpBackend.verifyNoOutstandingExpectation(); - - expect(query.scopedVars.__interval.text).to.be('5s'); - expect(query.scopedVars.__interval.value).to.be('5s'); - expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000); - expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000); - }); - }); -}); - -describe('PrometheusDatasource for POST', function() { - var ctx = new helpers.ServiceTestContext(); - var instanceSettings = { - url: 'proxied', - directUrl: 'direct', - user: 'test', - password: 'mupp', - jsonData: { httpMethod: 'POST' }, - }; - - beforeEach(angularMocks.module('grafana.core')); - beforeEach(angularMocks.module('grafana.services')); - beforeEach(ctx.providePhase(['timeSrv'])); - - beforeEach( - angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { - ctx.$q = $q; - ctx.$httpBackend = $httpBackend; - ctx.$rootScope = $rootScope; - ctx.ds = $injector.instantiate(PrometheusDatasource, { instanceSettings: instanceSettings }); - $httpBackend.when('GET', /\.html$/).respond(''); - }) - ); - - describe('When querying prometheus with one target using query editor target spec', function() { - var results; - var urlExpected = 'proxied/api/v1/query_range'; - var dataExpected = $.param({ - query: 'test{job="testjob"}', - start: 1 * 60, - end: 3 * 60, - step: 60, - }); - var query = { - range: { from: time({ minutes: 1, seconds: 3 }), to: time({ minutes: 2, seconds: 3 }) }, - targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], - interval: '60s', - }; - var response = { - status: 'success', - data: { - resultType: 'matrix', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - values: [[2 * 60, '3846']], - }, - ], - }, - }; - beforeEach(function() { - ctx.$httpBackend.expectPOST(urlExpected, dataExpected).respond(response); - ctx.ds.query(query).then(function(data) { - results = data; - }); - ctx.$httpBackend.flush(); - }); - it('should generate the correct query', function() { - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - it('should return series list', function() { - expect(results.data.length).to.be(1); - expect(results.data[0].target).to.be('test{job="testjob"}'); - }); - }); -}); From 790aadf8ef3544eb0c1007042525c7ad54f611e2 Mon Sep 17 00:00:00 2001 From: Tobias Skarhed Date: Wed, 1 Aug 2018 10:09:05 +0200 Subject: [PATCH 4/6] Remove angularMocks --- .../app/plugins/datasource/prometheus/specs/_datasource.jest.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts b/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts index 2deab13a101..efe2738cce9 100644 --- a/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts +++ b/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts @@ -1,7 +1,6 @@ import moment from 'moment'; import { PrometheusDatasource } from '../datasource'; import $q from 'q'; -import { angularMocks } from 'test/lib/common'; const SECOND = 1000; const MINUTE = 60 * SECOND; From af32bfebefcc02170fbaa4104ae2e5883b5c1ba8 Mon Sep 17 00:00:00 2001 From: Tobias Skarhed Date: Wed, 1 Aug 2018 14:26:29 +0200 Subject: [PATCH 5/6] Add all tests to one file --- .../prometheus/specs/_datasource.jest.ts | 829 ------------------ .../prometheus/specs/datasource.jest.ts | 794 +++++++++++++++++ 2 files changed, 794 insertions(+), 829 deletions(-) delete mode 100644 public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts diff --git a/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts b/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts deleted file mode 100644 index efe2738cce9..00000000000 --- a/public/app/plugins/datasource/prometheus/specs/_datasource.jest.ts +++ /dev/null @@ -1,829 +0,0 @@ -import moment from 'moment'; -import { PrometheusDatasource } from '../datasource'; -import $q from 'q'; - -const SECOND = 1000; -const MINUTE = 60 * SECOND; -const HOUR = 60 * MINUTE; - -const time = ({ hours = 0, seconds = 0, minutes = 0 }) => moment(hours * HOUR + minutes * MINUTE + seconds * SECOND); - -let ctx = {}; -let instanceSettings = { - url: 'proxied', - directUrl: 'direct', - user: 'test', - password: 'mupp', - jsonData: { httpMethod: 'GET' }, -}; -let backendSrv = { - datasourceRequest: jest.fn(), -}; - -let templateSrv = { - replace: jest.fn(str => str), -}; - -let timeSrv = { - timeRange: () => { - return { to: { diff: () => 2000 }, from: '' }; - }, -}; - -describe('PrometheusDatasource', function() { - // beforeEach(angularMocks.module('grafana.core')); - // beforeEach(angularMocks.module('grafana.services')); - // beforeEach(ctx.providePhase(['timeSrv'])); - - // beforeEach( - // angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { - // ctx.$q = $q; - // ctx.$httpBackend = $httpBackend; - // ctx.$rootScope = $rootScope; - // ctx.ds = $injector.instantiate(PrometheusDatasource, { - // instanceSettings: instanceSettings, - // }); - // $httpBackend.when('GET', /\.html$/).respond(''); - // }) - // ); - - describe('When querying prometheus with one target using query editor target spec', async () => { - var results; - var query = { - range: { from: time({ seconds: 63 }), to: time({ seconds: 183 }) }, - targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], - interval: '60s', - }; - // Interval alignment with step - var urlExpected = - 'proxied/api/v1/query_range?query=' + encodeURIComponent('test{job="testjob"}') + '&start=60&end=240&step=60'; - - beforeEach(async () => { - let response = { - data: { - status: 'success', - data: { - resultType: 'matrix', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - values: [[60, '3846']], - }, - ], - }, - }, - }; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - - await ctx.ds.query(query).then(function(data) { - results = data; - }); - }); - - it('should generate the correct query', function() { - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - }); - it('should return series list', async () => { - expect(results.data.length).toBe(1); - expect(results.data[0].target).toBe('test{job="testjob"}'); - }); - }); - describe('When querying prometheus with one target which return multiple series', function() { - var results; - var start = 60; - var end = 360; - var step = 60; - - var query = { - range: { from: time({ seconds: start }), to: time({ seconds: end }) }, - targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], - interval: '60s', - }; - - beforeEach(async () => { - let response = { - status: 'success', - data: { - data: { - resultType: 'matrix', - result: [ - { - metric: { __name__: 'test', job: 'testjob', series: 'series 1' }, - values: [[start + step * 1, '3846'], [start + step * 3, '3847'], [end - step * 1, '3848']], - }, - { - metric: { __name__: 'test', job: 'testjob', series: 'series 2' }, - values: [[start + step * 2, '4846']], - }, - ], - }, - }, - }; - - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - - await ctx.ds.query(query).then(function(data) { - results = data; - }); - }); - - it('should be same length', function() { - expect(results.data.length).toBe(2); - expect(results.data[0].datapoints.length).toBe((end - start) / step + 1); - expect(results.data[1].datapoints.length).toBe((end - start) / step + 1); - }); - - it('should fill null until first datapoint in response', function() { - expect(results.data[0].datapoints[0][1]).toBe(start * 1000); - expect(results.data[0].datapoints[0][0]).toBe(null); - expect(results.data[0].datapoints[1][1]).toBe((start + step * 1) * 1000); - expect(results.data[0].datapoints[1][0]).toBe(3846); - }); - it('should fill null after last datapoint in response', function() { - var length = (end - start) / step + 1; - expect(results.data[0].datapoints[length - 2][1]).toBe((end - step * 1) * 1000); - expect(results.data[0].datapoints[length - 2][0]).toBe(3848); - expect(results.data[0].datapoints[length - 1][1]).toBe(end * 1000); - expect(results.data[0].datapoints[length - 1][0]).toBe(null); - }); - it('should fill null at gap between series', function() { - expect(results.data[0].datapoints[2][1]).toBe((start + step * 2) * 1000); - expect(results.data[0].datapoints[2][0]).toBe(null); - expect(results.data[1].datapoints[1][1]).toBe((start + step * 1) * 1000); - expect(results.data[1].datapoints[1][0]).toBe(null); - expect(results.data[1].datapoints[3][1]).toBe((start + step * 3) * 1000); - expect(results.data[1].datapoints[3][0]).toBe(null); - }); - }); - describe('When querying prometheus with one target and instant = true', function() { - var results; - var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123'; - var query = { - range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) }, - targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }], - interval: '60s', - }; - - beforeEach(async () => { - let response = { - status: 'success', - data: { - data: { - resultType: 'vector', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - value: [123, '3846'], - }, - ], - }, - }, - }; - - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - - await ctx.ds.query(query).then(function(data) { - results = data; - }); - }); - it('should generate the correct query', function() { - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - }); - it('should return series list', function() { - expect(results.data.length).toBe(1); - expect(results.data[0].target).toBe('test{job="testjob"}'); - }); - }); - describe('When performing annotationQuery', function() { - var results; - - var options = { - annotation: { - expr: 'ALERTS{alertstate="firing"}', - tagKeys: 'job', - titleFormat: '{{alertname}}', - textFormat: '{{instance}}', - }, - range: { - from: time({ seconds: 63 }), - to: time({ seconds: 123 }), - }, - }; - - beforeEach(async () => { - let response = { - status: 'success', - data: { - data: { - resultType: 'matrix', - result: [ - { - metric: { - __name__: 'ALERTS', - alertname: 'InstanceDown', - alertstate: 'firing', - instance: 'testinstance', - job: 'testjob', - }, - values: [[123, '1']], - }, - ], - }, - }, - }; - - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - - await ctx.ds.annotationQuery(options).then(function(data) { - results = data; - }); - }); - it('should return annotation list', function() { - // ctx.$rootScope.$apply(); - expect(results.length).toBe(1); - expect(results[0].tags).toContain('testjob'); - expect(results[0].title).toBe('InstanceDown'); - expect(results[0].text).toBe('testinstance'); - expect(results[0].time).toBe(123 * 1000); - }); - }); - - describe('When resultFormat is table and instant = true', function() { - var results; - // var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123'; - var query = { - range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) }, - targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }], - interval: '60s', - }; - - beforeEach(async () => { - let response = { - status: 'success', - data: { - data: { - resultType: 'vector', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - value: [123, '3846'], - }, - ], - }, - }, - }; - - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query).then(function(data) { - results = data; - }); - }); - - it('should return result', () => { - expect(results).not.toBe(null); - }); - }); - - describe('The "step" query parameter', function() { - var response = { - status: 'success', - data: { - data: { - resultType: 'matrix', - result: [], - }, - }, - }; - - it('should be min interval when greater than auto interval', async () => { - let query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'test', - interval: '10s', - }, - ], - interval: '5s', - }; - let urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=10'; - - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - }); - - it('step should never go below 1', async () => { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [{ expr: 'test' }], - interval: '100ms', - }; - var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=1'; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - }); - - it('should be auto interval when greater than min interval', async () => { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'test', - interval: '5s', - }, - ], - interval: '10s', - }; - var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=10'; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - }); - it('should result in querying fewer than 11000 data points', async () => { - var query = { - // 6 hour range - range: { from: time({ hours: 1 }), to: time({ hours: 7 }) }, - targets: [{ expr: 'test' }], - interval: '1s', - }; - var end = 7 * 60 * 60; - var start = 60 * 60; - var urlExpected = 'proxied/api/v1/query_range?query=test&start=' + start + '&end=' + end + '&step=2'; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - }); - it('should not apply min interval when interval * intervalFactor greater', async () => { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'test', - interval: '10s', - intervalFactor: 10, - }, - ], - interval: '5s', - }; - // times get rounded up to interval - var urlExpected = 'proxied/api/v1/query_range?query=test&start=50&end=450&step=50'; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - }); - it('should apply min interval when interval * intervalFactor smaller', async () => { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'test', - interval: '15s', - intervalFactor: 2, - }, - ], - interval: '5s', - }; - var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=60&end=420&step=15'; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - }); - it('should apply intervalFactor to auto interval when greater', async () => { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'test', - interval: '5s', - intervalFactor: 10, - }, - ], - interval: '10s', - }; - // times get aligned to interval - var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=0&end=500&step=100'; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - }); - it('should not not be affected by the 11000 data points limit when large enough', async () => { - var query = { - // 1 week range - range: { from: time({}), to: time({ hours: 7 * 24 }) }, - targets: [ - { - expr: 'test', - intervalFactor: 10, - }, - ], - interval: '10s', - }; - var end = 7 * 24 * 60 * 60; - var start = 0; - var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=' + start + '&end=' + end + '&step=100'; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - }); - it('should be determined by the 11000 data points limit when too small', async () => { - var query = { - // 1 week range - range: { from: time({}), to: time({ hours: 7 * 24 }) }, - targets: [ - { - expr: 'test', - intervalFactor: 10, - }, - ], - interval: '5s', - }; - var end = 7 * 24 * 60 * 60; - var start = 0; - var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=' + start + '&end=' + end + '&step=60'; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - }); - }); - - describe('The __interval and __interval_ms template variables', function() { - var response = { - status: 'success', - data: { - data: { - resultType: 'matrix', - result: [], - }, - }, - }; - - it('should be unchanged when auto interval is greater than min interval', async () => { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - interval: '5s', - }, - ], - interval: '10s', - scopedVars: { - __interval: { text: '10s', value: '10s' }, - __interval_ms: { text: 10 * 1000, value: 10 * 1000 }, - }, - }; - - var urlExpected = - 'proxied/api/v1/query_range?query=' + - encodeURIComponent('rate(test[$__interval])') + - '&start=60&end=420&step=10'; - - templateSrv.replace = jest.fn(str => str); - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - - expect(templateSrv.replace.mock.calls[0][1]).toEqual({ - __interval: { - text: '10s', - value: '10s', - }, - __interval_ms: { - text: 10000, - value: 10000, - }, - }); - }); - it('should be min interval when it is greater than auto interval', async () => { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - interval: '10s', - }, - ], - interval: '5s', - scopedVars: { - __interval: { text: '5s', value: '5s' }, - __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, - }, - }; - var urlExpected = - 'proxied/api/v1/query_range?query=' + - encodeURIComponent('rate(test[$__interval])') + - '&start=60&end=420&step=10'; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - templateSrv.replace = jest.fn(str => str); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - - expect(templateSrv.replace.mock.calls[0][1]).toEqual({ - __interval: { - text: '5s', - value: '5s', - }, - __interval_ms: { - text: 5000, - value: 5000, - }, - }); - }); - it('should account for intervalFactor', async () => { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - interval: '5s', - intervalFactor: 10, - }, - ], - interval: '10s', - scopedVars: { - __interval: { text: '10s', value: '10s' }, - __interval_ms: { text: 10 * 1000, value: 10 * 1000 }, - }, - }; - var urlExpected = - 'proxied/api/v1/query_range?query=' + - encodeURIComponent('rate(test[$__interval])') + - '&start=0&end=500&step=100'; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - templateSrv.replace = jest.fn(str => str); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - - expect(templateSrv.replace.mock.calls[0][1]).toEqual({ - __interval: { - text: '10s', - value: '10s', - }, - __interval_ms: { - text: 10000, - value: 10000, - }, - }); - - expect(query.scopedVars.__interval.text).toBe('10s'); - expect(query.scopedVars.__interval.value).toBe('10s'); - expect(query.scopedVars.__interval_ms.text).toBe(10 * 1000); - expect(query.scopedVars.__interval_ms.value).toBe(10 * 1000); - }); - it('should be interval * intervalFactor when greater than min interval', async () => { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - interval: '10s', - intervalFactor: 10, - }, - ], - interval: '5s', - scopedVars: { - __interval: { text: '5s', value: '5s' }, - __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, - }, - }; - var urlExpected = - 'proxied/api/v1/query_range?query=' + - encodeURIComponent('rate(test[$__interval])') + - '&start=50&end=450&step=50'; - - templateSrv.replace = jest.fn(str => str); - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - - expect(templateSrv.replace.mock.calls[0][1]).toEqual({ - __interval: { - text: '5s', - value: '5s', - }, - __interval_ms: { - text: 5000, - value: 5000, - }, - }); - }); - it('should be min interval when greater than interval * intervalFactor', async () => { - var query = { - // 6 minute range - range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - interval: '15s', - intervalFactor: 2, - }, - ], - interval: '5s', - scopedVars: { - __interval: { text: '5s', value: '5s' }, - __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, - }, - }; - var urlExpected = - 'proxied/api/v1/query_range?query=' + - encodeURIComponent('rate(test[$__interval])') + - '&start=60&end=420&step=15'; - - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - - expect(templateSrv.replace.mock.calls[0][1]).toEqual({ - __interval: { - text: '5s', - value: '5s', - }, - __interval_ms: { - text: 5000, - value: 5000, - }, - }); - }); - it('should be determined by the 11000 data points limit, accounting for intervalFactor', async () => { - var query = { - // 1 week range - range: { from: time({}), to: time({ hours: 7 * 24 }) }, - targets: [ - { - expr: 'rate(test[$__interval])', - intervalFactor: 10, - }, - ], - interval: '5s', - scopedVars: { - __interval: { text: '5s', value: '5s' }, - __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, - }, - }; - var end = 7 * 24 * 60 * 60; - var start = 0; - var urlExpected = - 'proxied/api/v1/query_range?query=' + - encodeURIComponent('rate(test[$__interval])') + - '&start=' + - start + - '&end=' + - end + - '&step=60'; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - templateSrv.replace = jest.fn(str => str); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query); - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('GET'); - expect(res.url).toBe(urlExpected); - - expect(templateSrv.replace.mock.calls[0][1]).toEqual({ - __interval: { - text: '5s', - value: '5s', - }, - __interval_ms: { - text: 5000, - value: 5000, - }, - }); - }); - }); -}); - -describe('PrometheusDatasource for POST', function() { - // var ctx = new helpers.ServiceTestContext(); - let instanceSettings = { - url: 'proxied', - directUrl: 'direct', - user: 'test', - password: 'mupp', - jsonData: { httpMethod: 'POST' }, - }; - - // beforeEach(angularMocks.module('grafana.core')); - // beforeEach(angularMocks.module('grafana.services')); - // beforeEach(ctx.providePhase(['timeSrv'])); - - // beforeEach( - // // angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { - // // ctx.$q = $q; - // // ctx.$httpBackend = $httpBackend; - // // ctx.$rootScope = $rootScope; - // // ctx.ds = $injector.instantiate(PrometheusDatasource, { instanceSettings: instanceSettings }); - // // $httpBackend.when('GET', /\.html$/).respond(''); - // // }) - // ); - - describe('When querying prometheus with one target using query editor target spec', function() { - var results; - var urlExpected = 'proxied/api/v1/query_range'; - var dataExpected = { - query: 'test{job="testjob"}', - start: 1 * 60, - end: 3 * 60, - step: 60, - }; - var query = { - range: { from: time({ minutes: 1, seconds: 3 }), to: time({ minutes: 2, seconds: 3 }) }, - targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], - interval: '60s', - }; - - beforeEach(async () => { - let response = { - status: 'success', - data: { - data: { - resultType: 'matrix', - result: [ - { - metric: { __name__: 'test', job: 'testjob' }, - values: [[2 * 60, '3846']], - }, - ], - }, - }, - }; - backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); - ctx.ds = new PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv); - await ctx.ds.query(query).then(function(data) { - results = data; - }); - }); - it('should generate the correct query', function() { - let res = backendSrv.datasourceRequest.mock.calls[0][0]; - expect(res.method).toBe('POST'); - expect(res.url).toBe(urlExpected); - expect(res.data).toEqual(dataExpected); - }); - it('should return series list', function() { - expect(results.data.length).toBe(1); - expect(results.data[0].target).toBe('test{job="testjob"}'); - }); - }); -}); diff --git a/public/app/plugins/datasource/prometheus/specs/datasource.jest.ts b/public/app/plugins/datasource/prometheus/specs/datasource.jest.ts index b8b2b50f590..f60af583f45 100644 --- a/public/app/plugins/datasource/prometheus/specs/datasource.jest.ts +++ b/public/app/plugins/datasource/prometheus/specs/datasource.jest.ts @@ -246,3 +246,797 @@ describe('PrometheusDatasource', () => { }); }); }); + +const SECOND = 1000; +const MINUTE = 60 * SECOND; +const HOUR = 60 * MINUTE; + +const time = ({ hours = 0, seconds = 0, minutes = 0 }) => moment(hours * HOUR + minutes * MINUTE + seconds * SECOND); + +let ctx = {}; +let instanceSettings = { + url: 'proxied', + directUrl: 'direct', + user: 'test', + password: 'mupp', + jsonData: { httpMethod: 'GET' }, +}; +let backendSrv = { + datasourceRequest: jest.fn(), +}; + +let templateSrv = { + replace: jest.fn(str => str), +}; + +let timeSrv = { + timeRange: () => { + return { to: { diff: () => 2000 }, from: '' }; + }, +}; + +describe('PrometheusDatasource', function() { + describe('When querying prometheus with one target using query editor target spec', async () => { + var results; + var query = { + range: { from: time({ seconds: 63 }), to: time({ seconds: 183 }) }, + targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], + interval: '60s', + }; + // Interval alignment with step + var urlExpected = + 'proxied/api/v1/query_range?query=' + encodeURIComponent('test{job="testjob"}') + '&start=60&end=240&step=60'; + + beforeEach(async () => { + let response = { + data: { + status: 'success', + data: { + resultType: 'matrix', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + values: [[60, '3846']], + }, + ], + }, + }, + }; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + + await ctx.ds.query(query).then(function(data) { + results = data; + }); + }); + + it('should generate the correct query', function() { + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should return series list', async () => { + expect(results.data.length).toBe(1); + expect(results.data[0].target).toBe('test{job="testjob"}'); + }); + }); + describe('When querying prometheus with one target which return multiple series', function() { + var results; + var start = 60; + var end = 360; + var step = 60; + + var query = { + range: { from: time({ seconds: start }), to: time({ seconds: end }) }, + targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], + interval: '60s', + }; + + beforeEach(async () => { + let response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [ + { + metric: { __name__: 'test', job: 'testjob', series: 'series 1' }, + values: [[start + step * 1, '3846'], [start + step * 3, '3847'], [end - step * 1, '3848']], + }, + { + metric: { __name__: 'test', job: 'testjob', series: 'series 2' }, + values: [[start + step * 2, '4846']], + }, + ], + }, + }, + }; + + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + + await ctx.ds.query(query).then(function(data) { + results = data; + }); + }); + + it('should be same length', function() { + expect(results.data.length).toBe(2); + expect(results.data[0].datapoints.length).toBe((end - start) / step + 1); + expect(results.data[1].datapoints.length).toBe((end - start) / step + 1); + }); + + it('should fill null until first datapoint in response', function() { + expect(results.data[0].datapoints[0][1]).toBe(start * 1000); + expect(results.data[0].datapoints[0][0]).toBe(null); + expect(results.data[0].datapoints[1][1]).toBe((start + step * 1) * 1000); + expect(results.data[0].datapoints[1][0]).toBe(3846); + }); + it('should fill null after last datapoint in response', function() { + var length = (end - start) / step + 1; + expect(results.data[0].datapoints[length - 2][1]).toBe((end - step * 1) * 1000); + expect(results.data[0].datapoints[length - 2][0]).toBe(3848); + expect(results.data[0].datapoints[length - 1][1]).toBe(end * 1000); + expect(results.data[0].datapoints[length - 1][0]).toBe(null); + }); + it('should fill null at gap between series', function() { + expect(results.data[0].datapoints[2][1]).toBe((start + step * 2) * 1000); + expect(results.data[0].datapoints[2][0]).toBe(null); + expect(results.data[1].datapoints[1][1]).toBe((start + step * 1) * 1000); + expect(results.data[1].datapoints[1][0]).toBe(null); + expect(results.data[1].datapoints[3][1]).toBe((start + step * 3) * 1000); + expect(results.data[1].datapoints[3][0]).toBe(null); + }); + }); + describe('When querying prometheus with one target and instant = true', function() { + var results; + var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123'; + var query = { + range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) }, + targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }], + interval: '60s', + }; + + beforeEach(async () => { + let response = { + status: 'success', + data: { + data: { + resultType: 'vector', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + value: [123, '3846'], + }, + ], + }, + }, + }; + + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + + await ctx.ds.query(query).then(function(data) { + results = data; + }); + }); + it('should generate the correct query', function() { + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should return series list', function() { + expect(results.data.length).toBe(1); + expect(results.data[0].target).toBe('test{job="testjob"}'); + }); + }); + describe('When performing annotationQuery', function() { + var results; + + var options = { + annotation: { + expr: 'ALERTS{alertstate="firing"}', + tagKeys: 'job', + titleFormat: '{{alertname}}', + textFormat: '{{instance}}', + }, + range: { + from: time({ seconds: 63 }), + to: time({ seconds: 123 }), + }, + }; + + beforeEach(async () => { + let response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [ + { + metric: { + __name__: 'ALERTS', + alertname: 'InstanceDown', + alertstate: 'firing', + instance: 'testinstance', + job: 'testjob', + }, + values: [[123, '1']], + }, + ], + }, + }, + }; + + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + + await ctx.ds.annotationQuery(options).then(function(data) { + results = data; + }); + }); + it('should return annotation list', function() { + expect(results.length).toBe(1); + expect(results[0].tags).toContain('testjob'); + expect(results[0].title).toBe('InstanceDown'); + expect(results[0].text).toBe('testinstance'); + expect(results[0].time).toBe(123 * 1000); + }); + }); + + describe('When resultFormat is table and instant = true', function() { + var results; + var query = { + range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) }, + targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }], + interval: '60s', + }; + + beforeEach(async () => { + let response = { + status: 'success', + data: { + data: { + resultType: 'vector', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + value: [123, '3846'], + }, + ], + }, + }, + }; + + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query).then(function(data) { + results = data; + }); + }); + + it('should return result', () => { + expect(results).not.toBe(null); + }); + }); + + describe('The "step" query parameter', function() { + var response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [], + }, + }, + }; + + it('should be min interval when greater than auto interval', async () => { + let query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'test', + interval: '10s', + }, + ], + interval: '5s', + }; + let urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=10'; + + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + + it('step should never go below 1', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [{ expr: 'test' }], + interval: '100ms', + }; + var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=1'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + + it('should be auto interval when greater than min interval', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'test', + interval: '5s', + }, + ], + interval: '10s', + }; + var urlExpected = 'proxied/api/v1/query_range?query=test&start=60&end=420&step=10'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should result in querying fewer than 11000 data points', async () => { + var query = { + // 6 hour range + range: { from: time({ hours: 1 }), to: time({ hours: 7 }) }, + targets: [{ expr: 'test' }], + interval: '1s', + }; + var end = 7 * 60 * 60; + var start = 60 * 60; + var urlExpected = 'proxied/api/v1/query_range?query=test&start=' + start + '&end=' + end + '&step=2'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should not apply min interval when interval * intervalFactor greater', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'test', + interval: '10s', + intervalFactor: 10, + }, + ], + interval: '5s', + }; + // times get rounded up to interval + var urlExpected = 'proxied/api/v1/query_range?query=test&start=50&end=450&step=50'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should apply min interval when interval * intervalFactor smaller', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'test', + interval: '15s', + intervalFactor: 2, + }, + ], + interval: '5s', + }; + var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=60&end=420&step=15'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should apply intervalFactor to auto interval when greater', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'test', + interval: '5s', + intervalFactor: 10, + }, + ], + interval: '10s', + }; + // times get aligned to interval + var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=0&end=500&step=100'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should not not be affected by the 11000 data points limit when large enough', async () => { + var query = { + // 1 week range + range: { from: time({}), to: time({ hours: 7 * 24 }) }, + targets: [ + { + expr: 'test', + intervalFactor: 10, + }, + ], + interval: '10s', + }; + var end = 7 * 24 * 60 * 60; + var start = 0; + var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=' + start + '&end=' + end + '&step=100'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + it('should be determined by the 11000 data points limit when too small', async () => { + var query = { + // 1 week range + range: { from: time({}), to: time({ hours: 7 * 24 }) }, + targets: [ + { + expr: 'test', + intervalFactor: 10, + }, + ], + interval: '5s', + }; + var end = 7 * 24 * 60 * 60; + var start = 0; + var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=' + start + '&end=' + end + '&step=60'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + }); + }); + + describe('The __interval and __interval_ms template variables', function() { + var response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [], + }, + }, + }; + + it('should be unchanged when auto interval is greater than min interval', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + interval: '5s', + }, + ], + interval: '10s', + scopedVars: { + __interval: { text: '10s', value: '10s' }, + __interval_ms: { text: 10 * 1000, value: 10 * 1000 }, + }, + }; + + var urlExpected = + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[$__interval])') + + '&start=60&end=420&step=10'; + + templateSrv.replace = jest.fn(str => str); + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '10s', + value: '10s', + }, + __interval_ms: { + text: 10000, + value: 10000, + }, + }); + }); + it('should be min interval when it is greater than auto interval', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + interval: '10s', + }, + ], + interval: '5s', + scopedVars: { + __interval: { text: '5s', value: '5s' }, + __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, + }, + }; + var urlExpected = + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[$__interval])') + + '&start=60&end=420&step=10'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + templateSrv.replace = jest.fn(str => str); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '5s', + value: '5s', + }, + __interval_ms: { + text: 5000, + value: 5000, + }, + }); + }); + it('should account for intervalFactor', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + interval: '5s', + intervalFactor: 10, + }, + ], + interval: '10s', + scopedVars: { + __interval: { text: '10s', value: '10s' }, + __interval_ms: { text: 10 * 1000, value: 10 * 1000 }, + }, + }; + var urlExpected = + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[$__interval])') + + '&start=0&end=500&step=100'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + templateSrv.replace = jest.fn(str => str); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '10s', + value: '10s', + }, + __interval_ms: { + text: 10000, + value: 10000, + }, + }); + + expect(query.scopedVars.__interval.text).toBe('10s'); + expect(query.scopedVars.__interval.value).toBe('10s'); + expect(query.scopedVars.__interval_ms.text).toBe(10 * 1000); + expect(query.scopedVars.__interval_ms.value).toBe(10 * 1000); + }); + it('should be interval * intervalFactor when greater than min interval', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + interval: '10s', + intervalFactor: 10, + }, + ], + interval: '5s', + scopedVars: { + __interval: { text: '5s', value: '5s' }, + __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, + }, + }; + var urlExpected = + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[$__interval])') + + '&start=50&end=450&step=50'; + + templateSrv.replace = jest.fn(str => str); + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '5s', + value: '5s', + }, + __interval_ms: { + text: 5000, + value: 5000, + }, + }); + }); + it('should be min interval when greater than interval * intervalFactor', async () => { + var query = { + // 6 minute range + range: { from: time({ minutes: 1 }), to: time({ minutes: 7 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + interval: '15s', + intervalFactor: 2, + }, + ], + interval: '5s', + scopedVars: { + __interval: { text: '5s', value: '5s' }, + __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, + }, + }; + var urlExpected = + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[$__interval])') + + '&start=60&end=420&step=15'; + + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '5s', + value: '5s', + }, + __interval_ms: { + text: 5000, + value: 5000, + }, + }); + }); + it('should be determined by the 11000 data points limit, accounting for intervalFactor', async () => { + var query = { + // 1 week range + range: { from: time({}), to: time({ hours: 7 * 24 }) }, + targets: [ + { + expr: 'rate(test[$__interval])', + intervalFactor: 10, + }, + ], + interval: '5s', + scopedVars: { + __interval: { text: '5s', value: '5s' }, + __interval_ms: { text: 5 * 1000, value: 5 * 1000 }, + }, + }; + var end = 7 * 24 * 60 * 60; + var start = 0; + var urlExpected = + 'proxied/api/v1/query_range?query=' + + encodeURIComponent('rate(test[$__interval])') + + '&start=' + + start + + '&end=' + + end + + '&step=60'; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + templateSrv.replace = jest.fn(str => str); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query); + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('GET'); + expect(res.url).toBe(urlExpected); + + expect(templateSrv.replace.mock.calls[0][1]).toEqual({ + __interval: { + text: '5s', + value: '5s', + }, + __interval_ms: { + text: 5000, + value: 5000, + }, + }); + }); + }); +}); + +describe('PrometheusDatasource for POST', function() { + // var ctx = new helpers.ServiceTestContext(); + let instanceSettings = { + url: 'proxied', + directUrl: 'direct', + user: 'test', + password: 'mupp', + jsonData: { httpMethod: 'POST' }, + }; + + describe('When querying prometheus with one target using query editor target spec', function() { + var results; + var urlExpected = 'proxied/api/v1/query_range'; + var dataExpected = { + query: 'test{job="testjob"}', + start: 1 * 60, + end: 3 * 60, + step: 60, + }; + var query = { + range: { from: time({ minutes: 1, seconds: 3 }), to: time({ minutes: 2, seconds: 3 }) }, + targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], + interval: '60s', + }; + + beforeEach(async () => { + let response = { + status: 'success', + data: { + data: { + resultType: 'matrix', + result: [ + { + metric: { __name__: 'test', job: 'testjob' }, + values: [[2 * 60, '3846']], + }, + ], + }, + }, + }; + backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response)); + ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv, templateSrv, timeSrv); + await ctx.ds.query(query).then(function(data) { + results = data; + }); + }); + it('should generate the correct query', function() { + let res = backendSrv.datasourceRequest.mock.calls[0][0]; + expect(res.method).toBe('POST'); + expect(res.url).toBe(urlExpected); + expect(res.data).toEqual(dataExpected); + }); + it('should return series list', function() { + expect(results.data.length).toBe(1); + expect(results.data[0].target).toBe('test{job="testjob"}'); + }); + }); +}); From 951b623bd23ca1aa43833e2898876579c8417370 Mon Sep 17 00:00:00 2001 From: Tobias Skarhed Date: Wed, 1 Aug 2018 14:27:45 +0200 Subject: [PATCH 6/6] Change to arrow functions --- .../prometheus/specs/datasource.jest.ts | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/specs/datasource.jest.ts b/public/app/plugins/datasource/prometheus/specs/datasource.jest.ts index f60af583f45..aeca8d69191 100644 --- a/public/app/plugins/datasource/prometheus/specs/datasource.jest.ts +++ b/public/app/plugins/datasource/prometheus/specs/datasource.jest.ts @@ -150,49 +150,49 @@ describe('PrometheusDatasource', () => { }); }); - describe('alignRange', function() { - it('does not modify already aligned intervals with perfect step', function() { + describe('alignRange', () => { + it('does not modify already aligned intervals with perfect step', () => { const range = alignRange(0, 3, 3); expect(range.start).toEqual(0); expect(range.end).toEqual(3); }); - it('does modify end-aligned intervals to reflect number of steps possible', function() { + it('does modify end-aligned intervals to reflect number of steps possible', () => { const range = alignRange(1, 6, 3); expect(range.start).toEqual(0); expect(range.end).toEqual(6); }); - it('does align intervals that are a multiple of steps', function() { + it('does align intervals that are a multiple of steps', () => { const range = alignRange(1, 4, 3); expect(range.start).toEqual(0); expect(range.end).toEqual(6); }); - it('does align intervals that are not a multiple of steps', function() { + it('does align intervals that are not a multiple of steps', () => { const range = alignRange(1, 5, 3); expect(range.start).toEqual(0); expect(range.end).toEqual(6); }); }); - describe('Prometheus regular escaping', function() { - it('should not escape non-string', function() { + describe('Prometheus regular escaping', () => { + it('should not escape non-string', () => { expect(prometheusRegularEscape(12)).toEqual(12); }); - it('should not escape simple string', function() { + it('should not escape simple string', () => { expect(prometheusRegularEscape('cryptodepression')).toEqual('cryptodepression'); }); - it("should escape '", function() { + it("should escape '", () => { expect(prometheusRegularEscape("looking'glass")).toEqual("looking\\\\'glass"); }); - it('should escape multiple characters', function() { + it('should escape multiple characters', () => { expect(prometheusRegularEscape("'looking'glass'")).toEqual("\\\\'looking\\\\'glass\\\\'"); }); }); - describe('Prometheus regexes escaping', function() { - it('should not escape simple string', function() { + describe('Prometheus regexes escaping', () => { + it('should not escape simple string', () => { expect(prometheusSpecialRegexEscape('cryptodepression')).toEqual('cryptodepression'); }); - it('should escape $^*+?.()\\', function() { + it('should escape $^*+?.()\\', () => { expect(prometheusSpecialRegexEscape("looking'glass")).toEqual("looking\\\\'glass"); expect(prometheusSpecialRegexEscape('looking{glass')).toEqual('looking\\\\{glass'); expect(prometheusSpecialRegexEscape('looking}glass')).toEqual('looking\\\\}glass'); @@ -208,7 +208,7 @@ describe('PrometheusDatasource', () => { expect(prometheusSpecialRegexEscape('looking)glass')).toEqual('looking\\\\)glass'); expect(prometheusSpecialRegexEscape('looking\\glass')).toEqual('looking\\\\\\\\glass'); }); - it('should escape multiple special characters', function() { + it('should escape multiple special characters', () => { expect(prometheusSpecialRegexEscape('+looking$glass?')).toEqual('\\\\+looking\\\\$glass\\\\?'); }); }); @@ -275,7 +275,7 @@ let timeSrv = { }, }; -describe('PrometheusDatasource', function() { +describe('PrometheusDatasource', () => { describe('When querying prometheus with one target using query editor target spec', async () => { var results; var query = { @@ -310,7 +310,7 @@ describe('PrometheusDatasource', function() { }); }); - it('should generate the correct query', function() { + it('should generate the correct query', () => { let res = backendSrv.datasourceRequest.mock.calls[0][0]; expect(res.method).toBe('GET'); expect(res.url).toBe(urlExpected); @@ -320,7 +320,7 @@ describe('PrometheusDatasource', function() { expect(results.data[0].target).toBe('test{job="testjob"}'); }); }); - describe('When querying prometheus with one target which return multiple series', function() { + describe('When querying prometheus with one target which return multiple series', () => { var results; var start = 60; var end = 360; @@ -360,26 +360,26 @@ describe('PrometheusDatasource', function() { }); }); - it('should be same length', function() { + it('should be same length', () => { expect(results.data.length).toBe(2); expect(results.data[0].datapoints.length).toBe((end - start) / step + 1); expect(results.data[1].datapoints.length).toBe((end - start) / step + 1); }); - it('should fill null until first datapoint in response', function() { + it('should fill null until first datapoint in response', () => { expect(results.data[0].datapoints[0][1]).toBe(start * 1000); expect(results.data[0].datapoints[0][0]).toBe(null); expect(results.data[0].datapoints[1][1]).toBe((start + step * 1) * 1000); expect(results.data[0].datapoints[1][0]).toBe(3846); }); - it('should fill null after last datapoint in response', function() { + it('should fill null after last datapoint in response', () => { var length = (end - start) / step + 1; expect(results.data[0].datapoints[length - 2][1]).toBe((end - step * 1) * 1000); expect(results.data[0].datapoints[length - 2][0]).toBe(3848); expect(results.data[0].datapoints[length - 1][1]).toBe(end * 1000); expect(results.data[0].datapoints[length - 1][0]).toBe(null); }); - it('should fill null at gap between series', function() { + it('should fill null at gap between series', () => { expect(results.data[0].datapoints[2][1]).toBe((start + step * 2) * 1000); expect(results.data[0].datapoints[2][0]).toBe(null); expect(results.data[1].datapoints[1][1]).toBe((start + step * 1) * 1000); @@ -388,7 +388,7 @@ describe('PrometheusDatasource', function() { expect(results.data[1].datapoints[3][0]).toBe(null); }); }); - describe('When querying prometheus with one target and instant = true', function() { + describe('When querying prometheus with one target and instant = true', () => { var results; var urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123'; var query = { @@ -420,17 +420,17 @@ describe('PrometheusDatasource', function() { results = data; }); }); - it('should generate the correct query', function() { + it('should generate the correct query', () => { let res = backendSrv.datasourceRequest.mock.calls[0][0]; expect(res.method).toBe('GET'); expect(res.url).toBe(urlExpected); }); - it('should return series list', function() { + it('should return series list', () => { expect(results.data.length).toBe(1); expect(results.data[0].target).toBe('test{job="testjob"}'); }); }); - describe('When performing annotationQuery', function() { + describe('When performing annotationQuery', () => { var results; var options = { @@ -475,7 +475,7 @@ describe('PrometheusDatasource', function() { results = data; }); }); - it('should return annotation list', function() { + it('should return annotation list', () => { expect(results.length).toBe(1); expect(results[0].tags).toContain('testjob'); expect(results[0].title).toBe('InstanceDown'); @@ -484,7 +484,7 @@ describe('PrometheusDatasource', function() { }); }); - describe('When resultFormat is table and instant = true', function() { + describe('When resultFormat is table and instant = true', () => { var results; var query = { range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) }, @@ -520,7 +520,7 @@ describe('PrometheusDatasource', function() { }); }); - describe('The "step" query parameter', function() { + describe('The "step" query parameter', () => { var response = { status: 'success', data: { @@ -717,7 +717,7 @@ describe('PrometheusDatasource', function() { }); }); - describe('The __interval and __interval_ms template variables', function() { + describe('The __interval and __interval_ms template variables', () => { var response = { status: 'success', data: { @@ -982,7 +982,7 @@ describe('PrometheusDatasource', function() { }); }); -describe('PrometheusDatasource for POST', function() { +describe('PrometheusDatasource for POST', () => { // var ctx = new helpers.ServiceTestContext(); let instanceSettings = { url: 'proxied', @@ -992,7 +992,7 @@ describe('PrometheusDatasource for POST', function() { jsonData: { httpMethod: 'POST' }, }; - describe('When querying prometheus with one target using query editor target spec', function() { + describe('When querying prometheus with one target using query editor target spec', () => { var results; var urlExpected = 'proxied/api/v1/query_range'; var dataExpected = { @@ -1028,13 +1028,13 @@ describe('PrometheusDatasource for POST', function() { results = data; }); }); - it('should generate the correct query', function() { + it('should generate the correct query', () => { let res = backendSrv.datasourceRequest.mock.calls[0][0]; expect(res.method).toBe('POST'); expect(res.url).toBe(urlExpected); expect(res.data).toEqual(dataExpected); }); - it('should return series list', function() { + it('should return series list', () => { expect(results.data.length).toBe(1); expect(results.data[0].target).toBe('test{job="testjob"}'); });