@ -7,7 +7,14 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user"
"github.com/stretchr/testify/require"
"golang.org/x/exp/rand"
@ -21,12 +28,13 @@ func TestIntegrationUpdateAlertRules(t *testing.T) {
if testing . Short ( ) {
t . Skip ( "skipping integration test" )
}
cfg := setting . NewCfg ( )
cfg . UnifiedAlerting = setting . UnifiedAlertingSettings { BaseInterval : time . Duration ( rand . Int63n ( 100 ) ) * time . Second }
sqlStore := db . InitTestDB ( t )
store := & DBstore {
SQLStore : sqlStore ,
Cfg : setting . UnifiedAlertingSettings {
BaseInterval : time . Duration ( rand . Int63n ( 100 ) ) * time . Second ,
} ,
SQLStore : sqlStore ,
Cfg : cfg . UnifiedAlerting ,
FolderService : setupFolderService ( t , sqlStore , cfg ) ,
}
t . Run ( "should increase version" , func ( t * testing . T ) {
@ -68,75 +76,112 @@ func TestIntegrationUpdateAlertRules(t *testing.T) {
} )
}
func withIntervalMatching ( baseInterval time . Duration ) func ( * models . AlertRule ) {
return func ( rule * models . AlertRule ) {
rule . IntervalSeconds = int64 ( baseInterval . Seconds ( ) ) * rand . Int63n ( 10 )
rule . For = time . Duration ( rule . IntervalSeconds * rand . Int63n ( 9 ) + 1 ) * time . Second
}
}
func TestIntegration_getFilterByOrgsString ( t * testing . T ) {
func TestIntegration_GetAlertRulesForScheduling ( t * testing . T ) {
if testing . Short ( ) {
t . Skip ( "skipping integration test" )
}
testCases := [ ] struct {
testName string
orgs map [ int64 ] struct { }
expectedFilter string
expectedArgs [ ] interface { }
cfg := setting . NewCfg ( )
cfg . UnifiedAlerting = setting . UnifiedAlertingSettings {
BaseInterval : time . Duration ( rand . Int63n ( 100 ) ) * time . Second ,
}
sqlStore := db . InitTestDB ( t )
store := & DBstore {
SQLStore : sqlStore ,
Cfg : setting . UnifiedAlertingSettings {
BaseInterval : time . Duration ( rand . Int63n ( 100 ) ) * time . Second ,
} ,
FolderService : setupFolderService ( t , sqlStore , cfg ) ,
}
rule1 := createRule ( t , store )
rule2 := createRule ( t , store )
tc := [ ] struct {
name string
rules [ ] string
ruleGroups [ ] string
disabledOrgs [ ] int64
folders map [ string ] string
} {
{
testName : "should return empty string if map is empty" ,
orgs : map [ int64 ] struct { } { } ,
expectedFilter : "" ,
expectedArgs : nil ,
name : "without a rule group filter, it returns all created rules" ,
rules : [ ] string { rule1 . Title , rule2 . Title } ,
} ,
{
testName : "should return empty string if map is nil" ,
orgs : nil ,
expectedFilter : "" ,
expectedArgs : nil ,
name : "with a rule group filter, it only returns the rules that match on rule group" ,
ruleGroups : [ ] string { rule1 . RuleGroup } ,
rules : [ ] string { rule1 . Title } ,
} ,
{
testName : "should return correct filter if single element" ,
orgs : map [ int64 ] struct { } {
1 : { } ,
} ,
expectedFilter : "org_id NOT IN(?)" ,
expectedArgs : [ ] interface { } { int64 ( 1 ) } ,
name : "with a filter on orgs, it returns rules that do not belong to that org" ,
rules : [ ] string { rule1 . Title } ,
disabledOrgs : [ ] int64 { rule2 . OrgID } ,
} ,
{
testName : "should return correct filter if many elements" ,
orgs : map [ int64 ] struct { } {
1 : { } ,
2 : { } ,
3 : { } ,
} ,
expectedFilter : "org_id NOT IN(?,?,?)" ,
expectedArgs : [ ] interface { } { int64 ( 1 ) , int64 ( 2 ) , int64 ( 3 ) } ,
name : "with populate folders enabled, it returns them" ,
rules : [ ] string { rule1 . Title , rule2 . Title } ,
folders : map [ string ] string { rule1 . NamespaceUID : rule1 . Title , rule2 . NamespaceUID : rule2 . Title } ,
} ,
{
name : "with populate folders enabled and a filter on orgs, it only returns selected information" ,
rules : [ ] string { rule1 . Title } ,
disabledOrgs : [ ] int64 { rule2 . OrgID } ,
folders : map [ string ] string { rule1 . NamespaceUID : rule1 . Title } ,
} ,
}
for _ , testCase := range testCases {
t . Run ( testCase . testName , func ( t * testing . T ) {
store := & DBstore {
Cfg : setting . UnifiedAlertingSettings {
DisabledOrgs : testCase . orgs ,
} ,
for _ , tt := range tc {
t . Run ( tt . name , func ( t * testing . T ) {
if len ( tt . disabledOrgs ) > 0 {
store . Cfg . DisabledOrgs = map [ int64 ] struct { } { }
for _ , orgID := range tt . disabledOrgs {
store . Cfg . DisabledOrgs [ orgID ] = struct { } { }
t . Cleanup ( func ( ) {
delete ( store . Cfg . DisabledOrgs , orgID )
} )
}
}
populateFolders := len ( tt . folders ) > 0
query := & models . GetAlertRulesForSchedulingQuery {
RuleGroups : tt . ruleGroups ,
PopulateFolders : populateFolders ,
}
require . NoError ( t , store . GetAlertRulesForScheduling ( context . Background ( ) , query ) )
require . Len ( t , query . ResultRules , len ( tt . rules ) )
r := make ( [ ] string , 0 , len ( query . ResultRules ) )
for _ , rule := range query . ResultRules {
r = append ( r , rule . Title )
}
require . ElementsMatch ( t , r , tt . rules )
if populateFolders {
require . Equal ( t , tt . folders , query . ResultFoldersTitles )
}
filter , args := store . getFilterByOrgsString ( )
assert . Equal ( t , testCase . expectedFilter , filter )
assert . ElementsMatch ( t , testCase . expectedArgs , args )
} )
}
}
func withIntervalMatching ( baseInterval time . Duration ) func ( * models . AlertRule ) {
return func ( rule * models . AlertRule ) {
rule . IntervalSeconds = int64 ( baseInterval . Seconds ( ) ) * rand . Int63n ( 10 )
rule . For = time . Duration ( rule . IntervalSeconds * rand . Int63n ( 9 ) + 1 ) * time . Second
}
}
func TestIntegration_CountAlertRules ( t * testing . T ) {
if testing . Short ( ) {
t . Skip ( "skipping integration test" )
}
sqlStore := db . InitTestDB ( t )
store := & DBstore { SQLStore : sqlStore }
cfg := setting . NewCfg ( )
store := & DBstore { SQLStore : sqlStore , FolderService : setupFolderService ( t , sqlStore , cfg ) }
rule := createRule ( t , store )
tests := map [ string ] struct {
@ -176,7 +221,9 @@ func TestIntegration_CountAlertRules(t *testing.T) {
}
func createRule ( t * testing . T , store * DBstore ) * models . AlertRule {
t . Helper ( )
rule := models . AlertRuleGen ( withIntervalMatching ( store . Cfg . BaseInterval ) , models . WithUniqueID ( ) ) ( )
createFolder ( t , store , rule . NamespaceUID , rule . Title , rule . OrgID )
err := store . SQLStore . WithDbSession ( context . Background ( ) , func ( sess * db . Session ) error {
_ , err := sess . Table ( models . AlertRule { } ) . InsertOne ( rule )
if err != nil {
@ -191,8 +238,41 @@ func createRule(t *testing.T, store *DBstore) *models.AlertRule {
return errors . New ( "cannot read inserted record" )
}
rule = dbRule
require . NoError ( t , err )
return nil
} )
require . NoError ( t , err )
return rule
}
func createFolder ( t * testing . T , store * DBstore , namespace , title string , orgID int64 ) {
t . Helper ( )
u := & user . SignedInUser {
UserID : 1 ,
OrgID : orgID ,
OrgRole : org . RoleAdmin ,
IsGrafanaAdmin : true ,
}
_ , err := store . FolderService . Create ( context . Background ( ) , & folder . CreateFolderCommand {
UID : namespace ,
OrgID : orgID ,
Title : title ,
Description : "" ,
SignedInUser : u ,
} )
require . NoError ( t , err )
}
func setupFolderService ( t * testing . T , sqlStore * sqlstore . SQLStore , cfg * setting . Cfg ) folder . Service {
tracer := tracing . InitializeTracerForTest ( )
inProcBus := bus . ProvideBus ( tracer )
folderStore := folderimpl . ProvideDashboardFolderStore ( sqlStore )
_ , dashboardStore := SetupDashboardService ( t , sqlStore , folderStore , cfg )
return SetupFolderService ( t , cfg , dashboardStore , folderStore , inProcBus )
}