Like Prometheus, but for logs.
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.
loki/pkg/logql/syntax/serialize_test.go

106 lines
3.1 KiB

package syntax
import (
"bytes"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func TestJSONSerializationRoundTrip(t *testing.T) {
tests := map[string]struct {
query string
}{
"simple matchers": {
query: `{env="prod", app=~"loki.*"}`,
},
"simple aggregation": {
query: `count_over_time({env="prod", app=~"loki.*"}[5m])`,
},
"simple aggregation with unwrap": {
query: `sum_over_time({env="prod", app=~"loki.*"} | unwrap bytes[5m])`,
},
"bin op": {
query: `(count_over_time({env="prod", app=~"loki.*"}[5m]) >= 0)`,
},
"label filter": {
query: `{app="foo"} |= "bar" | json | ( latency>=250ms or ( status_code<500 , status_code>200 ) )`,
},
"regexp": {
query: `{env="prod", app=~"loki.*"} |~ ".*foo.*"`,
},
"line filter": {
query: `{env="prod", app=~"loki.*"} |= "foo" |= "bar" or "baz" | line_format "blip{{ .foo }}blop" |= "blip"`,
},
"vector matching": {
query: `(sum by (cluster)(rate({foo="bar"}[5m])) / ignoring (cluster) count(rate({foo="bar"}[5m])))`,
},
"sum over or vector": {
query: `(sum(count_over_time({foo="bar"}[5m])) or vector(1.000000))`,
},
"label replace": {
query: `label_replace(vector(0.000000),"foo","bar","","")`,
},
"filters with bytes": {
query: `{app="foo"} |= "bar" | json | ( status_code <500 or ( status_code>200 , size>=2.5KiB ) )`,
},
"post filter": {
query: `quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200)
| line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo
| __error__ !~".+"[5m]) by (namespace,instance)`,
},
"multiple post filters": {
query: `rate({app="foo"} | json | unwrap foo | latency >= 250ms or bytes > 42B or ( status_code < 500 and status_code > 200) or source = ip("") and user = "me" [1m])`,
},
"multiple post filters where one is a noop": {
query: `rate({app="foo"} | json | unwrap foo | latency >= 250ms or bytes=~".*" [1m])`,
},
"empty label filter string": {
query: `rate({app="foo"} |= "bar" | json | unwrap latency | path!="" [5m])`,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
expr, err := ParseExpr(test.query)
require.NoError(t, err)
var buf bytes.Buffer
err = EncodeJSON(expr, &buf)
require.NoError(t, err)
t.Log(buf.String())
actual, err := DecodeJSON(buf.String())
require.NoError(t, err)
require.Equal(t, expr.Pretty(0), actual.Pretty(0))
})
}
}
func TestJSONSerializationParseTestCases(t *testing.T) {
for _, tc := range ParseTestCases {
if tc.err == nil {
t.Run(tc.in, func(t *testing.T) {
ast, err := ParseExpr(tc.in)
require.NoError(t, err)
if strings.Contains(tc.in, "KiB") {
t.Skipf("Byte roundtrip conversion is broken. '%s' vs '%s'", tc.in, ast.String())
}
var buf bytes.Buffer
err = EncodeJSON(ast, &buf)
require.NoError(t, err)
actual, err := DecodeJSON(buf.String())
require.NoError(t, err)
t.Log(buf.String())
require.Equal(t, tc.exp, actual)
})
}
}
}