@ -7,6 +7,7 @@ import (
"time"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/sqlstore"
@ -35,6 +36,22 @@ func TestAlertRuleService(t *testing.T) {
require . Equal ( t , models . ProvenanceAPI , provenance )
} )
t . Run ( "group creation should set the right provenance" , func ( t * testing . T ) {
var orgID int64 = 1
group := createDummyGroup ( "group-test-1" , orgID )
err := ruleService . ReplaceRuleGroup ( context . Background ( ) , orgID , group , 0 , models . ProvenanceAPI )
require . NoError ( t , err )
readGroup , err := ruleService . GetRuleGroup ( context . Background ( ) , orgID , "my-namespace" , "group-test-1" )
require . NoError ( t , err )
require . NotEmpty ( t , readGroup . Rules )
for _ , rule := range readGroup . Rules {
_ , provenance , err := ruleService . GetAlertRule ( context . Background ( ) , orgID , rule . UID )
require . NoError ( t , err )
require . Equal ( t , models . ProvenanceAPI , provenance )
}
} )
t . Run ( "alert rule group should be updated correctly" , func ( t * testing . T ) {
var orgID int64 = 1
rule := dummyRule ( "test#3" , orgID )
@ -52,6 +69,22 @@ func TestAlertRuleService(t *testing.T) {
require . Equal ( t , interval , rule . IntervalSeconds )
} )
t . Run ( "group creation should propagate group title correctly" , func ( t * testing . T ) {
var orgID int64 = 1
group := createDummyGroup ( "group-test-3" , orgID )
group . Rules [ 0 ] . RuleGroup = "something different"
err := ruleService . ReplaceRuleGroup ( context . Background ( ) , orgID , group , 0 , models . ProvenanceAPI )
require . NoError ( t , err )
readGroup , err := ruleService . GetRuleGroup ( context . Background ( ) , orgID , "my-namespace" , "group-test-3" )
require . NoError ( t , err )
require . NotEmpty ( t , readGroup . Rules )
for _ , rule := range readGroup . Rules {
require . Equal ( t , "group-test-3" , rule . RuleGroup )
}
} )
t . Run ( "alert rule should get interval from existing rule group" , func ( t * testing . T ) {
var orgID int64 = 1
rule := dummyRule ( "test#4" , orgID )
@ -70,7 +103,7 @@ func TestAlertRuleService(t *testing.T) {
require . Equal ( t , interval , rule . IntervalSeconds )
} )
t . Run ( "updating a rule group should bump the version number" , func ( t * testing . T ) {
t . Run ( "updating a rule group's top level fields should bump the version number" , func ( t * testing . T ) {
const (
orgID = 123
namespaceUID = "abc"
@ -99,6 +132,26 @@ func TestAlertRuleService(t *testing.T) {
require . Equal ( t , newInterval , rule . IntervalSeconds )
} )
t . Run ( "updating a group by updating a rule should bump that rule's data and version number" , func ( t * testing . T ) {
var orgID int64 = 1
group := createDummyGroup ( "group-test-5" , orgID )
err := ruleService . ReplaceRuleGroup ( context . Background ( ) , orgID , group , 0 , models . ProvenanceAPI )
require . NoError ( t , err )
updatedGroup , err := ruleService . GetRuleGroup ( context . Background ( ) , orgID , "my-namespace" , "group-test-5" )
require . NoError ( t , err )
updatedGroup . Rules [ 0 ] . Title = "some-other-title-asdf"
err = ruleService . ReplaceRuleGroup ( context . Background ( ) , orgID , updatedGroup , 0 , models . ProvenanceAPI )
require . NoError ( t , err )
readGroup , err := ruleService . GetRuleGroup ( context . Background ( ) , orgID , "my-namespace" , "group-test-5" )
require . NoError ( t , err )
require . NotEmpty ( t , readGroup . Rules )
require . Len ( t , readGroup . Rules , 1 )
require . Equal ( t , "some-other-title-asdf" , readGroup . Rules [ 0 ] . Title )
require . Equal ( t , int64 ( 2 ) , readGroup . Rules [ 0 ] . Version )
} )
t . Run ( "alert rule provenace should be correctly checked" , func ( t * testing . T ) {
tests := [ ] struct {
name string
@ -160,6 +213,68 @@ func TestAlertRuleService(t *testing.T) {
}
} )
t . Run ( "alert rule provenace should be correctly checked when writing groups" , func ( t * testing . T ) {
tests := [ ] struct {
name string
from models . Provenance
to models . Provenance
errNil bool
} {
{
name : "should be able to update from provenance none to api" ,
from : models . ProvenanceNone ,
to : models . ProvenanceAPI ,
errNil : true ,
} ,
{
name : "should be able to update from provenance none to file" ,
from : models . ProvenanceNone ,
to : models . ProvenanceFile ,
errNil : true ,
} ,
{
name : "should not be able to update from provenance api to file" ,
from : models . ProvenanceAPI ,
to : models . ProvenanceFile ,
errNil : false ,
} ,
{
name : "should not be able to update from provenance api to none" ,
from : models . ProvenanceAPI ,
to : models . ProvenanceNone ,
errNil : false ,
} ,
{
name : "should not be able to update from provenance file to api" ,
from : models . ProvenanceFile ,
to : models . ProvenanceAPI ,
errNil : false ,
} ,
{
name : "should not be able to update from provenance file to none" ,
from : models . ProvenanceFile ,
to : models . ProvenanceNone ,
errNil : false ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var orgID int64 = 1
group := createDummyGroup ( t . Name ( ) , orgID )
err := ruleService . ReplaceRuleGroup ( context . Background ( ) , 1 , group , 0 , test . from )
require . NoError ( t , err )
group . Rules [ 0 ] . Title = t . Name ( )
err = ruleService . ReplaceRuleGroup ( context . Background ( ) , 1 , group , 0 , test . to )
if test . errNil {
require . NoError ( t , err )
} else {
require . Error ( t , err )
}
} )
}
} )
t . Run ( "quota met causes create to be rejected" , func ( t * testing . T ) {
ruleService := createAlertRuleService ( t )
checker := & MockQuotaChecker { }
@ -170,6 +285,18 @@ func TestAlertRuleService(t *testing.T) {
require . ErrorIs ( t , err , models . ErrQuotaReached )
} )
t . Run ( "quota met causes group write to be rejected" , func ( t * testing . T ) {
ruleService := createAlertRuleService ( t )
checker := & MockQuotaChecker { }
checker . EXPECT ( ) . LimitExceeded ( )
ruleService . quotas = checker
group := createDummyGroup ( "quota-reached" , 1 )
err := ruleService . ReplaceRuleGroup ( context . Background ( ) , 1 , group , 0 , models . ProvenanceAPI )
require . ErrorIs ( t , err , models . ErrQuotaReached )
} )
}
func createAlertRuleService ( t * testing . T ) AlertRuleService {
@ -180,6 +307,7 @@ func createAlertRuleService(t *testing.T) AlertRuleService {
Cfg : setting . UnifiedAlertingSettings {
BaseInterval : time . Second * 10 ,
} ,
Logger : log . NewNopLogger ( ) ,
}
quotas := MockQuotaChecker { }
quotas . EXPECT ( ) . LimitOK ( )
@ -195,6 +323,10 @@ func createAlertRuleService(t *testing.T) AlertRuleService {
}
func dummyRule ( title string , orgID int64 ) models . AlertRule {
return createTestRule ( title , "my-cool-group" , orgID )
}
func createTestRule ( title string , groupTitle string , orgID int64 ) models . AlertRule {
return models . AlertRule {
OrgID : orgID ,
Title : title ,
@ -212,9 +344,21 @@ func dummyRule(title string, orgID int64) models.AlertRule {
} ,
} ,
} ,
RuleGroup : "my-cool-group" ,
NamespaceUID : "my-namespace" ,
RuleGroup : groupTitle ,
For : time . Second * 60 ,
NoDataState : models . OK ,
ExecErrState : models . OkErrState ,
}
}
func createDummyGroup ( title string , orgID int64 ) definitions . AlertRuleGroup {
return definitions . AlertRuleGroup {
Title : title ,
Interval : 60 ,
FolderUID : "my-namespace" ,
Rules : [ ] models . AlertRule {
dummyRule ( title + "-" + "rule-1" , orgID ) ,
} ,
}
}