Alerting: Fix handling of special floating-point cases when writing observed values to annotations (#61074)
* Fix json serialization of state values * Simplify two of the tests * Fix linter complaint * Don't return error if we fail to look up dashboard, just log it and move on * Address linter complaint
This commit is contained in:
@@ -2,6 +2,8 @@ package historian
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -12,7 +14,10 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/annotations"
|
||||
"github.com/grafana/grafana/pkg/services/annotations/annotationstest"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/eval"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/state"
|
||||
history_model "github.com/grafana/grafana/pkg/services/ngalert/state/historian/model"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/tests/fakes"
|
||||
)
|
||||
|
||||
@@ -64,8 +69,70 @@ func withOrgID(orgId int64) func(rule *models.AlertRule) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildAnnotations(t *testing.T) {
|
||||
t.Run("data wraps nil values when values are nil", func(t *testing.T) {
|
||||
logger := log.NewNopLogger()
|
||||
rule := history_model.RuleMeta{}
|
||||
states := []state.StateTransition{makeStateTransition()}
|
||||
states[0].State.Values = nil
|
||||
|
||||
items := buildAnnotations(rule, states, logger)
|
||||
|
||||
require.Len(t, items, 1)
|
||||
j := assertValidJSON(t, items[0].Data)
|
||||
require.JSONEq(t, `{"values": null}`, j)
|
||||
})
|
||||
|
||||
t.Run("data approximately contains expected values", func(t *testing.T) {
|
||||
logger := log.NewNopLogger()
|
||||
rule := history_model.RuleMeta{}
|
||||
states := []state.StateTransition{makeStateTransition()}
|
||||
states[0].State.Values = map[string]float64{"a": 1.0, "b": 2.0}
|
||||
|
||||
items := buildAnnotations(rule, states, logger)
|
||||
|
||||
require.Len(t, items, 1)
|
||||
assertValidJSON(t, items[0].Data)
|
||||
// Since we're comparing floats, avoid require.JSONEq to avoid intermittency caused by floating point rounding.
|
||||
vs := items[0].Data.MustMap()["values"]
|
||||
require.NotNil(t, vs)
|
||||
vals := vs.(*simplejson.Json).MustMap()
|
||||
require.InDelta(t, 1.0, vals["a"], 0.1)
|
||||
require.InDelta(t, 2.0, vals["b"], 0.1)
|
||||
})
|
||||
|
||||
t.Run("data handles special float values", func(t *testing.T) {
|
||||
logger := log.NewNopLogger()
|
||||
rule := history_model.RuleMeta{}
|
||||
states := []state.StateTransition{makeStateTransition()}
|
||||
states[0].State.Values = map[string]float64{"nan": math.NaN(), "inf": math.Inf(1), "ninf": math.Inf(-1)}
|
||||
|
||||
items := buildAnnotations(rule, states, logger)
|
||||
|
||||
require.Len(t, items, 1)
|
||||
j := assertValidJSON(t, items[0].Data)
|
||||
require.JSONEq(t, `{"values": {"nan": "NaN", "inf": "+Inf", "ninf": "-Inf"}}`, j)
|
||||
})
|
||||
}
|
||||
|
||||
func makeStateTransition() state.StateTransition {
|
||||
return state.StateTransition{
|
||||
State: &state.State{
|
||||
State: eval.Alerting,
|
||||
},
|
||||
PreviousState: eval.Normal,
|
||||
}
|
||||
}
|
||||
|
||||
func withUID(uid string) func(rule *models.AlertRule) {
|
||||
return func(rule *models.AlertRule) {
|
||||
rule.UID = uid
|
||||
}
|
||||
}
|
||||
|
||||
func assertValidJSON(t *testing.T, j *simplejson.Json) string {
|
||||
require.NotNil(t, j)
|
||||
ser, err := json.Marshal(j)
|
||||
require.NoError(t, err)
|
||||
return string(ser)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user