2021-12-14 07:36:47 -06:00
import { AbstractLabelOperator , AbstractQuery } from '@grafana/data' ;
2022-04-22 08:33:13 -05:00
2021-09-30 08:50:02 -05:00
import {
escapeLabelValueInExactSelector ,
escapeLabelValueInRegexSelector ,
expandRecordingRules ,
fixSummariesMetadata ,
parseSelector ,
2021-12-14 07:36:47 -06:00
toPromLikeQuery ,
2021-09-30 08:50:02 -05:00
} from './language_utils' ;
2018-08-10 07:45:09 -05:00
describe ( 'parseSelector()' , ( ) = > {
let parsed ;
2018-08-06 07:36:02 -05:00
it ( 'returns a clean selector from an empty selector' , ( ) = > {
2018-08-10 07:45:09 -05:00
parsed = parseSelector ( '{}' , 1 ) ;
expect ( parsed . selector ) . toBe ( '{}' ) ;
expect ( parsed . labelKeys ) . toEqual ( [ ] ) ;
2018-08-06 07:36:02 -05:00
} ) ;
2018-08-10 07:45:09 -05:00
2021-01-08 11:31:21 -06:00
it ( 'returns a clean selector from an unclosed selector' , ( ) = > {
const parsed = parseSelector ( '{foo' ) ;
expect ( parsed . selector ) . toBe ( '{}' ) ;
2018-08-06 07:36:02 -05:00
} ) ;
2018-08-10 07:45:09 -05:00
2018-08-06 07:36:02 -05:00
it ( 'returns the selector sorted by label key' , ( ) = > {
2018-08-10 07:45:09 -05:00
parsed = parseSelector ( '{foo="bar"}' ) ;
expect ( parsed . selector ) . toBe ( '{foo="bar"}' ) ;
expect ( parsed . labelKeys ) . toEqual ( [ 'foo' ] ) ;
parsed = parseSelector ( '{foo="bar",baz="xx"}' ) ;
expect ( parsed . selector ) . toBe ( '{baz="xx",foo="bar"}' ) ;
2018-08-06 07:36:02 -05:00
} ) ;
2018-08-10 07:45:09 -05:00
2018-08-06 07:36:02 -05:00
it ( 'returns a clean selector from an incomplete one' , ( ) = > {
2018-08-10 07:45:09 -05:00
parsed = parseSelector ( '{foo}' ) ;
expect ( parsed . selector ) . toBe ( '{}' ) ;
parsed = parseSelector ( '{foo="bar",baz}' ) ;
expect ( parsed . selector ) . toBe ( '{foo="bar"}' ) ;
parsed = parseSelector ( '{foo="bar",baz="}' ) ;
expect ( parsed . selector ) . toBe ( '{foo="bar"}' ) ;
2019-12-31 01:56:57 -06:00
// Cursor in value area counts as incomplete
parsed = parseSelector ( '{foo="bar",baz=""}' , 16 ) ;
expect ( parsed . selector ) . toBe ( '{foo="bar"}' ) ;
parsed = parseSelector ( '{foo="bar",baz="4"}' , 17 ) ;
expect ( parsed . selector ) . toBe ( '{foo="bar"}' ) ;
2018-08-06 07:36:02 -05:00
} ) ;
2018-08-10 07:45:09 -05:00
2018-08-06 07:36:02 -05:00
it ( 'throws if not inside a selector' , ( ) = > {
2018-08-10 07:45:09 -05:00
expect ( ( ) = > parseSelector ( 'foo{}' , 0 ) ) . toThrow ( ) ;
expect ( ( ) = > parseSelector ( 'foo{} + bar{}' , 5 ) ) . toThrow ( ) ;
2018-08-06 07:36:02 -05:00
} ) ;
2018-08-10 07:45:09 -05:00
2018-08-06 07:36:02 -05:00
it ( 'returns the selector nearest to the cursor offset' , ( ) = > {
2018-08-10 07:45:09 -05:00
expect ( ( ) = > parseSelector ( '{foo="bar"} + {foo="bar"}' , 0 ) ) . toThrow ( ) ;
parsed = parseSelector ( '{foo="bar"} + {foo="bar"}' , 1 ) ;
expect ( parsed . selector ) . toBe ( '{foo="bar"}' ) ;
parsed = parseSelector ( '{foo="bar"} + {baz="xx"}' , 1 ) ;
expect ( parsed . selector ) . toBe ( '{foo="bar"}' ) ;
parsed = parseSelector ( '{baz="xx"} + {foo="bar"}' , 16 ) ;
expect ( parsed . selector ) . toBe ( '{foo="bar"}' ) ;
2018-08-06 07:36:02 -05:00
} ) ;
2018-08-10 07:45:09 -05:00
2018-08-06 07:36:02 -05:00
it ( 'returns a selector with metric if metric is given' , ( ) = > {
2018-08-10 07:45:09 -05:00
parsed = parseSelector ( 'bar{foo}' , 4 ) ;
expect ( parsed . selector ) . toBe ( '{__name__="bar"}' ) ;
2019-12-31 01:56:57 -06:00
parsed = parseSelector ( 'baz{foo="bar"}' , 13 ) ;
2018-08-10 07:45:09 -05:00
expect ( parsed . selector ) . toBe ( '{__name__="baz",foo="bar"}' ) ;
2018-09-19 05:01:02 -05:00
parsed = parseSelector ( 'bar:metric:1m{}' , 14 ) ;
expect ( parsed . selector ) . toBe ( '{__name__="bar:metric:1m"}' ) ;
2018-08-06 07:36:02 -05:00
} ) ;
} ) ;
2018-11-16 08:31:51 -06:00
2020-05-07 05:02:45 -05:00
describe ( 'fixSummariesMetadata' , ( ) = > {
2021-05-28 07:51:06 -05:00
const synthetics = {
2021-09-21 08:19:52 -05:00
ALERTS : {
type : 'counter' ,
2022-02-02 06:02:32 -06:00
help : 'Time series showing pending and firing alerts. The sample value is set to 1 as long as the alert is in the indicated active (pending or firing) state.' ,
2021-09-21 08:19:52 -05:00
} ,
2021-05-28 07:51:06 -05:00
} ;
it ( 'returns only synthetics on empty metadata' , ( ) = > {
expect ( fixSummariesMetadata ( { } ) ) . toEqual ( { . . . synthetics } ) ;
2020-05-07 05:02:45 -05:00
} ) ;
it ( 'returns unchanged metadata if no summary is present' , ( ) = > {
2021-09-21 08:19:52 -05:00
const metadataRaw = {
2020-05-07 05:02:45 -05:00
foo : [ { type : 'not_a_summary' , help : 'foo help' } ] ,
} ;
2021-09-21 08:19:52 -05:00
const metadata = {
foo : { type : 'not_a_summary' , help : 'foo help' } ,
} ;
expect ( fixSummariesMetadata ( metadataRaw ) ) . toEqual ( { . . . metadata , . . . synthetics } ) ;
2020-05-07 05:02:45 -05:00
} ) ;
it ( 'returns metadata with added count and sum for a summary' , ( ) = > {
const metadata = {
foo : [ { type : 'not_a_summary' , help : 'foo help' } ] ,
bar : [ { type : 'summary' , help : 'bar help' } ] ,
} ;
const expected = {
2021-09-21 08:19:52 -05:00
foo : { type : 'not_a_summary' , help : 'foo help' } ,
bar : { type : 'summary' , help : 'bar help' } ,
bar_count : { type : 'counter' , help : 'Count of events that have been observed for the base metric (bar help)' } ,
bar_sum : { type : 'counter' , help : 'Total sum of all observed values for the base metric (bar help)' } ,
2020-05-07 05:02:45 -05:00
} ;
2021-05-28 07:51:06 -05:00
expect ( fixSummariesMetadata ( metadata ) ) . toEqual ( { . . . expected , . . . synthetics } ) ;
} ) ;
it ( 'returns metadata with added bucket/count/sum for a histogram' , ( ) = > {
const metadata = {
foo : [ { type : 'not_a_histogram' , help : 'foo help' } ] ,
bar : [ { type : 'histogram' , help : 'bar help' } ] ,
} ;
const expected = {
2021-09-21 08:19:52 -05:00
foo : { type : 'not_a_histogram' , help : 'foo help' } ,
bar : { type : 'histogram' , help : 'bar help' } ,
bar_bucket : { type : 'counter' , help : 'Cumulative counters for the observation buckets (bar help)' } ,
bar_count : {
type : 'counter' ,
help : 'Count of events that have been observed for the histogram metric (bar help)' ,
} ,
bar_sum : { type : 'counter' , help : 'Total sum of all observed values for the histogram metric (bar help)' } ,
2021-05-28 07:51:06 -05:00
} ;
expect ( fixSummariesMetadata ( metadata ) ) . toEqual ( { . . . expected , . . . synthetics } ) ;
2020-05-07 05:02:45 -05:00
} ) ;
} ) ;
2018-11-16 08:31:51 -06:00
describe ( 'expandRecordingRules()' , ( ) = > {
it ( 'returns query w/o recording rules as is' , ( ) = > {
expect ( expandRecordingRules ( 'metric' , { } ) ) . toBe ( 'metric' ) ;
expect ( expandRecordingRules ( 'metric + metric' , { } ) ) . toBe ( 'metric + metric' ) ;
expect ( expandRecordingRules ( 'metric{}' , { } ) ) . toBe ( 'metric{}' ) ;
} ) ;
it ( 'does not modify recording rules name in label values' , ( ) = > {
expect ( expandRecordingRules ( '{__name__="metric"} + bar' , { metric : 'foo' , bar : 'super' } ) ) . toBe (
'{__name__="metric"} + super'
) ;
} ) ;
it ( 'returns query with expanded recording rules' , ( ) = > {
expect ( expandRecordingRules ( 'metric' , { metric : 'foo' } ) ) . toBe ( 'foo' ) ;
expect ( expandRecordingRules ( 'metric + metric' , { metric : 'foo' } ) ) . toBe ( 'foo + foo' ) ;
expect ( expandRecordingRules ( 'metric{}' , { metric : 'foo' } ) ) . toBe ( 'foo{}' ) ;
expect ( expandRecordingRules ( 'metric[]' , { metric : 'foo' } ) ) . toBe ( 'foo[]' ) ;
expect ( expandRecordingRules ( 'metric + foo' , { metric : 'foo' , foo : 'bar' } ) ) . toBe ( 'foo + bar' ) ;
} ) ;
2020-05-22 08:16:01 -05:00
it ( 'returns query with labels with expanded recording rules' , ( ) = > {
expect (
expandRecordingRules ( 'metricA{label1="value1"} / metricB{label2="value2"}' , { metricA : 'fooA' , metricB : 'fooB' } )
) . toBe ( 'fooA{label1="value1"} / fooB{label2="value2"}' ) ;
expect (
expandRecordingRules ( 'metricA{label1="value1",label2="value,2"}' , {
metricA : 'rate(fooA[])' ,
} )
2022-03-15 11:37:20 -05:00
) . toBe ( 'rate(fooA{label1="value1", label2="value,2"}[])' ) ;
2020-05-22 08:16:01 -05:00
expect (
expandRecordingRules ( 'metricA{label1="value1"} / metricB{label2="value2"}' , {
metricA : 'rate(fooA[])' ,
metricB : 'rate(fooB[])' ,
} )
) . toBe ( 'rate(fooA{label1="value1"}[])/ rate(fooB{label2="value2"}[])' ) ;
expect (
expandRecordingRules ( 'metricA{label1="value1",label2="value2"} / metricB{label3="value3"}' , {
metricA : 'rate(fooA[])' ,
metricB : 'rate(fooB[])' ,
} )
2022-03-15 11:37:20 -05:00
) . toBe ( 'rate(fooA{label1="value1", label2="value2"}[])/ rate(fooB{label3="value3"}[])' ) ;
2020-05-22 08:16:01 -05:00
} ) ;
2018-11-16 08:31:51 -06:00
} ) ;
2021-09-30 08:50:02 -05:00
describe ( 'escapeLabelValueInExactSelector()' , ( ) = > {
it ( 'handles newline characters' , ( ) = > {
expect ( escapeLabelValueInExactSelector ( 't\nes\nt' ) ) . toBe ( 't\\nes\\nt' ) ;
} ) ;
it ( 'handles backslash characters' , ( ) = > {
expect ( escapeLabelValueInExactSelector ( 't\\es\\t' ) ) . toBe ( 't\\\\es\\\\t' ) ;
} ) ;
it ( 'handles double-quote characters' , ( ) = > {
expect ( escapeLabelValueInExactSelector ( 't"es"t' ) ) . toBe ( 't\\"es\\"t' ) ;
} ) ;
it ( 'handles all together' , ( ) = > {
expect ( escapeLabelValueInExactSelector ( 't\\e"st\nl\nab"e\\l' ) ) . toBe ( 't\\\\e\\"st\\nl\\nab\\"e\\\\l' ) ;
} ) ;
} ) ;
describe ( 'escapeLabelValueInRegexSelector()' , ( ) = > {
it ( 'handles newline characters' , ( ) = > {
expect ( escapeLabelValueInRegexSelector ( 't\nes\nt' ) ) . toBe ( 't\\nes\\nt' ) ;
} ) ;
it ( 'handles backslash characters' , ( ) = > {
expect ( escapeLabelValueInRegexSelector ( 't\\es\\t' ) ) . toBe ( 't\\\\\\\\es\\\\\\\\t' ) ;
} ) ;
it ( 'handles double-quote characters' , ( ) = > {
expect ( escapeLabelValueInRegexSelector ( 't"es"t' ) ) . toBe ( 't\\"es\\"t' ) ;
} ) ;
it ( 'handles regex-meaningful characters' , ( ) = > {
expect ( escapeLabelValueInRegexSelector ( 't+es$t' ) ) . toBe ( 't\\\\+es\\\\$t' ) ;
} ) ;
it ( 'handles all together' , ( ) = > {
expect ( escapeLabelValueInRegexSelector ( 't\\e"s+t\nl\n$ab"e\\l' ) ) . toBe (
't\\\\\\\\e\\"s\\\\+t\\nl\\n\\\\$ab\\"e\\\\\\\\l'
) ;
} ) ;
} ) ;
2021-12-14 07:36:47 -06:00
describe ( 'toPromLikeQuery' , ( ) = > {
it ( 'export abstract query to PromQL-like query' , ( ) = > {
const abstractQuery : AbstractQuery = {
refId : 'bar' ,
labelMatchers : [
{ name : 'label1' , operator : AbstractLabelOperator.Equal , value : 'value1' } ,
{ name : 'label2' , operator : AbstractLabelOperator.NotEqual , value : 'value2' } ,
{ name : 'label3' , operator : AbstractLabelOperator.EqualRegEx , value : 'value3' } ,
{ name : 'label4' , operator : AbstractLabelOperator.NotEqualRegEx , value : 'value4' } ,
] ,
} ;
expect ( toPromLikeQuery ( abstractQuery ) ) . toMatchObject ( {
refId : 'bar' ,
expr : '{label1="value1", label2!="value2", label3=~"value3", label4!~"value4"}' ,
range : true ,
} ) ;
} ) ;
} ) ;