@ -421,6 +421,8 @@ func TestAlertAndGroupsQuery(t *testing.T) {
Login : "grafana" ,
} )
apiClient := newAlertingApiClient ( grafanaListedAddr , "grafana" , "password" )
// invalid credentials request to get the alerts should fail
{
alertsURL := fmt . Sprintf ( "http://grafana:invalid@%s/api/alertmanager/grafana/api/v2/alerts" , grafanaListedAddr )
@ -476,9 +478,8 @@ func TestAlertAndGroupsQuery(t *testing.T) {
// Now, let's test the endpoint with some alerts.
{
// Create the namespace we'll save our alerts to.
err := c reateFolder( t , "default" , grafanaListedAddr , "grafana" , "password ")
apiClient . C reateFolder( t , "default" , "default ")
reloadCachedPermissions ( t , grafanaListedAddr , "grafana" , "password" )
require . NoError ( t , err )
}
// Create an alert that will fire as quickly as possible
@ -511,20 +512,9 @@ func TestAlertAndGroupsQuery(t *testing.T) {
} ,
} ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err = enc . Encode ( & rules )
require . NoError ( t , err )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Post ( u , "application/json" , & buf )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
status , _ := apiClient . PostRulesGroup ( t , "default" , & rules )
assert . Equal ( t , http . StatusAccepted , status )
}
// Eventually, we'll get an alert with its state being active.
@ -586,39 +576,40 @@ func TestRulerAccess(t *testing.T) {
Login : "admin" ,
} )
client := newAlertingApiClient ( grafanaListedAddr , "editor" , "editor" )
// Create the namespace we'll save our alerts to.
err := createFolder ( t , "default" , grafanaListedAddr , "editor" , "editor" )
client . C reateFolder( t , "default" , "default ")
reloadCachedPermissions ( t , grafanaListedAddr , "editor" , "editor" )
require . NoError ( t , err )
// Now, let's test the access policies.
testCases := [ ] struct {
desc string
url string
client apiClient
expStatus int
expectedMessage string
} {
{
desc : "un-authenticated request should fail" ,
url : "http://%s/api/ruler/grafana/api/v1/rules/default" ,
client : newAlertingApiClient ( grafanaListedAddr , "" , "" ) ,
expStatus : http . StatusUnauthorized ,
expectedMessage : ` Unauthorized ` ,
} ,
{
desc : "viewer request should fail" ,
url : "http://viewer:viewer@%s/api/ruler/grafana/api/v1/rules/default" ,
client : newAlertingApiClient ( grafanaListedAddr , "viewer" , "viewer" ) ,
expStatus : http . StatusForbidden ,
expectedMessage : ` You'll need additional permissions to perform this action. Permissions needed: any of alert.rules:write, alert.rules:create, alert.rules:delete ` ,
} ,
{
desc : "editor request should succeed" ,
url : "http://editor:editor@%s/api/ruler/grafana/api/v1/rules/default" ,
client : newAlertingApiClient ( grafanaListedAddr , "editor" , "editor" ) ,
expStatus : http . StatusAccepted ,
expectedMessage : ` rule group updated successfully ` ,
} ,
{
desc : "admin request should succeed" ,
url : "http://admin:admin@%s/api/ruler/grafana/api/v1/rules/default" ,
client : newAlertingApiClient ( grafanaListedAddr , "admin" , "admin" ) ,
expStatus : http . StatusAccepted ,
expectedMessage : ` rule group updated successfully ` ,
} ,
@ -661,25 +652,10 @@ func TestRulerAccess(t *testing.T) {
} ,
} ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err = enc . Encode ( & rules )
require . NoError ( t , err )
u := fmt . Sprintf ( tc . url , grafanaListedAddr )
// nolint:gosec
resp , err := http . Post ( u , "application/json" , & buf )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , tc . expStatus , resp . StatusCode )
status , body := tc . client . PostRulesGroup ( t , "default" , & rules )
assert . Equal ( t , tc . expStatus , status )
res := & Response { }
err = json . Unmarshal ( b , & res )
err = json . Unmarshal ( [ ] byte ( body ) , & res )
require . NoError ( t , err )
require . Equal ( t , tc . expectedMessage , res . Message )
} )
@ -710,13 +686,14 @@ func TestDeleteFolderWithRules(t *testing.T) {
Login : "editor" ,
} )
apiClient := newAlertingApiClient ( grafanaListedAddr , "editor" , "editor" )
// Create the namespace we'll save our alerts to.
namespaceUID := "default"
err := c reateFolder( t , namespaceUID , grafanaListedAddr , "editor" , "editor" )
apiClient . C reateFolder( t , namespaceUID , namespaceUID )
reloadCachedPermissions ( t , grafanaListedAddr , "editor" , "editor" )
require . NoError ( t , err )
createRule ( t , grafanaListedAddr , "default" , "editor" , "editor " )
createRule ( t , apiClient , "default" )
// First, let's have an editor create a rule within the folder/namespace.
{
@ -865,9 +842,10 @@ func TestAlertRuleCRUD(t *testing.T) {
Login : "grafana" ,
} )
apiClient := newAlertingApiClient ( grafanaListedAddr , "grafana" , "password" )
// Create the namespace we'll save our alerts to.
err := createFolder ( t , "default" , grafanaListedAddr , "grafana" , "password" )
require . NoError ( t , err )
apiClient . CreateFolder ( t , "default" , "default" )
reloadCachedPermissions ( t , grafanaListedAddr , "grafana" , "password" )
interval , err := model . ParseDuration ( "1m" )
@ -1093,30 +1071,15 @@ func TestAlertRuleCRUD(t *testing.T) {
tc . rule ,
} ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err := enc . Encode ( & rules )
require . NoError ( t , err )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Post ( u , "application/json" , & buf )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
status , body := apiClient . PostRulesGroup ( t , "default" , & rules )
res := & Response { }
err = json . Unmarshal ( b , & res )
err = json . Unmarshal ( [ ] byte ( body ) , & res )
require . NoError ( t , err )
assert . Equal ( t , res . Message , tc . expectedMessage )
assert . NotEmpty ( t , res . TraceID )
assert . Equal ( t , resp . StatusCode , http . StatusBadRequest )
assert . Equal ( t , http . StatusBadRequest , status )
} )
}
}
@ -1179,24 +1142,9 @@ func TestAlertRuleCRUD(t *testing.T) {
} ,
} ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err := enc . Encode ( & rules )
require . NoError ( t , err )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Post ( u , "application/json" , & buf )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
require . JSONEq ( t , ` { "message":"rule group updated successfully"} ` , string ( b ) )
status , body := apiClient . PostRulesGroup ( t , "default" , & rules )
assert . Equal ( t , http . StatusAccepted , status )
require . JSONEq ( t , ` { "message":"rule group updated successfully"} ` , body )
}
// With the rules created, let's make sure that rule definition is stored correctly.
@ -1359,37 +1307,23 @@ func TestAlertRuleCRUD(t *testing.T) {
} ,
Interval : interval ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err = enc . Encode ( & rules )
require . NoError ( t , err )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Post ( u , "application/json" , & buf )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , http . StatusNotFound , resp . StatusCode )
status , body := apiClient . PostRulesGroup ( t , "default" , & rules )
assert . Equal ( t , http . StatusNotFound , status )
var res map [ string ] interface { }
assert . NoError ( t , json . Unmarshal ( b , & res ) )
assert . NoError ( t , json . Unmarshal ( [ ] byte ( body ) , & res ) )
require . Equal ( t , "failed to update rule group: failed to update rule with UID unknown because could not find alert rule" , res [ "message" ] )
// let's make sure that rule definitions are not affected by the failed POST request.
u = fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err = http . Get ( u )
resp , err := http . Get ( u )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err = ioutil . ReadAll ( resp . Body )
b , err : = ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
@ -1480,37 +1414,22 @@ func TestAlertRuleCRUD(t *testing.T) {
} ,
Interval : interval ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err = enc . Encode ( & rules )
require . NoError ( t , err )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Post ( u , "application/json" , & buf )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , http . StatusBadRequest , resp . StatusCode )
status , body := apiClient . PostRulesGroup ( t , "default" , & rules )
assert . Equal ( t , http . StatusBadRequest , status )
var res map [ string ] interface { }
require . NoError ( t , json . Unmarshal ( b , & res ) )
require . NoError ( t , json . Unmarshal ( [ ] byte ( body ) , & res ) )
require . Equal ( t , fmt . Sprintf ( "rule [1] has UID %s that is already assigned to another rule at index 0" , ruleUID ) , res [ "message" ] )
// let's make sure that rule definitions are not affected by the failed POST request.
u = fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err = http . Get ( u )
resp , err := http . Get ( u )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err = ioutil . ReadAll ( resp . Body )
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
@ -1569,14 +1488,14 @@ func TestAlertRuleCRUD(t *testing.T) {
} ,
Interval : interval ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err = enc . Encode ( & rules )
require . NoError ( t , err )
status , body := apiClient . PostRulesGroup ( t , "default" , & rules )
assert . Equal ( t , http . StatusAccepted , status )
require . JSONEq ( t , ` { "message":"rule group updated successfully"} ` , body )
// let's make sure that rule definitions are updated correctly.
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Pos t( u , "application/json" , & buf )
resp , err := http . Ge t( u )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
@ -1585,21 +1504,6 @@ func TestAlertRuleCRUD(t *testing.T) {
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
require . JSONEq ( t , ` { "message":"rule group updated successfully"} ` , string ( b ) )
// let's make sure that rule definitions are updated correctly.
u = fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err = http . Get ( u )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err = ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
body , m := rulesNamespaceWithoutVariableValues ( t , b )
@ -1701,14 +1605,14 @@ func TestAlertRuleCRUD(t *testing.T) {
} ,
Interval : interval ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err = enc . Encode ( & rules )
require . NoError ( t , err )
status , body := apiClient . PostRulesGroup ( t , "default" , & rules )
assert . Equal ( t , http . StatusAccepted , status )
require . JSONEq ( t , ` { "message":"rule group updated successfully"} ` , body )
// let's make sure that rule definitions are updated correctly.
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Pos t( u , "application/json" , & buf )
resp , err := http . Ge t( u )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
@ -1717,21 +1621,6 @@ func TestAlertRuleCRUD(t *testing.T) {
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
require . JSONEq ( t , ` { "message":"rule group updated successfully"} ` , string ( b ) )
// let's make sure that rule definitions are updated correctly.
u = fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err = http . Get ( u )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err = ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
body , m := rulesNamespaceWithoutVariableValues ( t , b )
@ -1801,14 +1690,14 @@ func TestAlertRuleCRUD(t *testing.T) {
} ,
Interval : interval ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err = enc . Encode ( & rules )
require . NoError ( t , err )
status , body := apiClient . PostRulesGroup ( t , "default" , & rules )
assert . Equal ( t , http . StatusAccepted , status )
require . JSONEq ( t , ` { "message":"no changes detected in the rule group"} ` , body )
// let's make sure that rule definitions are updated correctly.
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Pos t( u , "application/json" , & buf )
resp , err := http . Ge t( u )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
@ -1817,21 +1706,6 @@ func TestAlertRuleCRUD(t *testing.T) {
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
require . JSONEq ( t , ` { "message":"no changes detected in the rule group"} ` , string ( b ) )
// let's make sure that rule definitions are updated correctly.
u = fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err = http . Get ( u )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err = ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
body , m := rulesNamespaceWithoutVariableValues ( t , b )
@ -2009,17 +1883,16 @@ func TestQuota(t *testing.T) {
Password : "password" ,
Login : "grafana" ,
} )
apiClient := newAlertingApiClient ( grafanaListedAddr , "grafana" , "password" )
// Create the namespace we'll save our alerts to.
err := createFolder ( t , "default" , grafanaListedAddr , "grafana" , "password" )
require . NoError ( t , err )
apiClient . CreateFolder ( t , "default" , "default" )
reloadCachedPermissions ( t , grafanaListedAddr , "grafana" , "password" )
interval , err := model . ParseDuration ( "1m" )
require . NoError ( t , err )
// Create rule under folder1
createRule ( t , grafanaListedAddr , "default" , "grafana" , "password " )
createRule ( t , apiClient , "default" )
// get the generated rule UID
var ruleUID string
@ -2100,24 +1973,10 @@ func TestQuota(t *testing.T) {
} ,
} ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err = enc . Encode ( & rules )
require . NoError ( t , err )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Post ( u , "application/json" , & buf )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , http . StatusForbidden , resp . StatusCode )
status , body := apiClient . PostRulesGroup ( t , "default" , & rules )
assert . Equal ( t , http . StatusForbidden , status )
var res map [ string ] interface { }
require . NoError ( t , json . Unmarshal ( b , & res ) )
require . NoError ( t , json . Unmarshal ( [ ] byte ( body ) , & res ) )
require . Equal ( t , "quota has been exceeded" , res [ "message" ] )
} )
@ -2150,34 +2009,21 @@ func TestQuota(t *testing.T) {
} ,
} ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err = enc . Encode ( & rules )
require . NoError ( t , err )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Post ( u , "application/json" , & buf )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , http . StatusAccepted , resp . StatusCode )
require . JSONEq ( t , ` { "message":"rule group updated successfully"} ` , string ( b ) )
status , body := apiClient . PostRulesGroup ( t , "default" , & rules )
assert . Equal ( t , http . StatusAccepted , status )
require . JSONEq ( t , ` { "message":"rule group updated successfully"} ` , body )
// let's make sure that rule definitions are updated correctly.
u = fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err = http . Get ( u )
resp , err := http . Get ( u )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err = ioutil . ReadAll ( resp . Body )
b , err : = ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
@ -2254,10 +2100,9 @@ func TestEval(t *testing.T) {
Password : "password" ,
Login : "grafana" ,
} )
apiClient := newAlertingApiClient ( grafanaListedAddr , "grafana" , "password" )
// Create the namespace we'll save our alerts to.
err := createFolder ( t , "default" , grafanaListedAddr , "grafana" , "password" )
require . NoError ( t , err )
apiClient . CreateFolder ( t , "default" , "default" )
// test eval conditions
testCases := [ ] struct {
@ -2675,24 +2520,6 @@ func TestEval(t *testing.T) {
}
}
// createFolder creates a folder for storing our alerts under. Grafana uses folders as a replacement for alert namespaces to match its permission model.
// We use the dashboard command using IsFolder = true to tell it's a folder, it takes the dashboard as the name of the folder.
func createFolder ( t * testing . T , folderUID , grafanaListedAddr , login , password string ) error {
t . Helper ( )
payload := fmt . Sprintf ( ` { "uid": "%s","title": "%s"} ` , folderUID , folderUID )
u := fmt . Sprintf ( "http://%s:%s@%s/api/folders" , login , password , grafanaListedAddr )
r := strings . NewReader ( payload )
// nolint:gosec
resp , err := http . Post ( u , "application/json" , r )
t . Cleanup ( func ( ) {
require . NoError ( t , resp . Body . Close ( ) )
} )
require . NoError ( t , err )
assert . Equal ( t , http . StatusOK , resp . StatusCode )
return err
}
// rulesNamespaceWithoutVariableValues takes a apimodels.NamespaceConfigResponse JSON-based input and makes the dynamic fields static e.g. uid, dates, etc.
// it returns a map of the modified rule UIDs with the namespace,rule_group as a key
func rulesNamespaceWithoutVariableValues ( t * testing . T , b [ ] byte ) ( string , map [ string ] [ ] string ) {