123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- import { buildVisualQueryFromString } from './parsing';
- import { PromVisualQuery } from './types';
- describe('buildVisualQueryFromString', () => {
- it('creates no errors for empty query', () => {
- expect(buildVisualQueryFromString('')).toEqual(
- noErrors({
- labels: [],
- operations: [],
- metric: '',
- })
- );
- });
- 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 query with aggregation without labels', () => {
- const visQuery = {
- metric: 'metric_name',
- labels: [
- {
- label: 'instance',
- op: '=',
- value: 'internal:3000',
- },
- ],
- operations: [
- {
- id: '__sum_without',
- params: ['app', 'version'],
- },
- ],
- };
- expect(buildVisualQueryFromString('sum(metric_name{instance="internal:3000"}) without (app, version)')).toEqual(
- noErrors(visQuery)
- );
- expect(buildVisualQueryFromString('sum without (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 argument', () => {
- expect(
- buildVisualQueryFromString('histogram_quantile(0.99, rate(counters_logins{app="backend"}[$__rate_interval]))')
- ).toEqual(
- noErrors({
- metric: 'counters_logins',
- labels: [{ label: 'app', op: '=', value: 'backend' }],
- operations: [
- {
- id: 'rate',
- params: ['$__rate_interval'],
- },
- {
- id: 'histogram_quantile',
- params: [0.99],
- },
- ],
- })
- );
- });
- 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: [],
- },
- });
- });
- it('parses query without metric', () => {
- expect(buildVisualQueryFromString('label_replace(rate([$__rate_interval]), "", "$1", "", "(.*)")')).toEqual({
- errors: [],
- query: {
- metric: '',
- labels: [],
- operations: [
- { id: 'rate', params: ['$__rate_interval'] },
- {
- id: 'label_replace',
- params: ['', '$1', '', '(.*)'],
- },
- ],
- },
- });
- });
- it('lone aggregation without params', () => {
- expect(buildVisualQueryFromString('sum()')).toEqual({
- errors: [],
- query: {
- metric: '',
- labels: [],
- operations: [{ id: 'sum', params: [] }],
- },
- });
- });
- it('handles multiple binary scalar operations', () => {
- expect(buildVisualQueryFromString('cluster_namespace_slug_dialer_name + 1 - 1 / 1 * 1 % 1 ^ 1')).toEqual({
- errors: [],
- query: {
- metric: 'cluster_namespace_slug_dialer_name',
- labels: [],
- operations: [
- {
- id: '__addition',
- params: [1],
- },
- {
- id: '__subtraction',
- params: [1],
- },
- {
- id: '__divide_by',
- params: [1],
- },
- {
- id: '__multiply_by',
- params: [1],
- },
- {
- id: '__modulo',
- params: [1],
- },
- {
- id: '__exponent',
- params: [1],
- },
- ],
- },
- });
- });
- it('handles scalar comparison operators', () => {
- expect(buildVisualQueryFromString('cluster_namespace_slug_dialer_name <= 2.5')).toEqual({
- errors: [],
- query: {
- metric: 'cluster_namespace_slug_dialer_name',
- labels: [],
- operations: [
- {
- id: '__less_or_equal',
- params: [2.5, false],
- },
- ],
- },
- });
- });
- it('handles bool with comparison operator', () => {
- expect(buildVisualQueryFromString('cluster_namespace_slug_dialer_name <= bool 2')).toEqual({
- errors: [],
- query: {
- metric: 'cluster_namespace_slug_dialer_name',
- labels: [],
- operations: [
- {
- id: '__less_or_equal',
- params: [2, true],
- },
- ],
- },
- });
- });
- it('handles multiple binary operations', () => {
- expect(buildVisualQueryFromString('foo{x="yy"} * metric{y="zz",a="bb"} * metric2')).toEqual({
- errors: [],
- query: {
- metric: 'foo',
- labels: [{ label: 'x', op: '=', value: 'yy' }],
- operations: [],
- binaryQueries: [
- {
- operator: '*',
- query: {
- metric: 'metric',
- labels: [
- { label: 'y', op: '=', value: 'zz' },
- { label: 'a', op: '=', value: 'bb' },
- ],
- operations: [],
- },
- },
- {
- operator: '*',
- query: {
- metric: 'metric2',
- labels: [],
- operations: [],
- },
- },
- ],
- },
- });
- });
- it('handles multiple binary operations and scalar', () => {
- expect(buildVisualQueryFromString('foo{x="yy"} * metric{y="zz",a="bb"} * 2')).toEqual({
- errors: [],
- query: {
- metric: 'foo',
- labels: [{ label: 'x', op: '=', value: 'yy' }],
- operations: [
- {
- id: '__multiply_by',
- params: [2],
- },
- ],
- binaryQueries: [
- {
- operator: '*',
- query: {
- metric: 'metric',
- labels: [
- { label: 'y', op: '=', value: 'zz' },
- { label: 'a', op: '=', value: 'bb' },
- ],
- operations: [],
- },
- },
- ],
- },
- });
- });
- it('handles binary operation with vector matchers', () => {
- expect(buildVisualQueryFromString('foo * on(foo, bar) metric')).toEqual({
- errors: [],
- query: {
- metric: 'foo',
- labels: [],
- operations: [],
- binaryQueries: [
- {
- operator: '*',
- vectorMatches: 'foo, bar',
- vectorMatchesType: 'on',
- query: { metric: 'metric', labels: [], operations: [] },
- },
- ],
- },
- });
- expect(buildVisualQueryFromString('foo * ignoring(foo) metric')).toEqual({
- errors: [],
- query: {
- metric: 'foo',
- labels: [],
- operations: [],
- binaryQueries: [
- {
- operator: '*',
- vectorMatches: 'foo',
- vectorMatchesType: 'ignoring',
- query: { metric: 'metric', labels: [], operations: [] },
- },
- ],
- },
- });
- });
- it('reports error on parenthesis', () => {
- expect(buildVisualQueryFromString('foo / (bar + baz)')).toEqual({
- errors: [
- {
- from: 6,
- parentType: 'Expr',
- text: '(bar + baz)',
- to: 17,
- },
- ],
- query: {
- metric: 'foo',
- labels: [],
- operations: [],
- binaryQueries: [
- {
- operator: '/',
- query: {
- binaryQueries: [{ operator: '+', query: { labels: [], metric: 'baz', operations: [] } }],
- metric: 'bar',
- labels: [],
- operations: [],
- },
- },
- ],
- },
- });
- });
- });
- function noErrors(query: PromVisualQuery) {
- return {
- errors: [],
- query,
- };
- }
|