Files
grafana/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts
2017-10-04 16:23:24 +02:00

580 lines
22 KiB
TypeScript

import {describe, beforeEach, it, expect, angularMocks} from 'test/lib/common';
import moment from 'moment';
import helpers from 'test/specs/helpers';
import {PrometheusDatasource} from '../datasource';
describe('PrometheusDatasource', function() {
var ctx = new helpers.ServiceTestContext();
var instanceSettings = {url: 'proxied', directUrl: 'direct', user: 'test', password: 'mupp' };
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?query=' +
encodeURIComponent('test{job="testjob"}') +
'&start=1443438675&end=1443460275&step=60';
var query = {
range: { from: moment(1443438674760), to: moment(1443460274760) },
targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }],
interval: '60s'
};
var response = {
status: "success",
data: {
resultType: "matrix",
result: [{
metric: {"__name__": "test", job: "testjob"},
values: [[1443454528, "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 = 1443438675;
var end = 1443460275;
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: moment(1443438674760), to: moment(1443460274760) },
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=1443460275';
var query = {
range: { from: moment(1443438674760), to: moment(1443460274760) },
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: [1443454528, "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=1443438675&end=1443460275&step=60s';
var options = {
annotation: {
expr: 'ALERTS{alertstate="firing"}',
tagKeys: 'job',
titleFormat: '{{alertname}}',
textFormat: '{{instance}}'
},
range: {
from: moment(1443438674760),
to: moment(1443460274760)
}
};
var response = {
status: "success",
data: {
resultType: "matrix",
result: [{
metric: {"__name__": "ALERTS", alertname: "InstanceDown", alertstate: "firing", instance: "testinstance", job: "testjob"},
values: [[1443454528, "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(1443454528 * 1000);
});
});
describe('When resultFormat is table', function() {
var response = {
status: "success",
data: {
resultType: "matrix",
result: [
{
metric: {"__name__": "test", job: "testjob"},
values: [[1443454528, "3846"]]
},
{
metric: {"__name__": "test", instance: "localhost:8080", job: "otherjob"},
values: [[1443454529, "3847"]]
},
]
}
};
it('should return table model', function() {
var table = ctx.ds.transformMetricDataToTable(response.data.result);
expect(table.type).to.be('table');
expect(table.rows).to.eql(
[
[ 1443454528000, 'test', '', 'testjob', 3846],
[ 1443454529000, 'test', 'localhost:8080', "otherjob", 3847],
]);
expect(table.columns).to.eql(
[ { text: 'Time', type: 'time' },
{ text: '__name__' },
{ text: 'instance' },
{ text: 'job' },
{ text: 'Value' }
]
);
});
});
describe('When resultFormat is table and instant = true', function() {
var results;
var urlExpected = 'proxied/api/v1/query?query=' +
encodeURIComponent('test{job="testjob"}') +
'&time=1443460275';
var query = {
range: { from: moment(1443438674760), to: moment(1443460274760) },
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: [1443454528, "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 table model', function() {
var table = ctx.ds.transformMetricDataToTable(response.data.result);
expect(table.type).to.be('table');
expect(table.rows).to.eql(
[
[ 1443454528000, 'test', 'testjob', 3846]
]);
expect(table.columns).to.eql(
[ { text: 'Time', type: 'time' },
{ text: '__name__' },
{ text: 'job' },
{ text: 'Value' }
]
);
});
});
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 hour range
range: { from: moment(1443438674760), to: moment(1443460274760) },
targets: [{
expr: 'test',
interval: '10s'
}],
interval: '5s'
};
var urlExpected = 'proxied/api/v1/query_range?query=test' +
'&start=1443438675&end=1443460275&step=10';
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 hour range
range: { from: moment(1443438674760), to: moment(1443460274760) },
targets: [{
expr: 'test',
interval: '5s'
}],
interval: '10s'
};
var urlExpected = 'proxied/api/v1/query_range?query=test' +
'&start=1443438675&end=1443460275&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: moment(1443438674760), to: moment(1443460274760) },
targets: [{ expr: 'test' }],
interval: '1s'
};
var urlExpected = 'proxied/api/v1/query_range?query=test' +
'&start=1443438675&end=1443460275&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 hour range
range: { from: moment(1443438674760), to: moment(1443460274760) },
targets: [{
expr: 'test',
interval: '10s',
intervalFactor: 10
}],
interval: '5s'
};
var urlExpected = 'proxied/api/v1/query_range?query=test' +
'&start=1443438675&end=1443460275&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 hour range
range: { from: moment(1443438674760), to: moment(1443460274760) },
targets: [{
expr: 'test',
interval: '15s',
intervalFactor: 2
}],
interval: '5s'
};
var urlExpected = 'proxied/api/v1/query_range?query=test' +
'&start=1443438675&end=1443460275&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 hour range
range: { from: moment(1443438674760), to: moment(1443460274760) },
targets: [{
expr: 'test',
interval: '5s',
intervalFactor: 10
}],
interval: '10s'
};
var urlExpected = 'proxied/api/v1/query_range?query=test' +
'&start=1443438675&end=1443460275&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: moment(1443438674760), to: moment(1444043474760) },
targets: [{
expr: 'test',
intervalFactor: 10
}],
interval: '10s'
};
var urlExpected = 'proxied/api/v1/query_range?query=test' +
'&start=1443438675&end=1444043475&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: moment(1443438674760), to: moment(1444043474760) },
targets: [{
expr: 'test',
intervalFactor: 10
}],
interval: '5s'
};
var urlExpected = 'proxied/api/v1/query_range?query=test' +
'&start=1443438675&end=1444043475&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 hour range
range: { from: moment(1443438674760), to: moment(1443460274760) },
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=1443438675&end=1443460275&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 hour range
range: { from: moment(1443438674760), to: moment(1443460274760) },
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=1443438675&end=1443460275&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 hour range
range: { from: moment(1443438674760), to: moment(1443460274760) },
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=1443438675&end=1443460275&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 hour range
range: { from: moment(1443438674760), to: moment(1443460274760) },
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=1443438675&end=1443460275&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 hour range
range: { from: moment(1443438674760), to: moment(1443460274760) },
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=1443438675&end=1443460275&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: moment(1443438674760), to: moment(1444043474760) },
targets: [{
expr: 'rate(test[$__interval])',
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[60s])') +
'&start=1443438675&end=1444043475&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);
});
});
});