Files
grafana/pkg/services/ngalert/state/cache_test.go
T
Grot (@grafanabot) 0d2a01f03f [v9.4.x] Alerting: Fix Classic Conditions $values variable (#64249)
Alerting: Fix Classic Conditions $values variable (#64243)

This commit fixes a bug in the $values variable in notification
templates when using Classic Conditions. Since Classic Conditions
are not multi-dimensional, the values of each series that exceeded
the condition should be available as a RefID and offset. For example,
B0, B1, etc. However, this bug meant that instead just a single
condition would be printed as B, not B0.

(cherry picked from commit ed71012ced)

Co-authored-by: George Robinson <george.robinson@grafana.com>
2023-03-06 12:33:30 -05:00

201 lines
6.2 KiB
Go

package state
import (
"context"
"fmt"
"net/url"
"testing"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/xorcare/pointer"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/util"
)
func Test_getOrCreate(t *testing.T) {
url := &url.URL{
Scheme: "http",
Host: "localhost:3000",
Path: "/test",
}
l := log.New("test")
c := newCache()
generateRule := models.AlertRuleGen(models.WithNotEmptyLabels(5, "rule-"))
t.Run("should combine all labels", func(t *testing.T) {
rule := generateRule()
extraLabels := models.GenerateAlertLabels(5, "extra-")
result := eval.Result{
Instance: models.GenerateAlertLabels(5, "result-"),
}
state := c.getOrCreate(context.Background(), l, rule, result, extraLabels, url)
for key, expected := range extraLabels {
require.Equal(t, expected, state.Labels[key])
}
assert.Len(t, state.Labels, len(extraLabels)+len(rule.Labels)+len(result.Instance))
for key, expected := range extraLabels {
assert.Equal(t, expected, state.Labels[key])
}
for key, expected := range rule.Labels {
assert.Equal(t, expected, state.Labels[key])
}
for key, expected := range result.Instance {
assert.Equal(t, expected, state.Labels[key])
}
})
t.Run("extra labels should take precedence over rule and result labels", func(t *testing.T) {
rule := generateRule()
extraLabels := models.GenerateAlertLabels(2, "extra-")
result := eval.Result{
Instance: models.GenerateAlertLabels(5, "result-"),
}
for key := range extraLabels {
rule.Labels[key] = "rule-" + util.GenerateShortUID()
result.Instance[key] = "result-" + util.GenerateShortUID()
}
state := c.getOrCreate(context.Background(), l, rule, result, extraLabels, url)
for key, expected := range extraLabels {
require.Equal(t, expected, state.Labels[key])
}
})
t.Run("rule labels should take precedence over result labels", func(t *testing.T) {
rule := generateRule()
extraLabels := models.GenerateAlertLabels(2, "extra-")
result := eval.Result{
Instance: models.GenerateAlertLabels(5, "result-"),
}
for key := range rule.Labels {
result.Instance[key] = "result-" + util.GenerateShortUID()
}
state := c.getOrCreate(context.Background(), l, rule, result, extraLabels, url)
for key, expected := range rule.Labels {
require.Equal(t, expected, state.Labels[key])
}
})
t.Run("rule labels should be able to be expanded with result and extra labels", func(t *testing.T) {
result := eval.Result{
Instance: models.GenerateAlertLabels(5, "result-"),
}
rule := generateRule()
extraLabels := models.GenerateAlertLabels(2, "extra-")
labelTemplates := make(data.Labels)
for key := range extraLabels {
labelTemplates["rule-"+key] = fmt.Sprintf("{{ with (index .Labels \"%s\") }}{{.}}{{end}}", key)
}
for key := range result.Instance {
labelTemplates["rule-"+key] = fmt.Sprintf("{{ with (index .Labels \"%s\") }}{{.}}{{end}}", key)
}
rule.Labels = labelTemplates
state := c.getOrCreate(context.Background(), l, rule, result, extraLabels, url)
for key, expected := range extraLabels {
assert.Equal(t, expected, state.Labels["rule-"+key])
}
for key, expected := range result.Instance {
assert.Equal(t, expected, state.Labels["rule-"+key])
}
})
t.Run("rule annotations should be able to be expanded with result and extra labels", func(t *testing.T) {
result := eval.Result{
Instance: models.GenerateAlertLabels(5, "result-"),
}
rule := generateRule()
extraLabels := models.GenerateAlertLabels(2, "extra-")
annotationTemplates := make(data.Labels)
for key := range extraLabels {
annotationTemplates["rule-"+key] = fmt.Sprintf("{{ with (index .Labels \"%s\") }}{{.}}{{end}}", key)
}
for key := range result.Instance {
annotationTemplates["rule-"+key] = fmt.Sprintf("{{ with (index .Labels \"%s\") }}{{.}}{{end}}", key)
}
rule.Annotations = annotationTemplates
state := c.getOrCreate(context.Background(), l, rule, result, extraLabels, url)
for key, expected := range extraLabels {
assert.Equal(t, expected, state.Annotations["rule-"+key])
}
for key, expected := range result.Instance {
assert.Equal(t, expected, state.Annotations["rule-"+key])
}
})
t.Run("expected Reduce and Math expression values", func(t *testing.T) {
result := eval.Result{
Instance: models.GenerateAlertLabels(5, "result-"),
Values: map[string]eval.NumberValueCapture{
"A": eval.NumberValueCapture{Var: "A", Value: pointer.Float64(1.0)},
"B": eval.NumberValueCapture{Var: "B", Value: pointer.Float64(2.0)},
},
}
rule := generateRule()
state := c.getOrCreate(context.Background(), l, rule, result, nil, url)
assert.Equal(t, map[string]float64{"A": 1, "B": 2}, state.Values)
})
t.Run("expected Classic Condition values", func(t *testing.T) {
result := eval.Result{
Instance: models.GenerateAlertLabels(5, "result-"),
Values: map[string]eval.NumberValueCapture{
"B0": eval.NumberValueCapture{Var: "B", Value: pointer.Float64(1.0)},
"B1": eval.NumberValueCapture{Var: "B", Value: pointer.Float64(2.0)},
},
}
rule := generateRule()
state := c.getOrCreate(context.Background(), l, rule, result, nil, url)
assert.Equal(t, map[string]float64{"B0": 1, "B1": 2}, state.Values)
})
}
func Test_mergeLabels(t *testing.T) {
t.Run("merges two maps", func(t *testing.T) {
a := models.GenerateAlertLabels(5, "set1-")
b := models.GenerateAlertLabels(5, "set2-")
result := mergeLabels(a, b)
require.Len(t, result, len(a)+len(b))
for key, val := range a {
require.Equal(t, val, result[key])
}
for key, val := range b {
require.Equal(t, val, result[key])
}
})
t.Run("first set take precedence if conflict", func(t *testing.T) {
a := models.GenerateAlertLabels(5, "set1-")
b := models.GenerateAlertLabels(5, "set2-")
c := b.Copy()
for key, val := range a {
c[key] = "set2-" + val
}
result := mergeLabels(a, c)
require.Len(t, result, len(a)+len(b))
for key, val := range a {
require.Equal(t, val, result[key])
}
for key, val := range b {
require.Equal(t, val, result[key])
}
})
}