Преглед на файлове

Merge pull request #11726 from grafana/11708_prom_variables

prometheus: variable query should fallback correctly to a series query
Daniel Lee преди 7 години
родител
ревизия
1dd4f03100

+ 4 - 0
public/app/plugins/datasource/prometheus/datasource.ts

@@ -329,4 +329,8 @@ export class PrometheusDatasource {
     }
     return Math.ceil(date.valueOf() / 1000);
   }
+
+  getOriginalMetricName(labelData) {
+    return this.resultTransformer.getOriginalMetricName(labelData);
+  }
 }

+ 1 - 1
public/app/plugins/datasource/prometheus/metric_find_query.ts

@@ -121,7 +121,7 @@ export default class PrometheusMetricFindQuery {
 
     var self = this;
     return this.datasource.metadataRequest(url).then(function(result) {
-      return _.map(result.data.data, function(metric) {
+      return _.map(result.data.data, metric => {
         return {
           text: self.datasource.getOriginalMetricName(metric),
           expandable: true,

+ 20 - 0
public/app/plugins/datasource/prometheus/specs/datasource.jest.ts

@@ -43,6 +43,26 @@ describe('PrometheusDatasource', () => {
     });
   });
 
+  describe('When performing performSuggestQuery', () => {
+    it('should cache response', async () => {
+      ctx.backendSrvMock.datasourceRequest.mockReturnValue(
+        Promise.resolve({
+          status: 'success',
+          data: { data: ['value1', 'value2', 'value3'] },
+        })
+      );
+
+      let results = await ctx.ds.performSuggestQuery('value', true);
+
+      expect(results).toHaveLength(3);
+
+      ctx.backendSrvMock.datasourceRequest.mockReset();
+      results = await ctx.ds.performSuggestQuery('value', true);
+
+      expect(results).toHaveLength(3);
+    });
+  });
+
   describe('When converting prometheus histogram to heatmap format', () => {
     beforeEach(() => {
       ctx.query = {

+ 205 - 0
public/app/plugins/datasource/prometheus/specs/metric_find_query.jest.ts

@@ -0,0 +1,205 @@
+import moment from 'moment';
+import { PrometheusDatasource } from '../datasource';
+import PrometheusMetricFindQuery from '../metric_find_query';
+import q from 'q';
+
+describe('PrometheusMetricFindQuery', function() {
+  let instanceSettings = {
+    url: 'proxied',
+    directUrl: 'direct',
+    user: 'test',
+    password: 'mupp',
+    jsonData: { httpMethod: 'GET' },
+  };
+  const raw = {
+    from: moment.utc('2018-04-25 10:00'),
+    to: moment.utc('2018-04-25 11:00'),
+  };
+  let ctx: any = {
+    backendSrvMock: {
+      datasourceRequest: jest.fn(() => Promise.resolve({})),
+    },
+    templateSrvMock: {
+      replace: a => a,
+    },
+    timeSrvMock: {
+      timeRange: () => ({
+        from: raw.from,
+        to: raw.to,
+        raw: raw,
+      }),
+    },
+  };
+
+  ctx.setupMetricFindQuery = (data: any) => {
+    ctx.backendSrvMock.datasourceRequest.mockReturnValue(Promise.resolve({ status: 'success', data: data.response }));
+    return new PrometheusMetricFindQuery(ctx.ds, data.query, ctx.timeSrvMock);
+  };
+
+  beforeEach(() => {
+    ctx.backendSrvMock.datasourceRequest.mockReset();
+    ctx.ds = new PrometheusDatasource(instanceSettings, q, ctx.backendSrvMock, ctx.templateSrvMock, ctx.timeSrvMock);
+  });
+
+  describe('When performing metricFindQuery', () => {
+    it('label_values(resource) should generate label search query', async () => {
+      const query = ctx.setupMetricFindQuery({
+        query: 'label_values(resource)',
+        response: {
+          data: ['value1', 'value2', 'value3'],
+        },
+      });
+      const results = await query.process();
+
+      expect(results).toHaveLength(3);
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledTimes(1);
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledWith({
+        method: 'GET',
+        url: 'proxied/api/v1/label/resource/values',
+        silent: true,
+      });
+    });
+
+    it('label_values(metric, resource) should generate series query with correct time', async () => {
+      const query = ctx.setupMetricFindQuery({
+        query: 'label_values(metric, resource)',
+        response: {
+          data: [
+            { __name__: 'metric', resource: 'value1' },
+            { __name__: 'metric', resource: 'value2' },
+            { __name__: 'metric', resource: 'value3' },
+          ],
+        },
+      });
+      const results = await query.process();
+
+      expect(results).toHaveLength(3);
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledTimes(1);
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledWith({
+        method: 'GET',
+        url: `proxied/api/v1/series?match[]=metric&start=${raw.from.unix()}&end=${raw.to.unix()}`,
+        silent: true,
+      });
+    });
+
+    it('label_values(metric{label1="foo", label2="bar", label3="baz"}, resource) should generate series query with correct time', async () => {
+      const query = ctx.setupMetricFindQuery({
+        query: 'label_values(metric{label1="foo", label2="bar", label3="baz"}, resource)',
+        response: {
+          data: [
+            { __name__: 'metric', resource: 'value1' },
+            { __name__: 'metric', resource: 'value2' },
+            { __name__: 'metric', resource: 'value3' },
+          ],
+        },
+      });
+      const results = await query.process();
+
+      expect(results).toHaveLength(3);
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledTimes(1);
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledWith({
+        method: 'GET',
+        url: `proxied/api/v1/series?match[]=${encodeURIComponent(
+          'metric{label1="foo", label2="bar", label3="baz"}'
+        )}&start=${raw.from.unix()}&end=${raw.to.unix()}`,
+        silent: true,
+      });
+    });
+
+    it('label_values(metric, resource) result should not contain empty string', async () => {
+      const query = ctx.setupMetricFindQuery({
+        query: 'label_values(metric, resource)',
+        response: {
+          data: [
+            { __name__: 'metric', resource: 'value1' },
+            { __name__: 'metric', resource: 'value2' },
+            { __name__: 'metric', resource: '' },
+          ],
+        },
+      });
+      const results = await query.process();
+
+      expect(results).toHaveLength(2);
+      expect(results[0].text).toBe('value1');
+      expect(results[1].text).toBe('value2');
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledTimes(1);
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledWith({
+        method: 'GET',
+        url: `proxied/api/v1/series?match[]=metric&start=${raw.from.unix()}&end=${raw.to.unix()}`,
+        silent: true,
+      });
+    });
+
+    it('metrics(metric.*) should generate metric name query', async () => {
+      const query = ctx.setupMetricFindQuery({
+        query: 'metrics(metric.*)',
+        response: {
+          data: ['metric1', 'metric2', 'metric3', 'nomatch'],
+        },
+      });
+      const results = await query.process();
+
+      expect(results).toHaveLength(3);
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledTimes(1);
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledWith({
+        method: 'GET',
+        url: 'proxied/api/v1/label/__name__/values',
+        silent: true,
+      });
+    });
+
+    it('query_result(metric) should generate metric name query', async () => {
+      const query = ctx.setupMetricFindQuery({
+        query: 'query_result(metric)',
+        response: {
+          data: {
+            resultType: 'vector',
+            result: [
+              {
+                metric: { __name__: 'metric', job: 'testjob' },
+                value: [1443454528.0, '3846'],
+              },
+            ],
+          },
+        },
+      });
+      const results = await query.process();
+
+      expect(results).toHaveLength(1);
+      expect(results[0].text).toBe('metric{job="testjob"} 3846 1443454528000');
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledTimes(1);
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledWith({
+        method: 'GET',
+        url: `proxied/api/v1/query?query=metric&time=${raw.to.unix()}`,
+        requestId: undefined,
+      });
+    });
+
+    it('up{job="job1"} should fallback using generate series query', async () => {
+      const query = ctx.setupMetricFindQuery({
+        query: 'up{job="job1"}',
+        response: {
+          data: [
+            { __name__: 'up', instance: '127.0.0.1:1234', job: 'job1' },
+            { __name__: 'up', instance: '127.0.0.1:5678', job: 'job1' },
+            { __name__: 'up', instance: '127.0.0.1:9102', job: 'job1' },
+          ],
+        },
+      });
+      const results = await query.process();
+
+      expect(results).toHaveLength(3);
+      expect(results[0].text).toBe('up{instance="127.0.0.1:1234",job="job1"}');
+      expect(results[1].text).toBe('up{instance="127.0.0.1:5678",job="job1"}');
+      expect(results[2].text).toBe('up{instance="127.0.0.1:9102",job="job1"}');
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledTimes(1);
+      expect(ctx.backendSrvMock.datasourceRequest).toHaveBeenCalledWith({
+        method: 'GET',
+        url: `proxied/api/v1/series?match[]=${encodeURIComponent(
+          'up{job="job1"}'
+        )}&start=${raw.from.unix()}&end=${raw.to.unix()}`,
+        silent: true,
+      });
+    });
+  });
+});

+ 0 - 181
public/app/plugins/datasource/prometheus/specs/metric_find_query_specs.ts

@@ -1,181 +0,0 @@
-import { describe, beforeEach, it, expect, angularMocks } from 'test/lib/common';
-
-import moment from 'moment';
-import helpers from 'test/specs/helpers';
-import { PrometheusDatasource } from '../datasource';
-import PrometheusMetricFindQuery from '../metric_find_query';
-
-describe('PrometheusMetricFindQuery', 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(
-    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 performing metricFindQuery', function() {
-    var results;
-    var response;
-    it('label_values(resource) should generate label search query', function() {
-      response = {
-        status: 'success',
-        data: ['value1', 'value2', 'value3'],
-      };
-      ctx.$httpBackend.expect('GET', 'proxied/api/v1/label/resource/values').respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(resource)', ctx.timeSrv);
-      pm.process().then(function(data) {
-        results = data;
-      });
-      ctx.$httpBackend.flush();
-      ctx.$rootScope.$apply();
-      expect(results.length).to.be(3);
-    });
-    it('label_values(metric, resource) should generate series query', function() {
-      response = {
-        status: 'success',
-        data: [
-          { __name__: 'metric', resource: 'value1' },
-          { __name__: 'metric', resource: 'value2' },
-          { __name__: 'metric', resource: 'value3' },
-        ],
-      };
-      ctx.$httpBackend.expect('GET', /proxied\/api\/v1\/series\?match\[\]=metric&start=.*&end=.*/).respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(metric, resource)', ctx.timeSrv);
-      pm.process().then(function(data) {
-        results = data;
-      });
-      ctx.$httpBackend.flush();
-      ctx.$rootScope.$apply();
-      expect(results.length).to.be(3);
-    });
-    it('label_values(metric, resource) should pass correct time', function() {
-      ctx.timeSrv.setTime({
-        from: moment.utc('2011-01-01'),
-        to: moment.utc('2015-01-01'),
-      });
-      ctx.$httpBackend
-        .expect('GET', /proxied\/api\/v1\/series\?match\[\]=metric&start=1293840000&end=1420070400/)
-        .respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(metric, resource)', ctx.timeSrv);
-      pm.process().then(function(data) {
-        results = data;
-      });
-      ctx.$httpBackend.flush();
-      ctx.$rootScope.$apply();
-    });
-    it('label_values(metric{label1="foo", label2="bar", label3="baz"}, resource) should generate series query', function() {
-      response = {
-        status: 'success',
-        data: [
-          { __name__: 'metric', resource: 'value1' },
-          { __name__: 'metric', resource: 'value2' },
-          { __name__: 'metric', resource: 'value3' },
-        ],
-      };
-      ctx.$httpBackend.expect('GET', /proxied\/api\/v1\/series\?match\[\]=metric&start=.*&end=.*/).respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(metric, resource)', ctx.timeSrv);
-      pm.process().then(function(data) {
-        results = data;
-      });
-      ctx.$httpBackend.flush();
-      ctx.$rootScope.$apply();
-      expect(results.length).to.be(3);
-    });
-    it('label_values(metric, resource) result should not contain empty string', function() {
-      response = {
-        status: 'success',
-        data: [
-          { __name__: 'metric', resource: 'value1' },
-          { __name__: 'metric', resource: 'value2' },
-          { __name__: 'metric', resource: '' },
-        ],
-      };
-      ctx.$httpBackend.expect('GET', /proxied\/api\/v1\/series\?match\[\]=metric&start=.*&end=.*/).respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(metric, resource)', ctx.timeSrv);
-      pm.process().then(function(data) {
-        results = data;
-      });
-      ctx.$httpBackend.flush();
-      ctx.$rootScope.$apply();
-      expect(results.length).to.be(2);
-      expect(results[0].text).to.be('value1');
-      expect(results[1].text).to.be('value2');
-    });
-    it('metrics(metric.*) should generate metric name query', function() {
-      response = {
-        status: 'success',
-        data: ['metric1', 'metric2', 'metric3', 'nomatch'],
-      };
-      ctx.$httpBackend.expect('GET', 'proxied/api/v1/label/__name__/values').respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'metrics(metric.*)', ctx.timeSrv);
-      pm.process().then(function(data) {
-        results = data;
-      });
-      ctx.$httpBackend.flush();
-      ctx.$rootScope.$apply();
-      expect(results.length).to.be(3);
-    });
-    it('query_result(metric) should generate metric name query', function() {
-      response = {
-        status: 'success',
-        data: {
-          resultType: 'vector',
-          result: [
-            {
-              metric: { __name__: 'metric', job: 'testjob' },
-              value: [1443454528.0, '3846'],
-            },
-          ],
-        },
-      };
-      ctx.$httpBackend.expect('GET', /proxied\/api\/v1\/query\?query=metric&time=.*/).respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'query_result(metric)', ctx.timeSrv);
-      pm.process().then(function(data) {
-        results = data;
-      });
-      ctx.$httpBackend.flush();
-      ctx.$rootScope.$apply();
-      expect(results.length).to.be(1);
-      expect(results[0].text).to.be('metric{job="testjob"} 3846 1443454528000');
-    });
-  });
-
-  describe('When performing performSuggestQuery', function() {
-    var results;
-    var response;
-    it('cache response', function() {
-      response = {
-        status: 'success',
-        data: ['value1', 'value2', 'value3'],
-      };
-      ctx.$httpBackend.expect('GET', 'proxied/api/v1/label/__name__/values').respond(response);
-      ctx.ds.performSuggestQuery('value', true).then(function(data) {
-        results = data;
-      });
-      ctx.$httpBackend.flush();
-      ctx.$rootScope.$apply();
-      expect(results.length).to.be(3);
-      ctx.ds.performSuggestQuery('value', true).then(function(data) {
-        // get from cache, no need to flush
-        results = data;
-        expect(results.length).to.be(3);
-      });
-    });
-  });
-});