mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'master' into permissions-to-redux
This commit is contained in:
commit
d173ebe7e8
16
public/app/core/specs/url.test.ts
Normal file
16
public/app/core/specs/url.test.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { toUrlParams } from '../utils/url';
|
||||
|
||||
describe('toUrlParams', () => {
|
||||
it('should encode object properties as url parameters', () => {
|
||||
const url = toUrlParams({
|
||||
server: 'backend-01',
|
||||
hasSpace: 'has space',
|
||||
many: ['1', '2', '3'],
|
||||
true: true,
|
||||
number: 20,
|
||||
isNull: null,
|
||||
isUndefined: undefined,
|
||||
});
|
||||
expect(url).toBe('server=backend-01&hasSpace=has%20space&many=1&many=2&many=3&true&number=20&isNull=&isUndefined=');
|
||||
});
|
||||
});
|
@ -50,7 +50,5 @@ export function toUrlParams(a) {
|
||||
return s;
|
||||
};
|
||||
|
||||
return buildParams('', a)
|
||||
.join('&')
|
||||
.replace(/%20/g, '+');
|
||||
return buildParams('', a).join('&');
|
||||
}
|
||||
|
@ -59,10 +59,10 @@ export class AdHocFiltersCtrl {
|
||||
let promise = null;
|
||||
|
||||
if (segment.type !== 'value') {
|
||||
promise = ds.getTagKeys();
|
||||
promise = ds.getTagKeys ? ds.getTagKeys() : Promise.resolve([]);
|
||||
} else {
|
||||
options.key = this.segments[index - 2].value;
|
||||
promise = ds.getTagValues(options);
|
||||
promise = ds.getTagValues ? ds.getTagValues(options) : Promise.resolve([]);
|
||||
}
|
||||
|
||||
return promise.then(results => {
|
||||
@ -99,7 +99,7 @@ export class AdHocFiltersCtrl {
|
||||
this.segments.splice(index, 0, this.uiSegmentSrv.newCondition('AND'));
|
||||
}
|
||||
this.segments.push(this.uiSegmentSrv.newOperator('='));
|
||||
this.segments.push(this.uiSegmentSrv.newFake('select tag value', 'value', 'query-segment-value'));
|
||||
this.segments.push(this.uiSegmentSrv.newFake('select value', 'value', 'query-segment-value'));
|
||||
segment.type = 'key';
|
||||
segment.cssClass = 'query-segment-key';
|
||||
}
|
||||
|
@ -56,11 +56,10 @@ export class TemplateSrv {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (variable.datasource === datasourceName) {
|
||||
// null is the "default" datasource
|
||||
if (variable.datasource === null || variable.datasource === datasourceName) {
|
||||
filters = filters.concat(variable.filters);
|
||||
}
|
||||
|
||||
if (variable.datasource.indexOf('$') === 0) {
|
||||
} else if (variable.datasource.indexOf('$') === 0) {
|
||||
if (this.replace(variable.datasource) === datasourceName) {
|
||||
filters = filters.concat(variable.filters);
|
||||
}
|
||||
|
@ -0,0 +1,93 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
const keywords = 'by|without|on|ignoring|group_left|group_right';
|
||||
|
||||
// Duplicate from mode-prometheus.js, which can't be used in tests due to global ace not being loaded.
|
||||
const builtInWords = [
|
||||
keywords,
|
||||
'count|count_values|min|max|avg|sum|stddev|stdvar|bottomk|topk|quantile',
|
||||
'true|false|null|__name__|job',
|
||||
'abs|absent|ceil|changes|clamp_max|clamp_min|count_scalar|day_of_month|day_of_week|days_in_month|delta|deriv',
|
||||
'drop_common_labels|exp|floor|histogram_quantile|holt_winters|hour|idelta|increase|irate|label_replace|ln|log2',
|
||||
'log10|minute|month|predict_linear|rate|resets|round|scalar|sort|sort_desc|sqrt|time|vector|year|avg_over_time',
|
||||
'min_over_time|max_over_time|sum_over_time|count_over_time|quantile_over_time|stddev_over_time|stdvar_over_time',
|
||||
]
|
||||
.join('|')
|
||||
.split('|');
|
||||
|
||||
const metricNameRegexp = /([A-Za-z]\w*)\b(?![\(\]{=!",])/g;
|
||||
const selectorRegexp = /{([^{]*)}/g;
|
||||
|
||||
// addLabelToQuery('foo', 'bar', 'baz') => 'foo{bar="baz"}'
|
||||
export function addLabelToQuery(query: string, key: string, value: string, operator?: string): string {
|
||||
if (!key || !value) {
|
||||
throw new Error('Need label to add to query.');
|
||||
}
|
||||
|
||||
// Add empty selectors to bare metric names
|
||||
let previousWord;
|
||||
query = query.replace(metricNameRegexp, (match, word, offset) => {
|
||||
const insideSelector = isPositionInsideChars(query, offset, '{', '}');
|
||||
// Handle "sum by (key) (metric)"
|
||||
const previousWordIsKeyWord = previousWord && keywords.split('|').indexOf(previousWord) > -1;
|
||||
previousWord = word;
|
||||
if (!insideSelector && !previousWordIsKeyWord && builtInWords.indexOf(word) === -1) {
|
||||
return `${word}{}`;
|
||||
}
|
||||
return word;
|
||||
});
|
||||
|
||||
// Adding label to existing selectors
|
||||
let match = selectorRegexp.exec(query);
|
||||
const parts = [];
|
||||
let lastIndex = 0;
|
||||
let suffix = '';
|
||||
|
||||
while (match) {
|
||||
const prefix = query.slice(lastIndex, match.index);
|
||||
const selector = match[1];
|
||||
const selectorWithLabel = addLabelToSelector(selector, key, value, operator);
|
||||
lastIndex = match.index + match[1].length + 2;
|
||||
suffix = query.slice(match.index + match[0].length);
|
||||
parts.push(prefix, '{', selectorWithLabel, '}');
|
||||
match = selectorRegexp.exec(query);
|
||||
}
|
||||
|
||||
parts.push(suffix);
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
const labelRegexp = /(\w+)\s*(=|!=|=~|!~)\s*("[^"]*")/g;
|
||||
|
||||
function addLabelToSelector(selector: string, labelKey: string, labelValue: string, labelOperator?: string) {
|
||||
const parsedLabels = [];
|
||||
|
||||
// Split selector into labels
|
||||
if (selector) {
|
||||
let match = labelRegexp.exec(selector);
|
||||
while (match) {
|
||||
parsedLabels.push({ key: match[1], operator: match[2], value: match[3] });
|
||||
match = labelRegexp.exec(selector);
|
||||
}
|
||||
}
|
||||
|
||||
// Add new label
|
||||
const operatorForLabelKey = labelOperator || '=';
|
||||
parsedLabels.push({ key: labelKey, operator: operatorForLabelKey, value: `"${labelValue}"` });
|
||||
|
||||
// Sort labels by key and put them together
|
||||
return _.chain(parsedLabels)
|
||||
.compact()
|
||||
.sortBy('key')
|
||||
.map(({ key, operator, value }) => `${key}${operator}${value}`)
|
||||
.value()
|
||||
.join(',');
|
||||
}
|
||||
|
||||
function isPositionInsideChars(text: string, position: number, openChar: string, closeChar: string) {
|
||||
const nextSelectorStart = text.slice(position).indexOf(openChar);
|
||||
const nextSelectorEnd = text.slice(position).indexOf(closeChar);
|
||||
return nextSelectorEnd > -1 && (nextSelectorStart === -1 || nextSelectorStart > nextSelectorEnd);
|
||||
}
|
||||
|
||||
export default addLabelToQuery;
|
@ -113,7 +113,7 @@ export class PromCompleter {
|
||||
_.uniq(
|
||||
_.flatten(
|
||||
result.map(r => {
|
||||
return Object.keys(r.metric);
|
||||
return Object.keys(r);
|
||||
})
|
||||
)
|
||||
),
|
||||
@ -151,7 +151,7 @@ export class PromCompleter {
|
||||
const labelValues = this.transformToCompletions(
|
||||
_.uniq(
|
||||
result.map(r => {
|
||||
return r.metric[labelName];
|
||||
return r[labelName];
|
||||
})
|
||||
),
|
||||
'label value'
|
||||
@ -191,7 +191,7 @@ export class PromCompleter {
|
||||
_.uniq(
|
||||
_.flatten(
|
||||
result.map(r => {
|
||||
return Object.keys(r.metric);
|
||||
return Object.keys(r);
|
||||
})
|
||||
)
|
||||
),
|
||||
@ -233,7 +233,7 @@ export class PromCompleter {
|
||||
_.uniq(
|
||||
_.flatten(
|
||||
result.map(r => {
|
||||
return Object.keys(r.metric);
|
||||
return Object.keys(r);
|
||||
})
|
||||
)
|
||||
),
|
||||
@ -249,7 +249,7 @@ export class PromCompleter {
|
||||
_.uniq(
|
||||
_.flatten(
|
||||
result.map(r => {
|
||||
return Object.keys(r.metric);
|
||||
return Object.keys(r);
|
||||
})
|
||||
)
|
||||
),
|
||||
@ -264,7 +264,7 @@ export class PromCompleter {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
getLabelNameAndValueForExpression(expr, type) {
|
||||
getLabelNameAndValueForExpression(expr: string, type: string): Promise<any> {
|
||||
if (this.labelQueryCache[expr]) {
|
||||
return Promise.resolve(this.labelQueryCache[expr]);
|
||||
}
|
||||
@ -276,9 +276,11 @@ export class PromCompleter {
|
||||
}
|
||||
query = '{__name__' + op + '"' + expr + '"}';
|
||||
}
|
||||
return this.datasource.performInstantQuery({ expr: query }, new Date().getTime() / 1000).then(response => {
|
||||
this.labelQueryCache[expr] = response.data.data.result;
|
||||
return response.data.data.result;
|
||||
const { start, end } = this.datasource.getTimeRange();
|
||||
const url = '/api/v1/series?match[]=' + encodeURIComponent(query) + '&start=' + start + '&end=' + end;
|
||||
return this.datasource.metadataRequest(url).then(response => {
|
||||
this.labelQueryCache[expr] = response.data.data;
|
||||
return response.data.data;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,8 @@ import PrometheusMetricFindQuery from './metric_find_query';
|
||||
import { ResultTransformer } from './result_transformer';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
|
||||
import addLabelToQuery from './add_label_to_query';
|
||||
|
||||
export function alignRange(start, end, step) {
|
||||
const alignedEnd = Math.ceil(end / step) * step;
|
||||
const alignedStart = Math.floor(start / step) * step;
|
||||
@ -16,74 +18,6 @@ export function alignRange(start, end, step) {
|
||||
};
|
||||
}
|
||||
|
||||
const keywords = 'by|without|on|ignoring|group_left|group_right';
|
||||
|
||||
// Duplicate from mode-prometheus.js, which can't be used in tests due to global ace not being loaded.
|
||||
const builtInWords = [
|
||||
keywords,
|
||||
'count|count_values|min|max|avg|sum|stddev|stdvar|bottomk|topk|quantile',
|
||||
'true|false|null|__name__|job',
|
||||
'abs|absent|ceil|changes|clamp_max|clamp_min|count_scalar|day_of_month|day_of_week|days_in_month|delta|deriv',
|
||||
'drop_common_labels|exp|floor|histogram_quantile|holt_winters|hour|idelta|increase|irate|label_replace|ln|log2',
|
||||
'log10|minute|month|predict_linear|rate|resets|round|scalar|sort|sort_desc|sqrt|time|vector|year|avg_over_time',
|
||||
'min_over_time|max_over_time|sum_over_time|count_over_time|quantile_over_time|stddev_over_time|stdvar_over_time',
|
||||
]
|
||||
.join('|')
|
||||
.split('|');
|
||||
|
||||
// addLabelToQuery('foo', 'bar', 'baz') => 'foo{bar="baz"}'
|
||||
export function addLabelToQuery(query: string, key: string, value: string): string {
|
||||
if (!key || !value) {
|
||||
throw new Error('Need label to add to query.');
|
||||
}
|
||||
|
||||
// Add empty selector to bare metric name
|
||||
let previousWord;
|
||||
query = query.replace(/([A-Za-z]\w*)\b(?![\(\]{=",])/g, (match, word, offset) => {
|
||||
// Check if inside a selector
|
||||
const nextSelectorStart = query.slice(offset).indexOf('{');
|
||||
const nextSelectorEnd = query.slice(offset).indexOf('}');
|
||||
const insideSelector = nextSelectorEnd > -1 && (nextSelectorStart === -1 || nextSelectorStart > nextSelectorEnd);
|
||||
// Handle "sum by (key) (metric)"
|
||||
const previousWordIsKeyWord = previousWord && keywords.split('|').indexOf(previousWord) > -1;
|
||||
previousWord = word;
|
||||
if (!insideSelector && !previousWordIsKeyWord && builtInWords.indexOf(word) === -1) {
|
||||
return `${word}{}`;
|
||||
}
|
||||
return word;
|
||||
});
|
||||
|
||||
// Adding label to existing selectors
|
||||
const selectorRegexp = /{([^{]*)}/g;
|
||||
let match = selectorRegexp.exec(query);
|
||||
const parts = [];
|
||||
let lastIndex = 0;
|
||||
let suffix = '';
|
||||
|
||||
while (match) {
|
||||
const prefix = query.slice(lastIndex, match.index);
|
||||
const selectorParts = match[1].split(',');
|
||||
const labels = selectorParts.reduce((acc, label) => {
|
||||
const labelParts = label.split('=');
|
||||
if (labelParts.length === 2) {
|
||||
acc[labelParts[0]] = labelParts[1];
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
labels[key] = `"${value}"`;
|
||||
const selector = Object.keys(labels)
|
||||
.sort()
|
||||
.map(key => `${key}=${labels[key]}`)
|
||||
.join(',');
|
||||
lastIndex = match.index + match[1].length + 2;
|
||||
suffix = query.slice(match.index + match[0].length);
|
||||
parts.push(prefix, '{', selector, '}');
|
||||
match = selectorRegexp.exec(query);
|
||||
}
|
||||
parts.push(suffix);
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
export function determineQueryHints(series: any[], datasource?: any): any[] {
|
||||
const hints = series.map((s, i) => {
|
||||
const query: string = s.query;
|
||||
@ -406,8 +340,21 @@ export class PrometheusDatasource {
|
||||
}
|
||||
query.step = interval;
|
||||
|
||||
let expr = target.expr;
|
||||
|
||||
// Apply adhoc filters
|
||||
const adhocFilters = this.templateSrv.getAdhocFilters(this.name);
|
||||
expr = adhocFilters.reduce((acc, filter) => {
|
||||
const { key, operator } = filter;
|
||||
let { value } = filter;
|
||||
if (operator === '=~' || operator === '!~') {
|
||||
value = prometheusSpecialRegexEscape(value);
|
||||
}
|
||||
return addLabelToQuery(acc, key, value, operator);
|
||||
}, expr);
|
||||
|
||||
// Only replace vars in expression after having (possibly) updated interval vars
|
||||
query.expr = this.templateSrv.replace(target.expr, scopedVars, this.interpolateQueryExpr);
|
||||
query.expr = this.templateSrv.replace(expr, scopedVars, this.interpolateQueryExpr);
|
||||
query.requestId = options.panelId + target.refId;
|
||||
|
||||
// Align query interval with step
|
||||
@ -631,6 +578,14 @@ export class PrometheusDatasource {
|
||||
return Math.ceil(date.valueOf() / 1000);
|
||||
}
|
||||
|
||||
getTimeRange(): { start: number; end: number } {
|
||||
const range = this.timeSrv.timeRange();
|
||||
return {
|
||||
start: this.getPrometheusTime(range.from, false),
|
||||
end: this.getPrometheusTime(range.to, true),
|
||||
};
|
||||
}
|
||||
|
||||
getOriginalMetricName(labelData) {
|
||||
return this.resultTransformer.getOriginalMetricName(labelData);
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
import addLabelToQuery from '../add_label_to_query';
|
||||
|
||||
describe('addLabelToQuery()', () => {
|
||||
it('should add label to simple query', () => {
|
||||
expect(() => {
|
||||
addLabelToQuery('foo', '', '');
|
||||
}).toThrow();
|
||||
expect(addLabelToQuery('foo', 'bar', 'baz')).toBe('foo{bar="baz"}');
|
||||
expect(addLabelToQuery('foo{}', 'bar', 'baz')).toBe('foo{bar="baz"}');
|
||||
expect(addLabelToQuery('foo{x="yy"}', 'bar', 'baz')).toBe('foo{bar="baz",x="yy"}');
|
||||
expect(addLabelToQuery('metric > 0.001', 'foo', 'bar')).toBe('metric{foo="bar"} > 0.001');
|
||||
});
|
||||
|
||||
it('should add custom operator', () => {
|
||||
expect(addLabelToQuery('foo{}', 'bar', 'baz', '!=')).toBe('foo{bar!="baz"}');
|
||||
expect(addLabelToQuery('foo{x="yy"}', 'bar', 'baz', '!=')).toBe('foo{bar!="baz",x="yy"}');
|
||||
});
|
||||
|
||||
it('should not modify ranges', () => {
|
||||
expect(addLabelToQuery('rate(metric[1m])', 'foo', 'bar')).toBe('rate(metric{foo="bar"}[1m])');
|
||||
});
|
||||
|
||||
it('should detect in-order function use', () => {
|
||||
expect(addLabelToQuery('sum by (xx) (foo)', 'bar', 'baz')).toBe('sum by (xx) (foo{bar="baz"})');
|
||||
});
|
||||
|
||||
it('should handle selectors with punctuation', () => {
|
||||
expect(addLabelToQuery('foo{instance="my-host.com:9100"}', 'bar', 'baz')).toBe(
|
||||
'foo{bar="baz",instance="my-host.com:9100"}'
|
||||
);
|
||||
expect(addLabelToQuery('foo{list="a,b,c"}', 'bar', 'baz')).toBe('foo{bar="baz",list="a,b,c"}');
|
||||
});
|
||||
|
||||
it('should work on arithmetical expressions', () => {
|
||||
expect(addLabelToQuery('foo + foo', 'bar', 'baz')).toBe('foo{bar="baz"} + foo{bar="baz"}');
|
||||
expect(addLabelToQuery('foo{x="yy"} + metric', 'bar', 'baz')).toBe('foo{bar="baz",x="yy"} + metric{bar="baz"}');
|
||||
expect(addLabelToQuery('avg(foo) + sum(xx_yy)', 'bar', 'baz')).toBe('avg(foo{bar="baz"}) + sum(xx_yy{bar="baz"})');
|
||||
expect(addLabelToQuery('foo{x="yy"} * metric{y="zz",a="bb"} * metric2', 'bar', 'baz')).toBe(
|
||||
'foo{bar="baz",x="yy"} * metric{a="bb",bar="baz",y="zz"} * metric2{bar="baz"}'
|
||||
);
|
||||
});
|
||||
});
|
@ -18,22 +18,12 @@ describe('Prometheus editor completer', () => {
|
||||
const backendSrv = {} as BackendSrv;
|
||||
const datasourceStub = new PrometheusDatasource({}, {}, backendSrv, {}, {});
|
||||
|
||||
datasourceStub.performInstantQuery = jest.fn(() =>
|
||||
Promise.resolve({
|
||||
data: {
|
||||
data: {
|
||||
result: [
|
||||
{
|
||||
metric: {
|
||||
job: 'node',
|
||||
instance: 'localhost:9100',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
datasourceStub.metadataRequest = jest.fn(() =>
|
||||
Promise.resolve({ data: { data: [{ metric: { job: 'node', instance: 'localhost:9100' } }] } })
|
||||
);
|
||||
datasourceStub.getTimeRange = jest.fn(() => {
|
||||
return { start: 1514732400, end: 1514818800 };
|
||||
});
|
||||
datasourceStub.performSuggestQuery = jest.fn(() => Promise.resolve(['node_cpu']));
|
||||
|
||||
const templateSrv = {
|
||||
|
@ -8,11 +8,15 @@ import {
|
||||
PrometheusDatasource,
|
||||
prometheusSpecialRegexEscape,
|
||||
prometheusRegularEscape,
|
||||
addLabelToQuery,
|
||||
} from '../datasource';
|
||||
|
||||
jest.mock('../metric_find_query');
|
||||
|
||||
const DEFAULT_TEMPLATE_SRV_MOCK = {
|
||||
getAdhocFilters: () => [],
|
||||
replace: a => a,
|
||||
};
|
||||
|
||||
describe('PrometheusDatasource', () => {
|
||||
const ctx: any = {};
|
||||
const instanceSettings = {
|
||||
@ -25,9 +29,8 @@ describe('PrometheusDatasource', () => {
|
||||
|
||||
ctx.backendSrvMock = {};
|
||||
|
||||
ctx.templateSrvMock = {
|
||||
replace: a => a,
|
||||
};
|
||||
ctx.templateSrvMock = DEFAULT_TEMPLATE_SRV_MOCK;
|
||||
|
||||
ctx.timeSrvMock = {
|
||||
timeRange: () => {
|
||||
return {
|
||||
@ -60,6 +63,37 @@ describe('PrometheusDatasource', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('When using adhoc filters', () => {
|
||||
const DEFAULT_QUERY_EXPRESSION = 'metric{job="foo"} - metric';
|
||||
const target = { expr: DEFAULT_QUERY_EXPRESSION };
|
||||
|
||||
afterEach(() => {
|
||||
ctx.templateSrvMock.getAdhocFilters = DEFAULT_TEMPLATE_SRV_MOCK.getAdhocFilters;
|
||||
});
|
||||
|
||||
it('should not modify expression with no filters', () => {
|
||||
const result = ctx.ds.createQuery(target, { interval: '15s' });
|
||||
expect(result).toMatchObject({ expr: DEFAULT_QUERY_EXPRESSION });
|
||||
});
|
||||
|
||||
it('should add filters to expression', () => {
|
||||
ctx.templateSrvMock.getAdhocFilters = () => [
|
||||
{
|
||||
key: 'k1',
|
||||
operator: '=',
|
||||
value: 'v1',
|
||||
},
|
||||
{
|
||||
key: 'k2',
|
||||
operator: '!=',
|
||||
value: 'v2',
|
||||
},
|
||||
];
|
||||
const result = ctx.ds.createQuery(target, { interval: '15s' });
|
||||
expect(result).toMatchObject({ expr: 'metric{job="foo",k1="v1",k2!="v2"} - metric{k1="v1",k2!="v2"}' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('When performing performSuggestQuery', () => {
|
||||
it('should cache response', async () => {
|
||||
ctx.backendSrvMock.datasourceRequest.mockReturnValue(
|
||||
@ -358,26 +392,6 @@ describe('PrometheusDatasource', () => {
|
||||
expect(intervalMs).toEqual({ text: 15000, value: 15000 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('addLabelToQuery()', () => {
|
||||
expect(() => {
|
||||
addLabelToQuery('foo', '', '');
|
||||
}).toThrow();
|
||||
expect(addLabelToQuery('foo + foo', 'bar', 'baz')).toBe('foo{bar="baz"} + foo{bar="baz"}');
|
||||
expect(addLabelToQuery('foo{}', 'bar', 'baz')).toBe('foo{bar="baz"}');
|
||||
expect(addLabelToQuery('foo{x="yy"}', 'bar', 'baz')).toBe('foo{bar="baz",x="yy"}');
|
||||
expect(addLabelToQuery('foo{x="yy"} + metric', 'bar', 'baz')).toBe('foo{bar="baz",x="yy"} + metric{bar="baz"}');
|
||||
expect(addLabelToQuery('avg(foo) + sum(xx_yy)', 'bar', 'baz')).toBe('avg(foo{bar="baz"}) + sum(xx_yy{bar="baz"})');
|
||||
expect(addLabelToQuery('foo{x="yy"} * metric{y="zz",a="bb"} * metric2', 'bar', 'baz')).toBe(
|
||||
'foo{bar="baz",x="yy"} * metric{a="bb",bar="baz",y="zz"} * metric2{bar="baz"}'
|
||||
);
|
||||
expect(addLabelToQuery('sum by (xx) (foo)', 'bar', 'baz')).toBe('sum by (xx) (foo{bar="baz"})');
|
||||
expect(addLabelToQuery('foo{instance="my-host.com:9100"}', 'bar', 'baz')).toBe(
|
||||
'foo{bar="baz",instance="my-host.com:9100"}'
|
||||
);
|
||||
expect(addLabelToQuery('rate(metric[1m])', 'foo', 'bar')).toBe('rate(metric{foo="bar"}[1m])');
|
||||
expect(addLabelToQuery('metric > 0.001', 'foo', 'bar')).toBe('metric{foo="bar"} > 0.001');
|
||||
});
|
||||
});
|
||||
|
||||
const SECOND = 1000;
|
||||
@ -399,6 +413,7 @@ const backendSrv = {
|
||||
} as any;
|
||||
|
||||
const templateSrv = {
|
||||
getAdhocFilters: () => [],
|
||||
replace: jest.fn(str => str),
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user