mirror of https://github.com/prometheus/prometheus
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.
670 lines
13 KiB
670 lines
13 KiB
// Copyright 2022 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. |
|
|
|
package parser |
|
|
|
import ( |
|
"fmt" |
|
"testing" |
|
|
|
"github.com/stretchr/testify/require" |
|
) |
|
|
|
func TestAggregateExprPretty(t *testing.T) { |
|
maxCharactersPerLine = 10 |
|
inputs := []struct { |
|
in, out string |
|
}{ |
|
{ |
|
in: `sum(foo)`, |
|
out: `sum(foo)`, |
|
}, |
|
{ |
|
in: `sum by() (task:errors:rate10s{job="s"})`, |
|
out: `sum( |
|
task:errors:rate10s{job="s"} |
|
)`, |
|
}, |
|
{ |
|
in: `sum without(job,foo) (task:errors:rate10s{job="s"})`, |
|
out: `sum without (job, foo) ( |
|
task:errors:rate10s{job="s"} |
|
)`, |
|
}, |
|
{ |
|
in: `sum(task:errors:rate10s{job="s"}) without(job,foo)`, |
|
out: `sum without (job, foo) ( |
|
task:errors:rate10s{job="s"} |
|
)`, |
|
}, |
|
{ |
|
in: `sum by(job,foo) (task:errors:rate10s{job="s"})`, |
|
out: `sum by (job, foo) ( |
|
task:errors:rate10s{job="s"} |
|
)`, |
|
}, |
|
{ |
|
in: `sum (task:errors:rate10s{job="s"}) by(job,foo)`, |
|
out: `sum by (job, foo) ( |
|
task:errors:rate10s{job="s"} |
|
)`, |
|
}, |
|
{ |
|
in: `topk(10, ask:errors:rate10s{job="s"})`, |
|
out: `topk( |
|
10, |
|
ask:errors:rate10s{job="s"} |
|
)`, |
|
}, |
|
{ |
|
in: `sum by(job,foo) (sum by(job,foo) (task:errors:rate10s{job="s"}))`, |
|
out: `sum by (job, foo) ( |
|
sum by (job, foo) ( |
|
task:errors:rate10s{job="s"} |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `sum by(job,foo) (sum by(job,foo) (sum by(job,foo) (task:errors:rate10s{job="s"})))`, |
|
out: `sum by (job, foo) ( |
|
sum by (job, foo) ( |
|
sum by (job, foo) ( |
|
task:errors:rate10s{job="s"} |
|
) |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `sum by(job,foo) |
|
(sum by(job,foo) (task:errors:rate10s{job="s"}))`, |
|
out: `sum by (job, foo) ( |
|
sum by (job, foo) ( |
|
task:errors:rate10s{job="s"} |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `sum by(job,foo) |
|
(sum(task:errors:rate10s{job="s"}) without(job,foo))`, |
|
out: `sum by (job, foo) ( |
|
sum without (job, foo) ( |
|
task:errors:rate10s{job="s"} |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `sum by(job,foo) # Comment 1. |
|
(sum by(job,foo) ( # Comment 2. |
|
task:errors:rate10s{job="s"}))`, |
|
out: `sum by (job, foo) ( |
|
sum by (job, foo) ( |
|
task:errors:rate10s{job="s"} |
|
) |
|
)`, |
|
}, |
|
} |
|
for _, test := range inputs { |
|
expr, err := ParseExpr(test.in) |
|
require.NoError(t, err) |
|
|
|
require.Equal(t, test.out, Prettify(expr)) |
|
} |
|
} |
|
|
|
func TestBinaryExprPretty(t *testing.T) { |
|
maxCharactersPerLine = 10 |
|
inputs := []struct { |
|
in, out string |
|
}{ |
|
{ |
|
in: `a+b`, |
|
out: `a + b`, |
|
}, |
|
{ |
|
in: `a == bool 1`, |
|
out: ` a |
|
== bool |
|
1`, |
|
}, |
|
{ |
|
in: `a + ignoring(job) b`, |
|
out: ` a |
|
+ ignoring (job) |
|
b`, |
|
}, |
|
{ |
|
in: `foo_1 + foo_2`, |
|
out: ` foo_1 |
|
+ |
|
foo_2`, |
|
}, |
|
{ |
|
in: `foo_1 + foo_2 + foo_3`, |
|
out: ` foo_1 |
|
+ |
|
foo_2 |
|
+ |
|
foo_3`, |
|
}, |
|
{ |
|
in: `foo + baar + foo_3`, |
|
out: ` foo + baar |
|
+ |
|
foo_3`, |
|
}, |
|
{ |
|
in: `foo_1 + foo_2 + foo_3 + foo_4`, |
|
out: ` foo_1 |
|
+ |
|
foo_2 |
|
+ |
|
foo_3 |
|
+ |
|
foo_4`, |
|
}, |
|
{ |
|
in: `foo_1 + ignoring(foo) foo_2 + ignoring(job) group_left foo_3 + on(instance) group_right foo_4`, |
|
out: ` foo_1 |
|
+ ignoring (foo) |
|
foo_2 |
|
+ ignoring (job) group_left () |
|
foo_3 |
|
+ on (instance) group_right () |
|
foo_4`, |
|
}, |
|
} |
|
for _, test := range inputs { |
|
t.Run(test.in, func(t *testing.T) { |
|
expr, err := ParseExpr(test.in) |
|
require.NoError(t, err) |
|
|
|
require.Equal(t, test.out, Prettify(expr)) |
|
}) |
|
} |
|
} |
|
|
|
func TestCallExprPretty(t *testing.T) { |
|
maxCharactersPerLine = 10 |
|
inputs := []struct { |
|
in, out string |
|
}{ |
|
{ |
|
in: `rate(foo[1m])`, |
|
out: `rate( |
|
foo[1m] |
|
)`, |
|
}, |
|
{ |
|
in: `sum_over_time(foo[1m])`, |
|
out: `sum_over_time( |
|
foo[1m] |
|
)`, |
|
}, |
|
{ |
|
in: `rate(long_vector_selector[10m:1m] @ start() offset 1m)`, |
|
out: `rate( |
|
long_vector_selector[10m:1m] @ start() offset 1m |
|
)`, |
|
}, |
|
{ |
|
in: `histogram_quantile(0.9, rate(foo[1m]))`, |
|
out: `histogram_quantile( |
|
0.9, |
|
rate( |
|
foo[1m] |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `max_over_time(rate(demo_api_request_duration_seconds_count[1m])[1m:] @ start() offset 1m)`, |
|
out: `max_over_time( |
|
rate( |
|
demo_api_request_duration_seconds_count[1m] |
|
)[1m:] @ start() offset 1m |
|
)`, |
|
}, |
|
{ |
|
in: `label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")`, |
|
out: `label_replace( |
|
up{job="api-server",service="a:c"}, |
|
"foo", |
|
"$1", |
|
"service", |
|
"(.*):.*" |
|
)`, |
|
}, |
|
{ |
|
in: `label_replace(label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*"), "foo", "$1", "service", "(.*):.*")`, |
|
out: `label_replace( |
|
label_replace( |
|
up{job="api-server",service="a:c"}, |
|
"foo", |
|
"$1", |
|
"service", |
|
"(.*):.*" |
|
), |
|
"foo", |
|
"$1", |
|
"service", |
|
"(.*):.*" |
|
)`, |
|
}, |
|
} |
|
for _, test := range inputs { |
|
expr, err := ParseExpr(test.in) |
|
require.NoError(t, err) |
|
|
|
fmt.Println("=>", expr.String()) |
|
require.Equal(t, test.out, Prettify(expr)) |
|
} |
|
} |
|
|
|
func TestParenExprPretty(t *testing.T) { |
|
maxCharactersPerLine = 10 |
|
inputs := []struct { |
|
in, out string |
|
}{ |
|
{ |
|
in: `(foo)`, |
|
out: `(foo)`, |
|
}, |
|
{ |
|
in: `(_foo_long_)`, |
|
out: `( |
|
_foo_long_ |
|
)`, |
|
}, |
|
{ |
|
in: `((foo_long))`, |
|
out: `( |
|
(foo_long) |
|
)`, |
|
}, |
|
{ |
|
in: `((_foo_long_))`, |
|
out: `( |
|
( |
|
_foo_long_ |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `(((foo_long)))`, |
|
out: `( |
|
( |
|
(foo_long) |
|
) |
|
)`, |
|
}, |
|
} |
|
for _, test := range inputs { |
|
expr, err := ParseExpr(test.in) |
|
require.NoError(t, err) |
|
|
|
require.Equal(t, test.out, Prettify(expr)) |
|
} |
|
} |
|
|
|
func TestStepInvariantExpr(t *testing.T) { |
|
maxCharactersPerLine = 10 |
|
inputs := []struct { |
|
in, out string |
|
}{ |
|
{ |
|
in: `a @ 1`, |
|
out: `a @ 1.000`, |
|
}, |
|
{ |
|
in: `a @ start()`, |
|
out: `a @ start()`, |
|
}, |
|
{ |
|
in: `vector_selector @ start()`, |
|
out: `vector_selector @ start()`, |
|
}, |
|
} |
|
for _, test := range inputs { |
|
expr, err := ParseExpr(test.in) |
|
require.NoError(t, err) |
|
|
|
require.Equal(t, test.out, Prettify(expr)) |
|
} |
|
} |
|
|
|
func TestExprPretty(t *testing.T) { |
|
maxCharactersPerLine = 10 |
|
inputs := []struct { |
|
in, out string |
|
}{ |
|
{ |
|
in: `(1 + 2)`, |
|
out: `(1 + 2)`, |
|
}, |
|
{ |
|
in: `(foo + bar)`, |
|
out: `( |
|
foo + bar |
|
)`, |
|
}, |
|
{ |
|
in: `(foo_long + bar_long)`, |
|
out: `( |
|
foo_long |
|
+ |
|
bar_long |
|
)`, |
|
}, |
|
{ |
|
in: `(foo_long + bar_long + bar_2_long)`, |
|
out: `( |
|
foo_long |
|
+ |
|
bar_long |
|
+ |
|
bar_2_long |
|
)`, |
|
}, |
|
{ |
|
in: `((foo_long + bar_long) + bar_2_long)`, |
|
out: `( |
|
( |
|
foo_long |
|
+ |
|
bar_long |
|
) |
|
+ |
|
bar_2_long |
|
)`, |
|
}, |
|
{ |
|
in: `(1111 + 2222)`, |
|
out: `( |
|
1111 |
|
+ |
|
2222 |
|
)`, |
|
}, |
|
{ |
|
in: `(sum_over_time(foo[1m]))`, |
|
out: `( |
|
sum_over_time( |
|
foo[1m] |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `histogram_quantile(0.9, rate(foo[1m] @ start()))`, |
|
out: `histogram_quantile( |
|
0.9, |
|
rate( |
|
foo[1m] @ start() |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `(label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*"))`, |
|
out: `( |
|
label_replace( |
|
up{job="api-server",service="a:c"}, |
|
"foo", |
|
"$1", |
|
"service", |
|
"(.*):.*" |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `(label_replace(label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*"), "foo", "$1", "service", "(.*):.*"))`, |
|
out: `( |
|
label_replace( |
|
label_replace( |
|
up{job="api-server",service="a:c"}, |
|
"foo", |
|
"$1", |
|
"service", |
|
"(.*):.*" |
|
), |
|
"foo", |
|
"$1", |
|
"service", |
|
"(.*):.*" |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `(label_replace(label_replace((up{job="api-server",service="a:c"}), "foo", "$1", "service", "(.*):.*"), "foo", "$1", "service", "(.*):.*"))`, |
|
out: `( |
|
label_replace( |
|
label_replace( |
|
( |
|
up{job="api-server",service="a:c"} |
|
), |
|
"foo", |
|
"$1", |
|
"service", |
|
"(.*):.*" |
|
), |
|
"foo", |
|
"$1", |
|
"service", |
|
"(.*):.*" |
|
) |
|
)`, |
|
}, |
|
// Following queries have been taken from https://monitoring.mixins.dev/ |
|
{ |
|
in: `(node_filesystem_avail_bytes{job="node",fstype!=""} / node_filesystem_size_bytes{job="node",fstype!=""} * 100 < 40 and predict_linear(node_filesystem_avail_bytes{job="node",fstype!=""}[6h], 24*60*60) < 0 and node_filesystem_readonly{job="node",fstype!=""} == 0)`, |
|
out: `( |
|
node_filesystem_avail_bytes{fstype!="",job="node"} |
|
/ |
|
node_filesystem_size_bytes{fstype!="",job="node"} |
|
* |
|
100 |
|
< |
|
40 |
|
and |
|
predict_linear( |
|
node_filesystem_avail_bytes{fstype!="",job="node"}[6h], |
|
24 * 60 |
|
* |
|
60 |
|
) |
|
< |
|
0 |
|
and |
|
node_filesystem_readonly{fstype!="",job="node"} |
|
== |
|
0 |
|
)`, |
|
}, |
|
{ |
|
in: `(node_filesystem_avail_bytes{job="node",fstype!=""} / node_filesystem_size_bytes{job="node",fstype!=""} * 100 < 20 and predict_linear(node_filesystem_avail_bytes{job="node",fstype!=""}[6h], 4*60*60) < 0 and node_filesystem_readonly{job="node",fstype!=""} == 0)`, |
|
out: `( |
|
node_filesystem_avail_bytes{fstype!="",job="node"} |
|
/ |
|
node_filesystem_size_bytes{fstype!="",job="node"} |
|
* |
|
100 |
|
< |
|
20 |
|
and |
|
predict_linear( |
|
node_filesystem_avail_bytes{fstype!="",job="node"}[6h], |
|
4 * 60 |
|
* |
|
60 |
|
) |
|
< |
|
0 |
|
and |
|
node_filesystem_readonly{fstype!="",job="node"} |
|
== |
|
0 |
|
)`, |
|
}, |
|
{ |
|
in: `(node_timex_offset_seconds > 0.05 and deriv(node_timex_offset_seconds[5m]) >= 0) or (node_timex_offset_seconds < -0.05 and deriv(node_timex_offset_seconds[5m]) <= 0)`, |
|
out: ` ( |
|
node_timex_offset_seconds |
|
> |
|
0.05 |
|
and |
|
deriv( |
|
node_timex_offset_seconds[5m] |
|
) |
|
>= |
|
0 |
|
) |
|
or |
|
( |
|
node_timex_offset_seconds |
|
< |
|
-0.05 |
|
and |
|
deriv( |
|
node_timex_offset_seconds[5m] |
|
) |
|
<= |
|
0 |
|
)`, |
|
}, |
|
{ |
|
in: `1 - ((node_memory_MemAvailable_bytes{job="node"} or (node_memory_Buffers_bytes{job="node"} + node_memory_Cached_bytes{job="node"} + node_memory_MemFree_bytes{job="node"} + node_memory_Slab_bytes{job="node"}) ) / node_memory_MemTotal_bytes{job="node"})`, |
|
out: ` 1 |
|
- |
|
( |
|
( |
|
node_memory_MemAvailable_bytes{job="node"} |
|
or |
|
( |
|
node_memory_Buffers_bytes{job="node"} |
|
+ |
|
node_memory_Cached_bytes{job="node"} |
|
+ |
|
node_memory_MemFree_bytes{job="node"} |
|
+ |
|
node_memory_Slab_bytes{job="node"} |
|
) |
|
) |
|
/ |
|
node_memory_MemTotal_bytes{job="node"} |
|
)`, |
|
}, |
|
{ |
|
in: `min by (job, integration) (rate(alertmanager_notifications_failed_total{job="alertmanager", integration=~".*"}[5m]) / rate(alertmanager_notifications_total{job="alertmanager", integration="~.*"}[5m])) > 0.01`, |
|
out: ` min by (job, integration) ( |
|
rate( |
|
alertmanager_notifications_failed_total{integration=~".*",job="alertmanager"}[5m] |
|
) |
|
/ |
|
rate( |
|
alertmanager_notifications_total{integration="~.*",job="alertmanager"}[5m] |
|
) |
|
) |
|
> |
|
0.01`, |
|
}, |
|
{ |
|
in: `(count by (job) (changes(process_start_time_seconds{job="alertmanager"}[10m]) > 4) / count by (job) (up{job="alertmanager"})) >= 0.5`, |
|
out: ` ( |
|
count by (job) ( |
|
changes( |
|
process_start_time_seconds{job="alertmanager"}[10m] |
|
) |
|
> |
|
4 |
|
) |
|
/ |
|
count by (job) ( |
|
up{job="alertmanager"} |
|
) |
|
) |
|
>= |
|
0.5`, |
|
}, |
|
} |
|
for _, test := range inputs { |
|
expr, err := ParseExpr(test.in) |
|
require.NoError(t, err) |
|
require.Equal(t, test.out, Prettify(expr)) |
|
} |
|
} |
|
|
|
func TestUnaryPretty(t *testing.T) { |
|
maxCharactersPerLine = 10 |
|
inputs := []struct { |
|
in, out string |
|
}{ |
|
{ |
|
in: `-1`, |
|
out: `-1`, |
|
}, |
|
{ |
|
in: `-vector_selector`, |
|
out: `-vector_selector`, |
|
}, |
|
{ |
|
in: `(-vector_selector)`, |
|
out: `( |
|
-vector_selector |
|
)`, |
|
}, |
|
{ |
|
in: `-histogram_quantile(0.9,rate(foo[1m]))`, |
|
out: `-histogram_quantile( |
|
0.9, |
|
rate( |
|
foo[1m] |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `-histogram_quantile(0.99, sum by (le) (rate(foo[1m])))`, |
|
out: `-histogram_quantile( |
|
0.99, |
|
sum by (le) ( |
|
rate( |
|
foo[1m] |
|
) |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `-histogram_quantile(0.9, -rate(foo[1m] @ start()))`, |
|
out: `-histogram_quantile( |
|
0.9, |
|
-rate( |
|
foo[1m] @ start() |
|
) |
|
)`, |
|
}, |
|
{ |
|
in: `(-histogram_quantile(0.9, -rate(foo[1m] @ start())))`, |
|
out: `( |
|
-histogram_quantile( |
|
0.9, |
|
-rate( |
|
foo[1m] @ start() |
|
) |
|
) |
|
)`, |
|
}, |
|
} |
|
for _, test := range inputs { |
|
t.Run(test.in, func(t *testing.T) { |
|
expr, err := ParseExpr(test.in) |
|
require.NoError(t, err) |
|
require.Equal(t, test.out, Prettify(expr)) |
|
}) |
|
} |
|
}
|
|
|