The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
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.
 
 
 
 
 
 
grafana/pkg/promlib/models/scope_test.go

212 lines
5.9 KiB

package models
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
tests := []struct {
name string
query string
adhocFilters []ScopeFilter
scopeFilters []ScopeFilter
expected string
expectErr bool
}{
{
name: "No filters with no existing filter",
query: `http_requests_total`,
expected: `http_requests_total`,
expectErr: false,
},
{
name: "No filters with existing filter",
query: `http_requests_total{job="prometheus"}`,
expected: `http_requests_total{job="prometheus"}`,
expectErr: false,
},
{
name: "Adhoc filter with existing filter",
query: `http_requests_total{job="prometheus"}`,
adhocFilters: []ScopeFilter{
{Key: "method", Value: "get", Operator: FilterOperatorEquals},
},
expected: `http_requests_total{job="prometheus",method="get"}`,
expectErr: false,
},
{
name: "Adhoc filter with no existing filter",
query: `http_requests_total`,
adhocFilters: []ScopeFilter{
{Key: "method", Value: "get", Operator: FilterOperatorEquals},
{Key: "job", Value: "prometheus", Operator: FilterOperatorEquals},
},
expected: `http_requests_total{job="prometheus",method="get"}`,
expectErr: false,
},
{
name: "Scope filter",
query: `http_requests_total{job="prometheus"}`,
scopeFilters: []ScopeFilter{
{Key: "status", Value: "200", Operator: FilterOperatorEquals},
},
expected: `http_requests_total{job="prometheus",status="200"}`,
expectErr: false,
},
{
name: "Adhoc and Scope filter no existing filter",
query: `http_requests_total`,
scopeFilters: []ScopeFilter{
{Key: "status", Value: "200", Operator: FilterOperatorEquals},
},
adhocFilters: []ScopeFilter{
{Key: "job", Value: "prometheus", Operator: FilterOperatorEquals},
},
expected: `http_requests_total{job="prometheus",status="200"}`,
expectErr: false,
},
{
name: "Adhoc and Scope filter conflict - adhoc wins (if not oneOf or notOneOf)",
query: `http_requests_total{job="prometheus"}`,
scopeFilters: []ScopeFilter{
{Key: "status", Value: "404", Operator: FilterOperatorEquals},
},
adhocFilters: []ScopeFilter{
{Key: "status", Value: "200", Operator: FilterOperatorEquals},
},
expected: `http_requests_total{job="prometheus",status="200"}`,
expectErr: false,
},
{
name: "Adhoc filters with more complex expression",
query: `capacity_bytes{job="prometheus"} + available_bytes{job="grafana"} / 1024`,
adhocFilters: []ScopeFilter{
{Key: "job", Value: "alloy", Operator: FilterOperatorEquals},
},
expected: `capacity_bytes{job="alloy"} + available_bytes{job="alloy"} / 1024`,
expectErr: false,
},
{
name: "OneOf Operator is combined into a single regex filter",
query: `http_requests_total{job="prometheus"}`,
scopeFilters: []ScopeFilter{
{Key: "status", Values: []string{"404", "400"}, Operator: FilterOperatorOneOf},
},
expected: `http_requests_total{job="prometheus",status=~"404|400"}`,
expectErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expr, err := ApplyFiltersAndGroupBy(tt.query, tt.scopeFilters, tt.adhocFilters, nil)
if tt.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tt.expected, expr)
}
})
}
}
func TestApplyQueryFiltersAndGroupBy_GroupBy(t *testing.T) {
tests := []struct {
name string
query string
groupBy []string
expected string
expectErr bool
}{
{
name: "GroupBy with no aggregate expression",
groupBy: []string{"job"},
query: `http_requests_total`,
expected: `http_requests_total`,
expectErr: false,
},
{
name: "No GroupBy with aggregate expression",
query: `sum by () (http_requests_total)`,
expected: `sum(http_requests_total)`,
expectErr: false,
},
{
name: "GroupBy with aggregate expression with no existing group by",
groupBy: []string{"job"},
query: `sum(http_requests_total)`,
expected: `sum by (job) (http_requests_total)`,
expectErr: false,
},
{
name: "GroupBy with aggregate expression with existing group by",
groupBy: []string{"status"},
query: `sum by (job) (http_requests_total)`,
expected: `sum by (job, status) (http_requests_total)`,
expectErr: false,
},
{
name: "GroupBy with aggregate expression with existing group by (already exists)",
groupBy: []string{"job"},
query: `sum by (job) (http_requests_total)`,
expected: `sum by (job) (http_requests_total)`,
expectErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expr, err := ApplyFiltersAndGroupBy(tt.query, nil, nil, tt.groupBy)
if tt.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, expr, tt.expected)
}
})
}
}
func TestApplyQueryFiltersAndGroupBy(t *testing.T) {
tests := []struct {
name string
query string
adhocFilters []ScopeFilter
scopeFilters []ScopeFilter
groupby []string
expected string
expectErr bool
}{
{
name: "Adhoc filters with more complex expression",
query: `sum(capacity_bytes{job="prometheus"} + available_bytes{job="grafana"}) / 1024`,
adhocFilters: []ScopeFilter{
{Key: "job", Value: "alloy", Operator: FilterOperatorEquals},
},
scopeFilters: []ScopeFilter{
{Key: "vol", Value: "/", Operator: FilterOperatorEquals},
},
groupby: []string{"job"},
expected: `sum by (job) (capacity_bytes{job="alloy",vol="/"} + available_bytes{job="alloy",vol="/"}) / 1024`,
expectErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expr, err := ApplyFiltersAndGroupBy(tt.query, tt.scopeFilters, tt.adhocFilters, tt.groupby)
if tt.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, expr, tt.expected)
}
})
}
}