@ -15,6 +15,7 @@ package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
@ -27,6 +28,7 @@ import (
"github.com/go-kit/log"
"github.com/grafana/regexp"
"github.com/nsf/jsondiff"
"github.com/prometheus/common/model"
"gopkg.in/yaml.v2"
@ -40,7 +42,7 @@ import (
// RulesUnitTest does unit testing of rules based on the unit testing files provided.
// More info about the file format can be found in the docs.
func RulesUnitTest ( queryOpts promql . LazyLoaderOpts , runStrings [ ] string , files ... string ) int {
func RulesUnitTest ( queryOpts promql . LazyLoaderOpts , runStrings [ ] string , diffFlag bool , files ... string ) int {
failed := false
var run * regexp . Regexp
@ -49,7 +51,7 @@ func RulesUnitTest(queryOpts promql.LazyLoaderOpts, runStrings []string, files .
}
for _ , f := range files {
if errs := ruleUnitTest ( f , queryOpts , run ) ; errs != nil {
if errs := ruleUnitTest ( f , queryOpts , run , diffFlag ) ; errs != nil {
fmt . Fprintln ( os . Stderr , " FAILED:" )
for _ , e := range errs {
fmt . Fprintln ( os . Stderr , e . Error ( ) )
@ -67,7 +69,7 @@ func RulesUnitTest(queryOpts promql.LazyLoaderOpts, runStrings []string, files .
return successExitCode
}
func ruleUnitTest ( filename string , queryOpts promql . LazyLoaderOpts , run * regexp . Regexp ) [ ] error {
func ruleUnitTest ( filename string , queryOpts promql . LazyLoaderOpts , run * regexp . Regexp , diffFlag bool ) [ ] error {
fmt . Println ( "Unit Testing: " , filename )
b , err := os . ReadFile ( filename )
@ -109,7 +111,7 @@ func ruleUnitTest(filename string, queryOpts promql.LazyLoaderOpts, run *regexp.
if t . Interval == 0 {
t . Interval = unitTestInp . EvaluationInterval
}
ers := t . test ( evalInterval , groupOrderMap , queryOpts , unitTestInp . RuleFiles ... )
ers := t . test ( evalInterval , groupOrderMap , queryOpts , diffFlag , unitTestInp . RuleFiles ... )
if ers != nil {
errs = append ( errs , ers ... )
}
@ -173,7 +175,7 @@ type testGroup struct {
}
// test performs the unit tests.
func ( tg * testGroup ) test ( evalInterval time . Duration , groupOrderMap map [ string ] int , queryOpts promql . LazyLoaderOpts , ruleFiles ... string ) [ ] error {
func ( tg * testGroup ) test ( evalInterval time . Duration , groupOrderMap map [ string ] int , queryOpts promql . LazyLoaderOpts , diffFlag bool , ruleFiles ... string ) [ ] error {
// Setup testing suite.
suite , err := promql . NewLazyLoader ( nil , tg . seriesLoadingString ( ) , queryOpts )
if err != nil {
@ -345,8 +347,44 @@ func (tg *testGroup) test(evalInterval time.Duration, groupOrderMap map[string]i
}
expString := indentLines ( expAlerts . String ( ) , " " )
gotString := indentLines ( gotAlerts . String ( ) , " " )
errs = append ( errs , fmt . Errorf ( "%s alertname: %s, time: %s, \n exp:%v, \n got:%v" ,
testName , testcase . Alertname , testcase . EvalTime . String ( ) , expString , gotString ) )
if diffFlag {
// If empty, populates an empty value
if gotAlerts . Len ( ) == 0 {
gotAlerts = append ( gotAlerts , labelAndAnnotation {
Labels : labels . Labels { } ,
Annotations : labels . Labels { } ,
} )
}
// If empty, populates an empty value
if expAlerts . Len ( ) == 0 {
expAlerts = append ( expAlerts , labelAndAnnotation {
Labels : labels . Labels { } ,
Annotations : labels . Labels { } ,
} )
}
diffOpts := jsondiff . DefaultConsoleOptions ( )
expAlertsJSON , err := json . Marshal ( expAlerts )
if err != nil {
errs = append ( errs , fmt . Errorf ( "error marshaling expected %s alert: [%s]" , tg . TestGroupName , err . Error ( ) ) )
continue
}
gotAlertsJSON , err := json . Marshal ( gotAlerts )
if err != nil {
errs = append ( errs , fmt . Errorf ( "error marshaling received %s alert: [%s]" , tg . TestGroupName , err . Error ( ) ) )
continue
}
res , diff := jsondiff . Compare ( expAlertsJSON , gotAlertsJSON , & diffOpts )
if res != jsondiff . FullMatch {
errs = append ( errs , fmt . Errorf ( "%s alertname: %s, time: %s, \n diff: %v" ,
testName , testcase . Alertname , testcase . EvalTime . String ( ) , indentLines ( diff , " " ) ) )
}
} else {
errs = append ( errs , fmt . Errorf ( "%s alertname: %s, time: %s, \n exp:%v, \n got:%v" ,
testName , testcase . Alertname , testcase . EvalTime . String ( ) , expString , gotString ) )
}
}
}