Alerting: Add doc comments to classic.go (#56724)
This commit is contained in:
+99
-69
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user