mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-17 15:36:48 +00:00
* feat(multi-threshold): added multi threshold * Update pkg/types/ruletypes/api_params.go Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * feat(multiple-threshold): added multiple thresholds * Update pkg/types/ruletypes/alerting.go Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * feat(multiple-threshold): added multiple thresholds * feat(cumulative-window): added cumulative window * feat(multi-threshold): added recovery min points * Update pkg/query-service/rules/threshold_rule.go Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * feat(multi-threshold): fixed log lines * feat(multi-threshold): added severity as threshold name * feat(cumulative-window): added cumulative window for alerts v2 * feat(multi-threshold): removed break to send multi threshold alerts * feat(multi-threshold): removed break to send multi threshold alerts * feat(cumulative-window): segregated json marshalling with evaluation logic * feat(multi-threshold): corrected the test cases * feat(cumulative-window): segregated json marshalling and evaluation logic * feat(cumulative-window): segregated json marshalling and evaluation logic * feat(multi-threshold): added segregation on json marshalling and actual threhsold logic * feat(multi-threshold): added segregation on json marshalling and actual threhsold logic * feat(cumulative-window): segregated json marshalling and evaluation logic * feat(multi-threshold): added segregation on json marshalling and actual threhsold logic * feat(cumulative-window): segregated json marshalling and evaluation logic * feat(multi-threhsold): added error wrapper * feat(multi-threhsold): added error wrapper * feat(cumulative-window): segregated json marshalling and evaluation logic * feat(multi-threhsold): added error wrapper * Update pkg/types/ruletypes/threshold.go Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * feat(cumulative-window): segregated json marshalling and evaluation logic * feat(multi-threshold): added validation and error propagation * feat(multi-notification): removed pre defined labels from links of log and traces * feat(multi-notification): removed pre defined labels from links of log and traces * feat(multi-threshold): added json parser for gettable rule * feat(multi-threshold): added json parser for gettable rule * feat(multi-threshold): added json parser for gettable rule * feat(multi-threshold): added umnarshaller for postable rule * feat(multi-threshold): added umnarshaller for postable rule * feat(cumulative-window): added validation check * Update pkg/types/ruletypes/evaluation.go Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * feat(multi-threhsold): removed yaml support for alerts * Update pkg/types/ruletypes/evaluation.go Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com> * Update pkg/types/ruletypes/evaluation.go Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com> * chore(cumulative-window): renamed funcitons * chore(cumulative-window): removed naked errors * chore(cumulative-window): added reset boundary condition tests * chore(cumulative-window): added reset boundary condition tests * chore(cumulative-window): sorted imports * chore(cumulative-window): sorted imports * chore(cumulative-window): sorted imports * chore(cumulative-window): removed error from next window for * chore(cumulative-window): removed error from next window for * chore(cumulative-window): added case for timezone * chore(cumulative-window): added validation for eval window * chore(cumulative-window): updated api structure for cumulative window * chore(cumulative-window): updated schedule enum --------- Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
729 lines
16 KiB
Go
729 lines
16 KiB
Go
package rules
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
|
|
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
|
|
ruletypes "github.com/SigNoz/signoz/pkg/types/ruletypes"
|
|
"github.com/SigNoz/signoz/pkg/valuer"
|
|
pql "github.com/prometheus/prometheus/promql"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func getVectorValues(vectors []ruletypes.Sample) []float64 {
|
|
if len(vectors) == 0 {
|
|
return []float64{} // Return empty slice instead of nil
|
|
}
|
|
var values []float64
|
|
for _, v := range vectors {
|
|
values = append(values, v.V)
|
|
}
|
|
return values
|
|
}
|
|
|
|
func TestPromRuleShouldAlert(t *testing.T) {
|
|
postableRule := ruletypes.PostableRule{
|
|
AlertName: "Test Rule",
|
|
AlertType: ruletypes.AlertTypeMetric,
|
|
RuleType: ruletypes.RuleTypeProm,
|
|
Evaluation: &ruletypes.EvaluationEnvelope{Kind: ruletypes.RollingEvaluation, Spec: ruletypes.RollingWindow{
|
|
EvalWindow: ruletypes.Duration(5 * time.Minute),
|
|
Frequency: ruletypes.Duration(1 * time.Minute),
|
|
}},
|
|
RuleCondition: &ruletypes.RuleCondition{
|
|
CompositeQuery: &v3.CompositeQuery{
|
|
QueryType: v3.QueryTypePromQL,
|
|
PromQueries: map[string]*v3.PromQuery{
|
|
"A": {
|
|
Query: "dummy_query", // This is not used in the test
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
cases := []struct {
|
|
values pql.Series
|
|
expectAlert bool
|
|
compareOp string
|
|
matchType string
|
|
target float64
|
|
expectedAlertSample v3.Point
|
|
expectedVectorValues []float64 // Expected values in result vector
|
|
}{
|
|
// Test cases for Equals Always
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "3", // Equals
|
|
matchType: "2", // Always
|
|
target: 0.0,
|
|
expectedAlertSample: v3.Point{Value: 0.0},
|
|
expectedVectorValues: []float64{0.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "3", // Equals
|
|
matchType: "2", // Always
|
|
target: 0.0,
|
|
expectedVectorValues: []float64{},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "3", // Equals
|
|
matchType: "2", // Always
|
|
target: 0.0,
|
|
expectedVectorValues: []float64{},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "3", // Equals
|
|
matchType: "2", // Always
|
|
target: 0.0,
|
|
},
|
|
// Test cases for Equals Once
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "3", // Equals
|
|
matchType: "1", // Once
|
|
target: 0.0,
|
|
expectedAlertSample: v3.Point{Value: 0.0},
|
|
expectedVectorValues: []float64{0.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "3", // Equals
|
|
matchType: "1", // Once
|
|
target: 0.0,
|
|
expectedAlertSample: v3.Point{Value: 0.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "3", // Equals
|
|
matchType: "1", // Once
|
|
target: 0.0,
|
|
expectedAlertSample: v3.Point{Value: 0.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "3", // Equals
|
|
matchType: "1", // Once
|
|
target: 0.0,
|
|
expectedVectorValues: []float64{},
|
|
},
|
|
// Test cases for Greater Than Always
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 4.0},
|
|
{F: 6.0},
|
|
{F: 8.0},
|
|
{F: 2.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "1", // Greater Than
|
|
matchType: "2", // Always
|
|
target: 1.5,
|
|
expectedAlertSample: v3.Point{Value: 2.0},
|
|
expectedVectorValues: []float64{2.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 11.0},
|
|
{F: 4.0},
|
|
{F: 3.0},
|
|
{F: 7.0},
|
|
{F: 12.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "1", // Above
|
|
matchType: "2", // Always
|
|
target: 2.0,
|
|
expectedAlertSample: v3.Point{Value: 3.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 11.0},
|
|
{F: 4.0},
|
|
{F: 3.0},
|
|
{F: 7.0},
|
|
{F: 12.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "2", // Below
|
|
matchType: "2", // Always
|
|
target: 13.0,
|
|
expectedAlertSample: v3.Point{Value: 12.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 4.0},
|
|
{F: 6.0},
|
|
{F: 8.0},
|
|
{F: 2.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "1", // Greater Than
|
|
matchType: "2", // Always
|
|
target: 4.5,
|
|
},
|
|
// Test cases for Greater Than Once
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 4.0},
|
|
{F: 6.0},
|
|
{F: 8.0},
|
|
{F: 2.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "1", // Greater Than
|
|
matchType: "1", // Once
|
|
target: 4.5,
|
|
expectedAlertSample: v3.Point{Value: 10.0},
|
|
expectedVectorValues: []float64{10.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 4.0},
|
|
{F: 4.0},
|
|
{F: 4.0},
|
|
{F: 4.0},
|
|
{F: 4.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "1", // Greater Than
|
|
matchType: "1", // Once
|
|
target: 4.5,
|
|
},
|
|
// Test cases for Not Equals Always
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
{F: 0.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "2", // Always
|
|
target: 0.0,
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 0.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "2", // Always
|
|
target: 0.0,
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "2", // Always
|
|
target: 0.0,
|
|
expectedAlertSample: v3.Point{Value: 1.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 1.0},
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "2", // Always
|
|
target: 0.0,
|
|
},
|
|
// Test cases for Not Equals Once
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
{F: 0.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "1", // Once
|
|
target: 0.0,
|
|
expectedAlertSample: v3.Point{Value: 1.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "1", // Once
|
|
target: 0.0,
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 0.0},
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
{F: 0.0},
|
|
{F: 1.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "1", // Once
|
|
target: 0.0,
|
|
expectedAlertSample: v3.Point{Value: 1.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
{F: 1.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "1", // Once
|
|
target: 0.0,
|
|
expectedAlertSample: v3.Point{Value: 1.0},
|
|
},
|
|
// Test cases for Less Than Always
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 1.5},
|
|
{F: 1.5},
|
|
{F: 1.5},
|
|
{F: 1.5},
|
|
{F: 1.5},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "2", // Less Than
|
|
matchType: "2", // Always
|
|
target: 4,
|
|
expectedAlertSample: v3.Point{Value: 1.5},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 4.5},
|
|
{F: 4.5},
|
|
{F: 4.5},
|
|
{F: 4.5},
|
|
{F: 4.5},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "2", // Less Than
|
|
matchType: "2", // Always
|
|
target: 4,
|
|
},
|
|
// Test cases for Less Than Once
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 4.5},
|
|
{F: 4.5},
|
|
{F: 4.5},
|
|
{F: 4.5},
|
|
{F: 2.5},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "2", // Less Than
|
|
matchType: "1", // Once
|
|
target: 4,
|
|
expectedAlertSample: v3.Point{Value: 2.5},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 4.5},
|
|
{F: 4.5},
|
|
{F: 4.5},
|
|
{F: 4.5},
|
|
{F: 4.5},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "2", // Less Than
|
|
matchType: "1", // Once
|
|
target: 4,
|
|
},
|
|
// Test cases for OnAverage
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 4.0},
|
|
{F: 6.0},
|
|
{F: 8.0},
|
|
{F: 2.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "3", // Equals
|
|
matchType: "3", // OnAverage
|
|
target: 6.0,
|
|
expectedAlertSample: v3.Point{Value: 6.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 4.0},
|
|
{F: 6.0},
|
|
{F: 8.0},
|
|
{F: 2.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "3", // Equals
|
|
matchType: "3", // OnAverage
|
|
target: 4.5,
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 4.0},
|
|
{F: 6.0},
|
|
{F: 8.0},
|
|
{F: 2.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "3", // OnAverage
|
|
target: 4.5,
|
|
expectedAlertSample: v3.Point{Value: 6.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 4.0},
|
|
{F: 6.0},
|
|
{F: 8.0},
|
|
{F: 2.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "3", // OnAverage
|
|
target: 6.0,
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 4.0},
|
|
{F: 6.0},
|
|
{F: 8.0},
|
|
{F: 2.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "1", // Greater Than
|
|
matchType: "3", // OnAverage
|
|
target: 4.5,
|
|
expectedAlertSample: v3.Point{Value: 6.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 4.0},
|
|
{F: 6.0},
|
|
{F: 8.0},
|
|
{F: 2.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "2", // Less Than
|
|
matchType: "3", // OnAverage
|
|
target: 12.0,
|
|
expectedAlertSample: v3.Point{Value: 6.0},
|
|
},
|
|
// Test cases for InTotal
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 4.0},
|
|
{F: 6.0},
|
|
{F: 8.0},
|
|
{F: 2.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "3", // Equals
|
|
matchType: "4", // InTotal
|
|
target: 30.0,
|
|
expectedAlertSample: v3.Point{Value: 30.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 4.0},
|
|
{F: 6.0},
|
|
{F: 8.0},
|
|
{F: 2.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "3", // Equals
|
|
matchType: "4", // InTotal
|
|
target: 20.0,
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "4", // InTotal
|
|
target: 9.0,
|
|
expectedAlertSample: v3.Point{Value: 10.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "4", // Not Equals
|
|
matchType: "4", // InTotal
|
|
target: 10.0,
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 10.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "1", // Greater Than
|
|
matchType: "4", // InTotal
|
|
target: 10.0,
|
|
expectedAlertSample: v3.Point{Value: 20.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 10.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "1", // Greater Than
|
|
matchType: "4", // InTotal
|
|
target: 20.0,
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 10.0},
|
|
},
|
|
},
|
|
expectAlert: true,
|
|
compareOp: "2", // Less Than
|
|
matchType: "4", // InTotal
|
|
target: 30.0,
|
|
expectedAlertSample: v3.Point{Value: 20.0},
|
|
},
|
|
{
|
|
values: pql.Series{
|
|
Floats: []pql.FPoint{
|
|
{F: 10.0},
|
|
{F: 10.0},
|
|
},
|
|
},
|
|
expectAlert: false,
|
|
compareOp: "2", // Less Than
|
|
matchType: "4", // InTotal
|
|
target: 20.0,
|
|
},
|
|
}
|
|
|
|
logger := instrumentationtest.New().Logger()
|
|
|
|
for idx, c := range cases {
|
|
postableRule.RuleCondition.CompareOp = ruletypes.CompareOp(c.compareOp)
|
|
postableRule.RuleCondition.MatchType = ruletypes.MatchType(c.matchType)
|
|
postableRule.RuleCondition.Target = &c.target
|
|
postableRule.RuleCondition.Thresholds = &ruletypes.RuleThresholdData{
|
|
Kind: ruletypes.BasicThresholdKind,
|
|
Spec: ruletypes.BasicRuleThresholds{
|
|
{
|
|
TargetValue: &c.target,
|
|
MatchType: ruletypes.MatchType(c.matchType),
|
|
CompareOp: ruletypes.CompareOp(c.compareOp),
|
|
},
|
|
},
|
|
}
|
|
|
|
rule, err := NewPromRule("69", valuer.GenerateUUID(), &postableRule, logger, nil, nil)
|
|
if err != nil {
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
resultVectors, err := rule.Threshold.ShouldAlert(toCommonSeries(c.values))
|
|
assert.NoError(t, err)
|
|
|
|
// Compare full result vector with expected vector
|
|
actualValues := getVectorValues(resultVectors)
|
|
if c.expectedVectorValues != nil {
|
|
// If expected vector values are specified, compare them exactly
|
|
assert.Equal(t, c.expectedVectorValues, actualValues, "Result vector values don't match expected for case %d", idx)
|
|
} else {
|
|
// Fallback to the old logic for cases without expectedVectorValues
|
|
if c.expectAlert {
|
|
assert.NotEmpty(t, resultVectors, "Expected alert but got no result vectors for case %d", idx)
|
|
// Verify at least one of the result vectors matches the expected alert sample
|
|
if len(resultVectors) > 0 {
|
|
found := false
|
|
for _, sample := range resultVectors {
|
|
if sample.V == c.expectedAlertSample.Value {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
assert.True(t, found, "Expected alert sample value %.2f not found in result vectors for case %d. Got values: %v", c.expectedAlertSample.Value, idx, actualValues)
|
|
}
|
|
} else {
|
|
assert.Empty(t, resultVectors, "Expected no alert but got result vectors for case %d", idx)
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|