mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			751 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			751 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
package classic
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"encoding/json"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/grafana/grafana-plugin-sdk-go/data"
 | 
						|
	"github.com/stretchr/testify/require"
 | 
						|
 | 
						|
	"github.com/grafana/grafana/pkg/expr/mathexp"
 | 
						|
	"github.com/grafana/grafana/pkg/infra/tracing"
 | 
						|
	"github.com/grafana/grafana/pkg/util"
 | 
						|
)
 | 
						|
 | 
						|
func TestConditionsCmd(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name     string
 | 
						|
		cmd      *ConditionsCmd
 | 
						|
		vars     mathexp.Vars
 | 
						|
		expected func() mathexp.Results
 | 
						|
	}{{
 | 
						|
		// This test asserts that a single query with condition returns 0 and no matches as the condition
 | 
						|
		// is not met
 | 
						|
		name: "single query with condition when condition is not met",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(util.Pointer(1.0), util.Pointer(5.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 2},
 | 
						|
				},
 | 
						|
			}},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(0.0))
 | 
						|
			v.SetMeta([]EvalMatch{})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		// This test asserts that a single query with condition returns 1 and the average in the meta as
 | 
						|
		// the condition is met
 | 
						|
		name: "single query with condition when condition is met",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(util.Pointer(1.0), util.Pointer(5.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("avg"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 2},
 | 
						|
				},
 | 
						|
			}},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: util.Pointer(3.0)}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single query with ranged condition when condition is not met",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(util.Pointer(1.0), util.Pointer(5.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("diff"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &rangedEvaluator{Type: "within_range", Lower: 2, Upper: 4},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(0.0))
 | 
						|
			v.SetMeta([]EvalMatch{})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single query with ranged condition when condition is met",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(util.Pointer(1.0), util.Pointer(5.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("diff"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &rangedEvaluator{Type: "within_range", Lower: 0, Upper: 10},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: util.Pointer(4.0)}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single no data query with condition is No Data",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{mathexp.NoData{}.New()},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(nil)
 | 
						|
			v.SetMeta([]EvalMatch{{Metric: "NoData"}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single no values query with condition is No Data",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(nil)
 | 
						|
			v.SetMeta([]EvalMatch{{Metric: "NoData"}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single series no points query with condition returns No Data",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(nil),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(nil)
 | 
						|
			v.SetMeta([]EvalMatch{{Metric: "NoData"}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single no data query with condition is met has no value",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{mathexp.NoData{}.New()},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &noValueEvaluator{},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: nil}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single no values query with condition is met has no value",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &noValueEvaluator{},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: nil}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single series no points query with condition is met has no value",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(nil),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &noValueEvaluator{},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: nil}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		// This test asserts that a single query with condition returns 1 and the average of the second
 | 
						|
		// series in the meta because while the first series is No Data the second series contains valid points
 | 
						|
		name: "single query with condition returns average when one series is no data and the other contains valid points",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(),
 | 
						|
					newSeries(util.Pointer(2.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 1},
 | 
						|
				},
 | 
						|
			}},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: util.Pointer(2.0)}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single query with condition and no series matches condition",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(util.Pointer(1.0), util.Pointer(5.0)),
 | 
						|
					newSeries(util.Pointer(2.0), util.Pointer(10.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 15},
 | 
						|
				},
 | 
						|
			}},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(0.0))
 | 
						|
			v.SetMeta([]EvalMatch{})
 | 
						|
			return mathexp.Results{Values: mathexp.Values{v}}
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single query with condition and one of two series matches condition",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(util.Pointer(1.0), util.Pointer(5.0)),
 | 
						|
					newSeriesWithLabels(data.Labels{"foo": "bar"}, util.Pointer(2.0), util.Pointer(10.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 1},
 | 
						|
				},
 | 
						|
			}},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: util.Pointer(2.0), Labels: data.Labels{"foo": "bar"}}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single query with condition and both series matches condition",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(util.Pointer(1.0), util.Pointer(5.0)),
 | 
						|
					newSeriesWithLabels(data.Labels{"foo": "bar"}, util.Pointer(2.0), util.Pointer(10.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 0},
 | 
						|
				},
 | 
						|
			}},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{
 | 
						|
				Value: util.Pointer(1.0),
 | 
						|
			}, {
 | 
						|
				Value:  util.Pointer(2.0),
 | 
						|
				Labels: data.Labels{"foo": "bar"},
 | 
						|
			}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single query with two conditions where left hand side is met",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(util.Pointer(1.0), util.Pointer(5.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("max"),
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 2},
 | 
						|
				},
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "or",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 1},
 | 
						|
				},
 | 
						|
			}},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: util.Pointer(5.0)}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single query with two conditions where right hand side is met",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(util.Pointer(1.0), util.Pointer(5.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("max"),
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 10},
 | 
						|
				},
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "or",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 0},
 | 
						|
				},
 | 
						|
			}},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: util.Pointer(1.0)}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single query with two conditions where both are met",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(util.Pointer(1.0), util.Pointer(5.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("max"),
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 2},
 | 
						|
				},
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "or",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 0},
 | 
						|
				},
 | 
						|
			}},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: util.Pointer(5.0)}, {Value: util.Pointer(1.0)}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "single instant query with condition where condition is met",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newNumber(util.Pointer(5.0)),
 | 
						|
					newNumber(util.Pointer(10.0)),
 | 
						|
					newNumber(util.Pointer(15.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("avg"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{
 | 
						|
				{Value: util.Pointer(5.0)},
 | 
						|
				{Value: util.Pointer(10.0)},
 | 
						|
				{Value: util.Pointer(15.0)},
 | 
						|
			})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "two queries with two conditions using and operator and first is No Data",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{mathexp.NoData{}.New()},
 | 
						|
			},
 | 
						|
			"B": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{newSeries(util.Pointer(5.0))},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
				{
 | 
						|
					InputRefID: "B",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(0.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Metric: "NoData"}, {Value: util.Pointer(5.0)}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "two queries with two conditions using and operator and last is No Data",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{newSeries(util.Pointer(5.0))},
 | 
						|
			},
 | 
						|
			"B": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{mathexp.NoData{}.New()},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
				{
 | 
						|
					InputRefID: "B",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(0.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: util.Pointer(5.0)}, {Metric: "NoData"}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "two queries with two conditions using or operator and first is No Data",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{mathexp.NoData{}.New()},
 | 
						|
			},
 | 
						|
			"B": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{newSeries(util.Pointer(5.0))},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "or",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
				{
 | 
						|
					InputRefID: "B",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "or",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(nil)
 | 
						|
			v.SetMeta([]EvalMatch{{Metric: "NoData"}, {Value: util.Pointer(5.0)}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "two queries with two conditions using or operator and last is No Data",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{newSeries(util.Pointer(5.0))},
 | 
						|
			},
 | 
						|
			"B": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{mathexp.NoData{}.New()},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "or",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
				{
 | 
						|
					InputRefID: "B",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "or",
 | 
						|
					Evaluator:  &thresholdEvaluator{"gt", 1},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(nil)
 | 
						|
			v.SetMeta([]EvalMatch{{Value: util.Pointer(5.0)}, {Metric: "NoData"}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}, {
 | 
						|
		name: "LogicOr will stop subsequent logic checks in condition: true AND true LogicOr false AND false",
 | 
						|
		vars: mathexp.Vars{
 | 
						|
			"A": mathexp.Results{
 | 
						|
				Values: []mathexp.Value{
 | 
						|
					newSeries(util.Pointer(1.0), util.Pointer(5.0)),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		cmd: &ConditionsCmd{
 | 
						|
			Conditions: []condition{
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("max"),
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 2},
 | 
						|
				},
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("min"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 0},
 | 
						|
				},
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("avg"),
 | 
						|
					Operator:   "logic-or",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 6},
 | 
						|
				},
 | 
						|
				{
 | 
						|
					InputRefID: "A",
 | 
						|
					Reducer:    reducer("last"),
 | 
						|
					Operator:   "and",
 | 
						|
					Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 6},
 | 
						|
				},
 | 
						|
			}},
 | 
						|
		expected: func() mathexp.Results {
 | 
						|
			v := newNumber(util.Pointer(1.0))
 | 
						|
			v.SetMeta([]EvalMatch{{Value: util.Pointer(5.0)}, {Value: util.Pointer(1.0)}})
 | 
						|
			return newResults(v)
 | 
						|
		},
 | 
						|
	}}
 | 
						|
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			res, err := tt.cmd.Execute(context.Background(), time.Now(), tt.vars, tracing.InitializeTracerForTest(), nil)
 | 
						|
			require.NoError(t, err)
 | 
						|
			require.Equal(t, tt.expected(), res)
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestUnmarshalConditionsCmd(t *testing.T) {
 | 
						|
	var tests = []struct {
 | 
						|
		name            string
 | 
						|
		rawJSON         string
 | 
						|
		expectedCommand *ConditionsCmd
 | 
						|
		needsVars       []string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "basic threshold condition",
 | 
						|
			rawJSON: `{
 | 
						|
				"conditions": [
 | 
						|
				  {
 | 
						|
					"evaluator": {
 | 
						|
					  "params": [
 | 
						|
						2
 | 
						|
					  ],
 | 
						|
					  "type": "gt"
 | 
						|
					},
 | 
						|
					"operator": {
 | 
						|
					  "type": "and"
 | 
						|
					},
 | 
						|
					"query": {
 | 
						|
					  "params": [
 | 
						|
						"A"
 | 
						|
					  ]
 | 
						|
					},
 | 
						|
					"reducer": {
 | 
						|
					  "params": [],
 | 
						|
					  "type": "avg"
 | 
						|
					},
 | 
						|
					"type": "query"
 | 
						|
				  }
 | 
						|
				]
 | 
						|
			}`,
 | 
						|
			expectedCommand: &ConditionsCmd{
 | 
						|
				Conditions: []condition{
 | 
						|
					{
 | 
						|
						InputRefID: "A",
 | 
						|
						Reducer:    reducer("avg"),
 | 
						|
						Operator:   "and",
 | 
						|
						Evaluator:  &thresholdEvaluator{Type: "gt", Threshold: 2},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			needsVars: []string{"A"},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "ranged condition",
 | 
						|
			rawJSON: `{
 | 
						|
				"conditions": [
 | 
						|
				  {
 | 
						|
					"evaluator": {
 | 
						|
					  "params": [
 | 
						|
						2,
 | 
						|
						3
 | 
						|
					  ],
 | 
						|
					  "type": "within_range"
 | 
						|
					},
 | 
						|
					"operator": {
 | 
						|
					  "type": "or"
 | 
						|
					},
 | 
						|
					"query": {
 | 
						|
					  "params": [
 | 
						|
						"A"
 | 
						|
					  ]
 | 
						|
					},
 | 
						|
					"reducer": {
 | 
						|
					  "params": [],
 | 
						|
					  "type": "diff"
 | 
						|
					},
 | 
						|
					"type": "query"
 | 
						|
				  }
 | 
						|
				]
 | 
						|
			}`,
 | 
						|
			expectedCommand: &ConditionsCmd{
 | 
						|
				Conditions: []condition{
 | 
						|
					{
 | 
						|
						InputRefID: "A",
 | 
						|
						Reducer:    reducer("diff"),
 | 
						|
						Operator:   "or",
 | 
						|
						Evaluator:  &rangedEvaluator{Type: "within_range", Lower: 2, Upper: 3},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			needsVars: []string{"A"},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			var rq map[string]any
 | 
						|
 | 
						|
			err := json.Unmarshal([]byte(tt.rawJSON), &rq)
 | 
						|
			require.NoError(t, err)
 | 
						|
 | 
						|
			cmd, err := UnmarshalConditionsCmd(rq, "")
 | 
						|
			require.NoError(t, err)
 | 
						|
			require.Equal(t, tt.expectedCommand, cmd)
 | 
						|
 | 
						|
			require.Equal(t, tt.needsVars, cmd.NeedsVars())
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |