mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
981 lines
28 KiB
TypeScript
981 lines
28 KiB
TypeScript
// Copyright 2021 The Prometheus Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import { Parser } from './parser';
|
|
import { Diagnostic } from '@codemirror/lint';
|
|
import { createEditorState } from '../test/utils-test';
|
|
import { syntaxTree } from '@codemirror/language';
|
|
import { ValueType } from '../types';
|
|
|
|
describe('promql operations', () => {
|
|
const testCases = [
|
|
{
|
|
expr: '1',
|
|
expectedValueType: ValueType.scalar,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: '2 * 3',
|
|
expectedValueType: ValueType.scalar,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: '1 unless 1',
|
|
expectedValueType: ValueType.scalar,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 10,
|
|
message: 'set operator not allowed in binary scalar expression',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'metric_name * "string"',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 14,
|
|
to: 22,
|
|
message: 'binary expression must contain only scalar and instant vector types',
|
|
severity: 'error',
|
|
},
|
|
] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'metric_name_1 > bool metric_name_2',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'metric_name_1 + bool metric_name_2',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 34,
|
|
message: 'bool modifier can only be used on comparison operators',
|
|
severity: 'error',
|
|
},
|
|
] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'metric_name offset 1d',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'metric_name[5m] offset 1d',
|
|
expectedValueType: ValueType.matrix,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'rate(metric_name[5m])[1h:] offset 1m',
|
|
expectedValueType: ValueType.matrix,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'sum(metric_name offset 1m)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'rate(metric_name[5m] offset 1d)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'mad_over_time(rate(metric_name[5m])[1h:] offset 1m)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'max_over_time(rate(metric_name[5m])[1h:] offset 1m)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo * bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo*bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo* bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo *bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo==bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo * sum',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo == 1',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo == bool 1',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: '2.5 / bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo and bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo or bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo unless bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
// Test and/or precedence and reassigning of operands.
|
|
// Here it will test only the first VectorMatching so (a + b) or (c and d) ==> ManyToMany
|
|
expr: 'foo + bar or bla and blub',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
// Test and/or/unless precedence.
|
|
// Here it will test only the first VectorMatching so ((a and b) unless c) or d ==> ManyToMany
|
|
expr: 'foo and bar unless baz or qux',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo * on(test,blub) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo*on(test,blub)bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo * on(test,blub) group_left bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo*on(test,blub)group_left()bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo and on(test,blub) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo and on(test,"blub") bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo and on() bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo and ignoring(test,blub) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo and ignoring(test,"blub") bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo and ignoring() bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo unless on(bar) baz',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo / on(test,blub) group_left(bar) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo / on(test,blub) group_left("bar") bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo / ignoring(test,blub) group_left(blub) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo / ignoring(test,blub) group_left(bar) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo - on(test,blub) group_right(bar,foo) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo - ignoring(test,blub) group_right(bar,foo) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [] as Diagnostic[],
|
|
},
|
|
{
|
|
expr: 'foo and 1',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 9,
|
|
message: 'set operator not allowed in binary scalar expression',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: '1 and foo',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 9,
|
|
message: 'set operator not allowed in binary scalar expression',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo or 1',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 8,
|
|
message: 'set operator not allowed in binary scalar expression',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: '1 or foo',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 8,
|
|
message: 'set operator not allowed in binary scalar expression',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo unless 1',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 12,
|
|
message: 'set operator not allowed in binary scalar expression',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: '1 unless foo',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 12,
|
|
message: 'set operator not allowed in binary scalar expression',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: '1 or on(bar) foo',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 16,
|
|
message: 'vector matching only allowed between instant vectors',
|
|
severity: 'error',
|
|
},
|
|
{
|
|
from: 0,
|
|
to: 16,
|
|
message: 'set operator not allowed in binary scalar expression',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo == on(bar) 10',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 17,
|
|
message: 'vector matching only allowed between instant vectors',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo and on(bar) group_left(baz) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 35,
|
|
message: 'no grouping allowed for set operations',
|
|
severity: 'error',
|
|
},
|
|
{
|
|
from: 0,
|
|
to: 35,
|
|
message: 'set operations must always be many-to-many',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo and on(bar) group_right(baz) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 36,
|
|
message: 'no grouping allowed for set operations',
|
|
severity: 'error',
|
|
},
|
|
{
|
|
from: 0,
|
|
to: 36,
|
|
message: 'set operations must always be many-to-many',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo or on(bar) group_left(baz) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 34,
|
|
message: 'no grouping allowed for set operations',
|
|
severity: 'error',
|
|
},
|
|
{
|
|
from: 0,
|
|
to: 34,
|
|
message: 'set operations must always be many-to-many',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo or on(bar) group_right(baz) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 35,
|
|
message: 'no grouping allowed for set operations',
|
|
severity: 'error',
|
|
},
|
|
{
|
|
from: 0,
|
|
to: 35,
|
|
message: 'set operations must always be many-to-many',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo unless on(bar) group_left(baz) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 38,
|
|
message: 'no grouping allowed for set operations',
|
|
severity: 'error',
|
|
},
|
|
{
|
|
from: 0,
|
|
to: 38,
|
|
message: 'set operations must always be many-to-many',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo unless on(bar) group_right(baz) bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 39,
|
|
message: 'no grouping allowed for set operations',
|
|
severity: 'error',
|
|
},
|
|
{
|
|
from: 0,
|
|
to: 39,
|
|
message: 'set operations must always be many-to-many',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'http_requests{group="production"} + on(instance) group_left(job,instance) cpu_count{type="smp"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 95,
|
|
message: 'label "instance" must not occur in ON and GROUP clause at once',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo + bool bar',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 14,
|
|
message: 'bool modifier can only be used on comparison operators',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo + bool 10',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 13,
|
|
message: 'bool modifier can only be used on comparison operators',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo and bool 10',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 15,
|
|
message: 'bool modifier can only be used on comparison operators',
|
|
severity: 'error',
|
|
},
|
|
{
|
|
from: 0,
|
|
to: 15,
|
|
message: 'set operator not allowed in binary scalar expression',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
// test aggregration
|
|
{
|
|
expr: 'sum by (foo)(some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'avg by (foo)(some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'max by (foo)(some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'sum without (foo) (some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'sum (some_metric) without (foo)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'stddev(some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'stdvar by (foo)(some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'sum by ()(some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'sum by (foo,bar,)(some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'sum by (foo,)(some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'topk(5, some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'topk( # my awesome comment\n' + '5, some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'count_values("value", some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'sum without(and, by, avg, count, alert, annotations)(some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'sum some_metric by (test)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 25,
|
|
message: 'unable to find the parameter for the expression',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
// Test function calls.
|
|
{
|
|
expr: 'time()',
|
|
expectedValueType: ValueType.scalar,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'floor(some_metric{foo!="bar"})',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'rate(some_metric[5m])',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'round(some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'round(some_metric, 5)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'floor()',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 7,
|
|
message: 'expected 1 argument(s) in call to "floor", got 0',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'floor(some_metric, other_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 32,
|
|
message: 'expected 1 argument(s) in call to "floor", got 2',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'floor(some_metric, 1)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 21,
|
|
message: 'expected 1 argument(s) in call to "floor", got 2',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'floor(1)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 6,
|
|
to: 7,
|
|
message: 'expected type vector in call to function "floor", got scalar',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'hour(some_metric, some_metric, some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 43,
|
|
message: 'expected at most 1 argument(s) in call to "hour", got 3',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'time(some_metric)',
|
|
expectedValueType: ValueType.scalar,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 17,
|
|
message: 'expected 0 argument(s) in call to "time", got 1',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'rate(some_metric)',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 5,
|
|
to: 16,
|
|
message: 'expected type matrix in call to function "rate", got vector',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr:
|
|
'histogram_quantile( # Root of the query, final result, approximates a quantile.\n' +
|
|
' 0.9, # 1st argument to histogram_quantile(), the target quantile.\n' +
|
|
' sum by(le, method, path) ( # 2nd argument to histogram_quantile(), an aggregated histogram.\n' +
|
|
' rate( # Argument to sum(), the per-second increase of a histogram over 5m.\n' +
|
|
' demo_api_request_duration_seconds_bucket{job="demo"}[5m] # Argument to rate(), the raw histogram series over the last 5m.\n' +
|
|
' )\n' +
|
|
' )\n' +
|
|
')',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr:
|
|
'histogram_fraction( # Root of the query, final result, approximates a fraction of observations within an interval.\n' +
|
|
' -Inf, # 1st argument to histogram_fraction(), start of the interval.\n' +
|
|
' 123.4, # 2nd argument to histogram_fraction(), end of the interval.\n' +
|
|
' sum by(method, path) ( # 3rd argument to histogram_fraction(), an aggregated histogram.\n' +
|
|
' rate( # Argument to sum(), the per-second increase of a histogram over 5m.\n' +
|
|
' demo_api_request_duration_seconds{job="demo"}[5m] # Argument to rate(), a vector of sparse histogram series over the last 5m.\n' +
|
|
' )\n' +
|
|
' )\n' +
|
|
')',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr:
|
|
'histogram_count( # Root of the query, final result, returns the count of observations.\n' +
|
|
' sum by(method, path) ( # Argument to histogram_count(), an aggregated histogram.\n' +
|
|
' rate( # Argument to sum(), the per-second increase of a histogram over 5m.\n' +
|
|
' demo_api_request_duration_seconds{job="demo"}[5m] # Argument to rate(), a vector of sparse histogram series over the last 5m.\n' +
|
|
' )\n' +
|
|
' )\n' +
|
|
')',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr:
|
|
'histogram_sum( # Root of the query, final result, returns the sum of observations.\n' +
|
|
' sum by(method, path) ( # Argument to histogram_sum(), an aggregated histogram.\n' +
|
|
' rate( # Argument to sum(), the per-second increase of a histogram over 5m.\n' +
|
|
' demo_api_request_duration_seconds{job="demo"}[5m] # Argument to rate(), a vector of sparse histogram series over the last 5m.\n' +
|
|
' )\n' +
|
|
' )\n' +
|
|
')',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr:
|
|
'histogram_avg( # Root of the query, final result, returns the average of observations.\n' +
|
|
' sum by(method, path) ( # Argument to histogram_avg(), an aggregated histogram.\n' +
|
|
' rate( # Argument to sum(), the per-second increase of a histogram over 5m.\n' +
|
|
' demo_api_request_duration_seconds{job="demo"}[5m] # Argument to rate(), a vector of sparse histogram series over the last 5m.\n' +
|
|
' )\n' +
|
|
' )\n' +
|
|
')',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr:
|
|
'histogram_stddev( # Root of the query, final result, returns the standard deviation of observations.\n' +
|
|
' sum by(method, path) ( # Argument to histogram_stddev(), an aggregated histogram.\n' +
|
|
' rate( # Argument to sum(), the per-second increase of a histogram over 5m.\n' +
|
|
' demo_api_request_duration_seconds{job="demo"}[5m] # Argument to rate(), a vector of sparse histogram series over the last 5m.\n' +
|
|
' )\n' +
|
|
' )\n' +
|
|
')',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr:
|
|
'histogram_stdvar( # Root of the query, final result, returns the standard variance of observations.\n' +
|
|
' sum by(method, path) ( # Argument to histogram_stdvar(), an aggregated histogram.\n' +
|
|
' rate( # Argument to sum(), the per-second increase of a histogram over 5m.\n' +
|
|
' demo_api_request_duration_seconds{job="demo"}[5m] # Argument to rate(), a vector of sparse histogram series over the last 5m.\n' +
|
|
' )\n' +
|
|
' )\n' +
|
|
')',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: '1 @ start()',
|
|
expectedValueType: ValueType.scalar,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 11,
|
|
message: '@ modifier must be preceded by an instant selector vector or range vector selector or a subquery',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: 'foo @ 879',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'food @ start()',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'food @ end()',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'sum (rate(foo[5m])) @ 456',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: '{"foo"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
// with metric name in the middle
|
|
expr: '{a="b","foo",c~="d"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: '{"foo", a="bc"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: '{"colon:in:the:middle"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: '{"dot.in.the.middle"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: '{"😀 in metric name"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
// quotes with escape
|
|
expr: '{"this is \"foo\" metric"}', // eslint-disable-line
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: '{"foo","colon:in:the:middle"="val"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: '{"foo","dot.in.the.middle"="val"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: '{"foo","😀 in label name"="val"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
// quotes with escape
|
|
expr: '{"foo","this is \"bar\" label"="val"}', // eslint-disable-line
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: 'foo{"bar"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
message: 'metric name must not be set twice: foo or bar',
|
|
severity: 'error',
|
|
to: 10,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: '{"foo", __name__="bar"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
message: 'metric name must not be set twice: foo or bar',
|
|
severity: 'error',
|
|
to: 23,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: '{"foo", "__name__"="bar"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
message: 'metric name must not be set twice: foo or bar',
|
|
severity: 'error',
|
|
to: 25,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: '{"__name__"="foo", __name__="bar"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
message: 'metric name must not be set twice: foo or bar',
|
|
severity: 'error',
|
|
to: 34,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: '{"foo", "bar"}',
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [
|
|
{
|
|
from: 0,
|
|
to: 14,
|
|
message: 'metric name must not be set twice: foo or bar',
|
|
severity: 'error',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
expr: `{'foo\`metric':'bar'}`, // eslint-disable-line
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
{
|
|
expr: '{`foo\"metric`=`bar`}', // eslint-disable-line
|
|
expectedValueType: ValueType.vector,
|
|
expectedDiag: [],
|
|
},
|
|
];
|
|
testCases.forEach((value) => {
|
|
const state = createEditorState(value.expr);
|
|
const parser = new Parser(state);
|
|
it(value.expr, () => {
|
|
expect(parser.checkAST(syntaxTree(state).topNode.firstChild)).toEqual(value.expectedValueType);
|
|
expect(parser.getDiagnostics()).toEqual(value.expectedDiag);
|
|
});
|
|
});
|
|
});
|