Alerting: Add doc comments to classic.go (#56724)

This commit is contained in:
George Robinson
2022-10-12 10:55:48 +01:00
committed by GitHub
parent dd9e1498f9
commit 67d93ceea0
4 changed files with 153 additions and 121 deletions
+99 -69
View File
@@ -11,92 +11,71 @@ import (
"github.com/grafana/grafana/pkg/expr/mathexp" "github.com/grafana/grafana/pkg/expr/mathexp"
) )
// ConditionsCmd is command for the classic conditions // ConditionsCmd is a command that supports the reduction and comparison of conditions.
// expression operation. //
// A condition in ConditionsCmd can reduce a time series, contain an instant metric, or the
// result of another expression; and checks if it exceeds a threshold, falls within a range,
// or does not contain a value.
//
// If ConditionsCmd contains more than one condition, it reduces the boolean outcomes of the
// threshold, range or value checks using the logical operator of the right hand side condition
// until all conditions have been reduced to a single boolean outcome. ConditionsCmd does not
// follow operator precedence.
//
// For example if we have the following classic condition:
//
// min(A) > 5 OR max(B) < 10 AND C = 1
//
// which reduces to the following boolean outcomes:
//
// false OR true AND true
//
// then the outcome of ConditionsCmd is true.
type ConditionsCmd struct { type ConditionsCmd struct {
Conditions []condition Conditions []condition
refID string RefID string
} }
// ClassicConditionJSON is the JSON model for a single condition. // condition is a single condition in ConditionsCmd.
// It is based on services/alerting/conditions/query.go's newQueryCondition().
type ClassicConditionJSON struct {
Evaluator ConditionEvalJSON `json:"evaluator"`
Operator struct {
Type string `json:"type"`
} `json:"operator"`
Query struct {
Params []string `json:"params"`
} `json:"query"`
Reducer struct {
// Params []interface{} `json:"params"` (Unused)
Type string `json:"type"`
} `json:"reducer"`
}
type ConditionEvalJSON struct {
Params []float64 `json:"params"`
Type string `json:"type"` // e.g. "gt"
}
// condition is a single condition within the ConditionsCmd.
type condition struct { type condition struct {
QueryRefID string InputRefID string
Reducer classicReducer
Evaluator evaluator
Operator string
}
type classicReducer string // Reducer reduces a series of data into a single result. An example of a reducer is the avg,
// min and max functions.
Reducer reducer
// Evaluator evaluates the reduced time series, instant metric, or result of another expression
// against an evaluator. An example of an evaluator is checking if it exceeds a threshold,
// falls within a range, or does not contain a value.
Evaluator evaluator
// Operator is the logical operator to use when there are two conditions in ConditionsCmd.
// If there are more than two conditions in ConditionsCmd then operator is used to compare
// the outcome of this condition with that of the condition before it.
Operator string
}
// NeedsVars returns the variable names (refIds) that are dependencies // NeedsVars returns the variable names (refIds) that are dependencies
// to execute the command and allows the command to fulfill the Command interface. // to execute the command and allows the command to fulfill the Command interface.
func (ccc *ConditionsCmd) NeedsVars() []string { func (cmd *ConditionsCmd) NeedsVars() []string {
vars := []string{} vars := []string{}
for _, c := range ccc.Conditions { for _, c := range cmd.Conditions {
vars = append(vars, c.QueryRefID) vars = append(vars, c.InputRefID)
} }
return vars return vars
} }
// EvalMatch represents the series violating the threshold.
// It goes into the metadata of data frames so it can be extracted.
type EvalMatch struct {
Value *float64 `json:"value"`
Metric string `json:"metric"`
Labels data.Labels `json:"labels"`
}
func (em EvalMatch) MarshalJSON() ([]byte, error) {
fs := ""
if em.Value != nil {
fs = strconv.FormatFloat(*em.Value, 'f', -1, 64)
}
return json.Marshal(struct {
Value string `json:"value"`
Metric string `json:"metric"`
Labels data.Labels `json:"labels"`
}{
fs,
em.Metric,
em.Labels,
})
}
// Execute runs the command and returns the results or an error if the command // Execute runs the command and returns the results or an error if the command
// failed to execute. // failed to execute.
func (ccc *ConditionsCmd) Execute(ctx context.Context, vars mathexp.Vars) (mathexp.Results, error) { func (cmd *ConditionsCmd) Execute(_ context.Context, vars mathexp.Vars) (mathexp.Results, error) {
firing := true firing := true
newRes := mathexp.Results{} newRes := mathexp.Results{}
noDataFound := true noDataFound := true
matches := []EvalMatch{} matches := []EvalMatch{}
for i, c := range ccc.Conditions { for i, c := range cmd.Conditions {
querySeriesSet := vars[c.QueryRefID] querySeriesSet := vars[c.InputRefID]
nilReducedCount := 0 nilReducedCount := 0
firingCount := 0 firingCount := 0
for _, val := range querySeriesSet.Values { for _, val := range querySeriesSet.Values {
@@ -184,19 +163,70 @@ func (ccc *ConditionsCmd) Execute(ctx context.Context, vars mathexp.Vars) (mathe
return newRes, nil return newRes, nil
} }
// EvalMatch represents the series violating the threshold.
// It goes into the metadata of data frames so it can be extracted.
type EvalMatch struct {
Value *float64 `json:"value"`
Metric string `json:"metric"`
Labels data.Labels `json:"labels"`
}
func (em EvalMatch) MarshalJSON() ([]byte, error) {
fs := ""
if em.Value != nil {
fs = strconv.FormatFloat(*em.Value, 'f', -1, 64)
}
return json.Marshal(struct {
Value string `json:"value"`
Metric string `json:"metric"`
Labels data.Labels `json:"labels"`
}{
fs,
em.Metric,
em.Labels,
})
}
// ConditionJSON is the JSON model for a single condition in ConditionsCmd.
// It is based on services/alerting/conditions/query.go's newQueryCondition().
type ConditionJSON struct {
Evaluator ConditionEvalJSON `json:"evaluator"`
Operator ConditionOperatorJSON `json:"operator"`
Query ConditionQueryJSON `json:"query"`
Reducer ConditionReducerJSON `json:"reducer"`
}
type ConditionEvalJSON struct {
Params []float64 `json:"params"`
Type string `json:"type"` // e.g. "gt"
}
type ConditionOperatorJSON struct {
Type string `json:"type"`
}
type ConditionQueryJSON struct {
Params []string `json:"params"`
}
type ConditionReducerJSON struct {
Type string `json:"type"`
// Params []interface{} `json:"params"` (Unused)
}
// UnmarshalConditionsCmd creates a new ConditionsCmd. // UnmarshalConditionsCmd creates a new ConditionsCmd.
func UnmarshalConditionsCmd(rawQuery map[string]interface{}, refID string) (*ConditionsCmd, error) { func UnmarshalConditionsCmd(rawQuery map[string]interface{}, refID string) (*ConditionsCmd, error) {
jsonFromM, err := json.Marshal(rawQuery["conditions"]) jsonFromM, err := json.Marshal(rawQuery["conditions"])
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to remarshal classic condition body: %w", err) return nil, fmt.Errorf("failed to remarshal classic condition body: %w", err)
} }
var ccj []ClassicConditionJSON var ccj []ConditionJSON
if err = json.Unmarshal(jsonFromM, &ccj); err != nil { if err = json.Unmarshal(jsonFromM, &ccj); err != nil {
return nil, fmt.Errorf("failed to unmarshal remarshaled classic condition body: %w", err) return nil, fmt.Errorf("failed to unmarshal remarshaled classic condition body: %w", err)
} }
c := &ConditionsCmd{ c := &ConditionsCmd{
refID: refID, RefID: refID,
} }
for i, cj := range ccj { for i, cj := range ccj {
@@ -208,12 +238,12 @@ func UnmarshalConditionsCmd(rawQuery map[string]interface{}, refID string) (*Con
cond.Operator = cj.Operator.Type cond.Operator = cj.Operator.Type
if len(cj.Query.Params) == 0 || cj.Query.Params[0] == "" { if len(cj.Query.Params) == 0 || cj.Query.Params[0] == "" {
return nil, fmt.Errorf("condition %v is missing the query refID argument", i+1) return nil, fmt.Errorf("condition %v is missing the query RefID argument", i+1)
} }
cond.QueryRefID = cj.Query.Params[0] cond.InputRefID = cj.Query.Params[0]
cond.Reducer = classicReducer(cj.Reducer.Type) cond.Reducer = reducer(cj.Reducer.Type)
if !cond.Reducer.ValidReduceFunc() { if !cond.Reducer.ValidReduceFunc() {
return nil, fmt.Errorf("invalid reducer '%v' in condition %v", cond.Reducer, i+1) return nil, fmt.Errorf("invalid reducer '%v' in condition %v", cond.Reducer, i+1)
} }
+26 -26
View File
@@ -49,8 +49,8 @@ func TestUnmarshalConditionCMD(t *testing.T) {
expectedCommand: &ConditionsCmd{ expectedCommand: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("avg"), Reducer: reducer("avg"),
Operator: "and", Operator: "and",
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 2}, Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 2},
}, },
@@ -89,8 +89,8 @@ func TestUnmarshalConditionCMD(t *testing.T) {
expectedCommand: &ConditionsCmd{ expectedCommand: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("diff"), Reducer: reducer("diff"),
Operator: "or", Operator: "or",
Evaluator: &rangedEvaluator{Type: "within_range", Lower: 2, Upper: 3}, Evaluator: &rangedEvaluator{Type: "within_range", Lower: 2, Upper: 3},
}, },
@@ -134,8 +134,8 @@ func TestConditionsCmdExecute(t *testing.T) {
conditionsCmd: &ConditionsCmd{ conditionsCmd: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("avg"), Reducer: reducer("avg"),
Operator: "and", Operator: "and",
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34}, Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34},
}, },
@@ -158,8 +158,8 @@ func TestConditionsCmdExecute(t *testing.T) {
conditionsCmd: &ConditionsCmd{ conditionsCmd: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("avg"), Reducer: reducer("avg"),
Operator: "and", Operator: "and",
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34}, Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34},
}, },
@@ -183,8 +183,8 @@ func TestConditionsCmdExecute(t *testing.T) {
conditionsCmd: &ConditionsCmd{ conditionsCmd: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("avg"), Reducer: reducer("avg"),
Operator: "and", Operator: "and",
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: .5}, Evaluator: &thresholdEvaluator{Type: "gt", Threshold: .5},
}, },
@@ -207,13 +207,13 @@ func TestConditionsCmdExecute(t *testing.T) {
conditionsCmd: &ConditionsCmd{ conditionsCmd: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("max"), Reducer: reducer("max"),
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34}, Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34},
}, },
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("min"), Reducer: reducer("min"),
Operator: "or", Operator: "or",
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 12}, Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 12},
}, },
@@ -237,8 +237,8 @@ func TestConditionsCmdExecute(t *testing.T) {
conditionsCmd: &ConditionsCmd{ conditionsCmd: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("avg"), Reducer: reducer("avg"),
Operator: "and", Operator: "and",
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34}, Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34},
}, },
@@ -262,8 +262,8 @@ func TestConditionsCmdExecute(t *testing.T) {
conditionsCmd: &ConditionsCmd{ conditionsCmd: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("avg"), Reducer: reducer("avg"),
Operator: "and", Operator: "and",
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34}, Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34},
}, },
@@ -287,8 +287,8 @@ func TestConditionsCmdExecute(t *testing.T) {
conditionsCmd: &ConditionsCmd{ conditionsCmd: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("avg"), Reducer: reducer("avg"),
Operator: "and", Operator: "and",
Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34}, Evaluator: &thresholdEvaluator{Type: "gt", Threshold: 34},
}, },
@@ -311,8 +311,8 @@ func TestConditionsCmdExecute(t *testing.T) {
conditionsCmd: &ConditionsCmd{ conditionsCmd: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("diff"), Reducer: reducer("diff"),
Operator: "and", Operator: "and",
Evaluator: &rangedEvaluator{Type: "within_range", Lower: 2, Upper: 3}, Evaluator: &rangedEvaluator{Type: "within_range", Lower: 2, Upper: 3},
}, },
@@ -334,8 +334,8 @@ func TestConditionsCmdExecute(t *testing.T) {
conditionsCmd: &ConditionsCmd{ conditionsCmd: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("avg"), Reducer: reducer("avg"),
Operator: "and", Operator: "and",
Evaluator: &thresholdEvaluator{"gt", 1}, Evaluator: &thresholdEvaluator{"gt", 1},
}, },
@@ -361,8 +361,8 @@ func TestConditionsCmdExecute(t *testing.T) {
conditionsCmd: &ConditionsCmd{ conditionsCmd: &ConditionsCmd{
Conditions: []condition{ Conditions: []condition{
{ {
QueryRefID: "A", InputRefID: "A",
Reducer: classicReducer("avg"), Reducer: reducer("avg"),
Operator: "and", Operator: "and",
Evaluator: &thresholdEvaluator{"gt", 1}, Evaluator: &thresholdEvaluator{"gt", 1},
}, },
+7 -5
View File
@@ -7,11 +7,9 @@ import (
"github.com/grafana/grafana/pkg/expr/mathexp" "github.com/grafana/grafana/pkg/expr/mathexp"
) )
func nilOrNaN(f *float64) bool { type reducer string
return f == nil || math.IsNaN(*f)
}
func (cr classicReducer) ValidReduceFunc() bool { func (cr reducer) ValidReduceFunc() bool {
switch cr { switch cr {
case "avg", "sum", "min", "max", "count", "last", "median": case "avg", "sum", "min", "max", "count", "last", "median":
return true return true
@@ -22,7 +20,7 @@ func (cr classicReducer) ValidReduceFunc() bool {
} }
//nolint:gocyclo //nolint:gocyclo
func (cr classicReducer) Reduce(series mathexp.Series) mathexp.Number { func (cr reducer) Reduce(series mathexp.Series) mathexp.Number {
num := mathexp.NewNumber("", nil) num := mathexp.NewNumber("", nil)
if series.GetLabels() != nil { if series.GetLabels() != nil {
@@ -184,6 +182,10 @@ func calculateDiff(ff mathexp.Float64Field, allNull bool, value float64, fn func
return allNull, value return allNull, value
} }
func nilOrNaN(f *float64) bool {
return f == nil || math.IsNaN(*f)
}
var diff = func(newest, oldest float64) float64 { var diff = func(newest, oldest float64) float64 {
return newest - oldest return newest - oldest
} }
+21 -21
View File
@@ -14,103 +14,103 @@ import (
func TestReducer(t *testing.T) { func TestReducer(t *testing.T) {
var tests = []struct { var tests = []struct {
name string name string
reducer classicReducer reducer reducer
inputSeries mathexp.Series inputSeries mathexp.Series
expectedNumber mathexp.Number expectedNumber mathexp.Number
}{ }{
{ {
name: "sum", name: "sum",
reducer: classicReducer("sum"), reducer: reducer("sum"),
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)), inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)),
expectedNumber: valBasedNumber(ptr.Float64(6)), expectedNumber: valBasedNumber(ptr.Float64(6)),
}, },
{ {
name: "min", name: "min",
reducer: classicReducer("min"), reducer: reducer("min"),
inputSeries: valBasedSeries(ptr.Float64(3), ptr.Float64(2), ptr.Float64(1)), inputSeries: valBasedSeries(ptr.Float64(3), ptr.Float64(2), ptr.Float64(1)),
expectedNumber: valBasedNumber(ptr.Float64(1)), expectedNumber: valBasedNumber(ptr.Float64(1)),
}, },
{ {
name: "min with NaNs only", name: "min with NaNs only",
reducer: classicReducer("min"), reducer: reducer("min"),
inputSeries: valBasedSeries(ptr.Float64(math.NaN()), ptr.Float64(math.NaN()), ptr.Float64(math.NaN())), inputSeries: valBasedSeries(ptr.Float64(math.NaN()), ptr.Float64(math.NaN()), ptr.Float64(math.NaN())),
expectedNumber: valBasedNumber(nil), expectedNumber: valBasedNumber(nil),
}, },
{ {
name: "max", name: "max",
reducer: classicReducer("max"), reducer: reducer("max"),
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)), inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)),
expectedNumber: valBasedNumber(ptr.Float64(3)), expectedNumber: valBasedNumber(ptr.Float64(3)),
}, },
{ {
name: "count", name: "count",
reducer: classicReducer("count"), reducer: reducer("count"),
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3000)), inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3000)),
expectedNumber: valBasedNumber(ptr.Float64(3)), expectedNumber: valBasedNumber(ptr.Float64(3)),
}, },
{ {
name: "last", name: "last",
reducer: classicReducer("last"), reducer: reducer("last"),
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3000)), inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3000)),
expectedNumber: valBasedNumber(ptr.Float64(3000)), expectedNumber: valBasedNumber(ptr.Float64(3000)),
}, },
{ {
name: "median with odd amount of numbers", name: "median with odd amount of numbers",
reducer: classicReducer("median"), reducer: reducer("median"),
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3000)), inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3000)),
expectedNumber: valBasedNumber(ptr.Float64(2)), expectedNumber: valBasedNumber(ptr.Float64(2)),
}, },
{ {
name: "median with even amount of numbers", name: "median with even amount of numbers",
reducer: classicReducer("median"), reducer: reducer("median"),
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(4), ptr.Float64(3000)), inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(4), ptr.Float64(3000)),
expectedNumber: valBasedNumber(ptr.Float64(3)), expectedNumber: valBasedNumber(ptr.Float64(3)),
}, },
{ {
name: "median with one value", name: "median with one value",
reducer: classicReducer("median"), reducer: reducer("median"),
inputSeries: valBasedSeries(ptr.Float64(1)), inputSeries: valBasedSeries(ptr.Float64(1)),
expectedNumber: valBasedNumber(ptr.Float64(1)), expectedNumber: valBasedNumber(ptr.Float64(1)),
}, },
{ {
name: "median should ignore null values", name: "median should ignore null values",
reducer: classicReducer("median"), reducer: reducer("median"),
inputSeries: valBasedSeries(nil, nil, nil, ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)), inputSeries: valBasedSeries(nil, nil, nil, ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)),
expectedNumber: valBasedNumber(ptr.Float64(2)), expectedNumber: valBasedNumber(ptr.Float64(2)),
}, },
{ {
name: "avg", name: "avg",
reducer: classicReducer("avg"), reducer: reducer("avg"),
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)), inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)),
expectedNumber: valBasedNumber(ptr.Float64(2)), expectedNumber: valBasedNumber(ptr.Float64(2)),
}, },
{ {
name: "avg with only nulls", name: "avg with only nulls",
reducer: classicReducer("avg"), reducer: reducer("avg"),
inputSeries: valBasedSeries(nil), inputSeries: valBasedSeries(nil),
expectedNumber: valBasedNumber(nil), expectedNumber: valBasedNumber(nil),
}, },
{ {
name: "avg of number values and null values should ignore nulls", name: "avg of number values and null values should ignore nulls",
reducer: classicReducer("avg"), reducer: reducer("avg"),
inputSeries: valBasedSeries(ptr.Float64(3), nil, nil, ptr.Float64(3)), inputSeries: valBasedSeries(ptr.Float64(3), nil, nil, ptr.Float64(3)),
expectedNumber: valBasedNumber(ptr.Float64(3)), expectedNumber: valBasedNumber(ptr.Float64(3)),
}, },
{ {
name: "count_non_null with mixed null/real values", name: "count_non_null with mixed null/real values",
reducer: classicReducer("count_non_null"), reducer: reducer("count_non_null"),
inputSeries: valBasedSeries(nil, nil, ptr.Float64(3), ptr.Float64(4)), inputSeries: valBasedSeries(nil, nil, ptr.Float64(3), ptr.Float64(4)),
expectedNumber: valBasedNumber(ptr.Float64(2)), expectedNumber: valBasedNumber(ptr.Float64(2)),
}, },
{ {
name: "count_non_null with mixed null/real values", name: "count_non_null with mixed null/real values",
reducer: classicReducer("count_non_null"), reducer: reducer("count_non_null"),
inputSeries: valBasedSeries(nil, nil, ptr.Float64(3), ptr.Float64(4)), inputSeries: valBasedSeries(nil, nil, ptr.Float64(3), ptr.Float64(4)),
expectedNumber: valBasedNumber(ptr.Float64(2)), expectedNumber: valBasedNumber(ptr.Float64(2)),
}, },
{ {
name: "count_non_null with no values", name: "count_non_null with no values",
reducer: classicReducer("count_non_null"), reducer: reducer("count_non_null"),
inputSeries: valBasedSeries(nil, nil), inputSeries: valBasedSeries(nil, nil),
expectedNumber: valBasedNumber(nil), expectedNumber: valBasedNumber(nil),
}, },
@@ -189,7 +189,7 @@ func TestDiffReducer(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
num := classicReducer("diff").Reduce(tt.inputSeries) num := reducer("diff").Reduce(tt.inputSeries)
require.Equal(t, tt.expectedNumber, num) require.Equal(t, tt.expectedNumber, num)
}) })
} }
@@ -259,7 +259,7 @@ func TestDiffAbsReducer(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
num := classicReducer("diff_abs").Reduce(tt.inputSeries) num := reducer("diff_abs").Reduce(tt.inputSeries)
require.Equal(t, tt.expectedNumber, num) require.Equal(t, tt.expectedNumber, num)
}) })
} }
@@ -329,7 +329,7 @@ func TestPercentDiffReducer(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
num := classicReducer("percent_diff").Reduce(tt.inputSeries) num := reducer("percent_diff").Reduce(tt.inputSeries)
require.Equal(t, tt.expectedNumber, num) require.Equal(t, tt.expectedNumber, num)
}) })
} }
@@ -399,7 +399,7 @@ func TestPercentDiffAbsReducer(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
num := classicReducer("percent_diff_abs").Reduce(tt.inputSeries) num := reducer("percent_diff_abs").Reduce(tt.inputSeries)
require.Equal(t, tt.expectedNumber, num) require.Equal(t, tt.expectedNumber, num)
}) })
} }