The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/public/app/plugins/datasource/prometheus/querybuilder/parsing.test.ts

313 lines
7.8 KiB

import { buildVisualQueryFromString } from './parsing';
import { PromVisualQuery } from './types';
describe('buildVisualQueryFromString', () => {
it('parses simple query', () => {
expect(buildVisualQueryFromString('counters_logins{app="frontend"}')).toEqual(
noErrors({
metric: 'counters_logins',
labels: [
{
op: '=',
value: 'frontend',
label: 'app',
},
],
operations: [],
})
);
});
it('parses query with rate and interval', () => {
expect(buildVisualQueryFromString('rate(counters_logins{app="frontend"}[5m])')).toEqual(
noErrors({
metric: 'counters_logins',
labels: [
{
op: '=',
value: 'frontend',
label: 'app',
},
],
operations: [
{
id: 'rate',
params: ['5m'],
},
],
})
);
});
it('parses query with nested query and interval variable', () => {
expect(
buildVisualQueryFromString(
'avg(rate(access_evaluation_duration_count{instance="host.docker.internal:3000"}[$__rate_interval]))'
)
).toEqual(
noErrors({
metric: 'access_evaluation_duration_count',
labels: [
{
op: '=',
value: 'host.docker.internal:3000',
label: 'instance',
},
],
operations: [
{
id: 'rate',
params: ['$__rate_interval'],
},
{
id: 'avg',
params: [],
},
],
})
);
});
it('parses query with aggregation by labels', () => {
const visQuery = {
metric: 'metric_name',
labels: [
{
label: 'instance',
op: '=',
value: 'internal:3000',
},
],
operations: [
{
id: '__sum_by',
params: ['app', 'version'],
},
],
};
expect(buildVisualQueryFromString('sum(metric_name{instance="internal:3000"}) by (app, version)')).toEqual(
noErrors(visQuery)
);
expect(buildVisualQueryFromString('sum by (app, version)(metric_name{instance="internal:3000"})')).toEqual(
noErrors(visQuery)
);
});
it('parses aggregation with params', () => {
expect(buildVisualQueryFromString('topk(5, http_requests_total)')).toEqual(
noErrors({
metric: 'http_requests_total',
labels: [],
operations: [
{
id: 'topk',
params: [5],
},
],
})
);
});
it('parses aggregation with params and labels', () => {
expect(buildVisualQueryFromString('topk by(instance, job) (5, http_requests_total)')).toEqual(
noErrors({
metric: 'http_requests_total',
labels: [],
operations: [
{
id: '__topk_by',
params: [5, 'instance', 'job'],
},
],
})
);
});
it('parses function with multiple arguments', () => {
expect(
buildVisualQueryFromString(
'label_replace(avg_over_time(http_requests_total{instance="foo"}[$__interval]), "instance", "$1", "", "(.*)")'
)
).toEqual(
noErrors({
metric: 'http_requests_total',
labels: [{ label: 'instance', op: '=', value: 'foo' }],
operations: [
{
id: 'avg_over_time',
params: ['$__interval'],
},
{
id: 'label_replace',
params: ['instance', '$1', '', '(.*)'],
},
],
})
);
});
it('parses binary operation with scalar', () => {
expect(buildVisualQueryFromString('avg_over_time(http_requests_total{instance="foo"}[$__interval]) / 2')).toEqual(
noErrors({
metric: 'http_requests_total',
labels: [{ label: 'instance', op: '=', value: 'foo' }],
operations: [
{
id: 'avg_over_time',
params: ['$__interval'],
},
{
id: '__divide_by',
params: [2],
},
],
})
);
});
it('parses binary operation with 2 queries', () => {
expect(
buildVisualQueryFromString('avg_over_time(http_requests_total{instance="foo"}[$__interval]) / sum(logins_count)')
).toEqual(
noErrors({
metric: 'http_requests_total',
labels: [{ label: 'instance', op: '=', value: 'foo' }],
operations: [{ id: 'avg_over_time', params: ['$__interval'] }],
binaryQueries: [
{
operator: '/',
query: {
metric: 'logins_count',
labels: [],
operations: [{ id: 'sum', params: [] }],
},
},
],
})
);
});
it('parses template variables in strings', () => {
expect(buildVisualQueryFromString('http_requests_total{instance="$label_variable"}')).toEqual(
noErrors({
metric: 'http_requests_total',
labels: [{ label: 'instance', op: '=', value: '$label_variable' }],
operations: [],
})
);
});
it('parses template variables for metric', () => {
expect(buildVisualQueryFromString('$metric_variable{instance="foo"}')).toEqual(
noErrors({
metric: '$metric_variable',
labels: [{ label: 'instance', op: '=', value: 'foo' }],
operations: [],
})
);
expect(buildVisualQueryFromString('${metric_variable:fmt}{instance="foo"}')).toEqual(
noErrors({
metric: '${metric_variable:fmt}',
labels: [{ label: 'instance', op: '=', value: 'foo' }],
operations: [],
})
);
expect(buildVisualQueryFromString('[[metric_variable:fmt]]{instance="foo"}')).toEqual(
noErrors({
metric: '[[metric_variable:fmt]]',
labels: [{ label: 'instance', op: '=', value: 'foo' }],
operations: [],
})
);
});
it('parses template variables in label name', () => {
expect(buildVisualQueryFromString('metric{${variable_label}="foo"}')).toEqual(
noErrors({
metric: 'metric',
labels: [{ label: '${variable_label}', op: '=', value: 'foo' }],
operations: [],
})
);
});
it('fails to parse variable for function', () => {
expect(buildVisualQueryFromString('${func_var}(metric{bar="foo"})')).toEqual({
errors: [
{
text: '(',
from: 20,
to: 21,
parentType: 'VectorSelector',
},
{
text: 'metric',
from: 21,
to: 27,
parentType: 'VectorSelector',
},
],
query: {
metric: '${func_var}',
labels: [{ label: 'bar', op: '=', value: 'foo' }],
operations: [],
},
});
});
it('fails to parse malformed query', () => {
expect(buildVisualQueryFromString('asdf-metric{bar="})')).toEqual({
errors: [
{
text: '',
from: 19,
to: 19,
parentType: 'LabelMatchers',
},
],
query: {
metric: 'asdf',
labels: [],
operations: [],
binaryQueries: [
{
operator: '-',
query: {
metric: 'metric',
labels: [{ label: 'bar', op: '=', value: '})' }],
operations: [],
},
},
],
},
});
});
it('fails to parse malformed query 2', () => {
expect(buildVisualQueryFromString('ewafweaf{afea=afe}')).toEqual({
errors: [
{
text: 'afe}',
from: 14,
to: 18,
parentType: 'LabelMatcher',
},
],
query: {
metric: 'ewafweaf',
labels: [{ label: 'afea', op: '=', value: '' }],
operations: [],
},
});
});
});
function noErrors(query: PromVisualQuery) {
return {
errors: [],
query,
};
}