2021-03-11 13:28:00 -06:00
package api
import (
2022-08-12 08:56:18 -05:00
"math/rand"
"net/http"
2021-03-11 13:28:00 -06:00
"testing"
"github.com/stretchr/testify/assert"
2022-08-12 08:56:18 -05:00
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/infra/log"
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
2022-11-18 02:56:06 -06:00
"github.com/grafana/grafana/pkg/services/auth"
2023-01-27 01:50:36 -06:00
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
2023-06-15 12:33:42 -05:00
"github.com/grafana/grafana/pkg/services/ngalert/eval"
2022-08-24 14:33:33 -05:00
models2 "github.com/grafana/grafana/pkg/services/ngalert/models"
2022-08-12 08:56:18 -05:00
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
2021-03-11 13:28:00 -06:00
)
func TestToMacaronPath ( t * testing . T ) {
testCases := [ ] struct {
inputPath string
expectedOutputPath string
} {
{
inputPath : "" ,
expectedOutputPath : "" ,
} ,
{
2022-04-20 08:20:17 -05:00
inputPath : "/ruler/{DatasourceID}/api/v1/rules/{Namespace}/{Groupname}" ,
expectedOutputPath : "/ruler/:DatasourceID/api/v1/rules/:Namespace/:Groupname" ,
2021-03-11 13:28:00 -06:00
} ,
}
for _ , tc := range testCases {
outputPath := toMacaronPath ( tc . inputPath )
assert . Equal ( t , tc . expectedOutputPath , outputPath )
}
}
2022-08-12 08:56:18 -05:00
func TestAlertingProxy_createProxyContext ( t * testing . T ) {
2023-01-27 01:50:36 -06:00
ctx := & contextmodel . ReqContext {
2022-08-12 08:56:18 -05:00
Context : & web . Context {
2022-08-16 05:25:27 -05:00
Req : & http . Request { } ,
2022-08-12 08:56:18 -05:00
} ,
2023-08-25 13:56:02 -05:00
SignedInUser : & user . SignedInUser { } ,
UserToken : & auth . UserToken { } ,
IsSignedIn : rand . Int63 ( ) % 2 == 1 ,
IsRenderCall : rand . Int63 ( ) % 2 == 1 ,
AllowAnonymous : rand . Int63 ( ) % 2 == 1 ,
SkipDSCache : rand . Int63 ( ) % 2 == 1 ,
SkipQueryCache : rand . Int63 ( ) % 2 == 1 ,
Logger : log . New ( "test" ) ,
RequestNonce : util . GenerateShortUID ( ) ,
PublicDashboardAccessToken : util . GenerateShortUID ( ) ,
2022-08-12 08:56:18 -05:00
}
t . Run ( "should create a copy of request context" , func ( t * testing . T ) {
for _ , mock := range [ ] * accesscontrolmock . Mock {
2023-09-05 05:04:39 -05:00
accesscontrolmock . New ( ) , accesscontrolmock . New ( ) ,
2022-08-12 08:56:18 -05:00
} {
proxy := AlertingProxy {
DataProxy : nil ,
ac : mock ,
}
req := & http . Request { }
resp := & response . NormalResponse { }
newCtx := proxy . createProxyContext ( ctx , req , resp )
require . NotEqual ( t , ctx , newCtx )
require . Equal ( t , ctx . UserToken , newCtx . UserToken )
require . Equal ( t , ctx . IsSignedIn , newCtx . IsSignedIn )
require . Equal ( t , ctx . IsRenderCall , newCtx . IsRenderCall )
require . Equal ( t , ctx . AllowAnonymous , newCtx . AllowAnonymous )
2023-04-12 11:30:33 -05:00
require . Equal ( t , ctx . SkipDSCache , newCtx . SkipDSCache )
require . Equal ( t , ctx . SkipQueryCache , newCtx . SkipQueryCache )
2022-08-12 08:56:18 -05:00
require . Equal ( t , ctx . Logger , newCtx . Logger )
require . Equal ( t , ctx . RequestNonce , newCtx . RequestNonce )
2023-08-25 13:56:02 -05:00
require . Equal ( t , ctx . PublicDashboardAccessToken , newCtx . PublicDashboardAccessToken )
2022-08-12 08:56:18 -05:00
}
} )
t . Run ( "should overwrite response writer" , func ( t * testing . T ) {
proxy := AlertingProxy {
DataProxy : nil ,
ac : accesscontrolmock . New ( ) ,
}
req := & http . Request { }
resp := & response . NormalResponse { }
newCtx := proxy . createProxyContext ( ctx , req , resp )
require . NotEqual ( t , ctx . Context . Resp , newCtx . Context . Resp )
require . Equal ( t , ctx . Context . Req , newCtx . Context . Req )
require . NotEqual ( t , 123 , resp . Status ( ) )
newCtx . Context . Resp . WriteHeader ( 123 )
require . Equal ( t , 123 , resp . Status ( ) )
} )
t . Run ( "if access control is enabled" , func ( t * testing . T ) {
t . Run ( "should elevate permissions to Editor for Viewer" , func ( t * testing . T ) {
proxy := AlertingProxy {
DataProxy : nil ,
ac : accesscontrolmock . New ( ) ,
}
req := & http . Request { }
resp := & response . NormalResponse { }
viewerCtx := * ctx
viewerCtx . SignedInUser = & user . SignedInUser {
OrgRole : org . RoleViewer ,
}
newCtx := proxy . createProxyContext ( & viewerCtx , req , resp )
require . NotEqual ( t , viewerCtx . SignedInUser , newCtx . SignedInUser )
require . Truef ( t , newCtx . SignedInUser . HasRole ( org . RoleEditor ) , "user of the proxy request should have at least Editor role but has %s" , newCtx . SignedInUser . OrgRole )
} )
t . Run ( "should not alter user if it is Editor" , func ( t * testing . T ) {
proxy := AlertingProxy {
DataProxy : nil ,
ac : accesscontrolmock . New ( ) ,
}
req := & http . Request { }
resp := & response . NormalResponse { }
for _ , roleType := range [ ] org . RoleType { org . RoleEditor , org . RoleAdmin } {
roleCtx := * ctx
roleCtx . SignedInUser = & user . SignedInUser {
OrgRole : roleType ,
}
newCtx := proxy . createProxyContext ( & roleCtx , req , resp )
require . Equalf ( t , roleCtx . SignedInUser , newCtx . SignedInUser , "user should not be altered if role is %s" , roleType )
}
} )
} )
}
2022-08-24 14:33:33 -05:00
func Test_containsProvisionedAlerts ( t * testing . T ) {
t . Run ( "should return true if at least one rule is provisioned" , func ( t * testing . T ) {
_ , rules := models2 . GenerateUniqueAlertRules ( rand . Intn ( 4 ) + 2 , models2 . AlertRuleGen ( ) )
provenance := map [ string ] models2 . Provenance {
2023-01-24 12:07:37 -06:00
rules [ rand . Intn ( len ( rules ) ) ] . UID : [ ] models2 . Provenance { models2 . ProvenanceAPI , models2 . ProvenanceFile } [ rand . Intn ( 2 ) ] ,
2022-08-24 14:33:33 -05:00
}
require . Truef ( t , containsProvisionedAlerts ( provenance , rules ) , "the group of rules is expected to be considered as provisioned but it isn't. Provenances: %v" , provenance )
} )
t . Run ( "should return false if map does not contain or has ProvenanceNone" , func ( t * testing . T ) {
_ , rules := models2 . GenerateUniqueAlertRules ( rand . Intn ( 5 ) + 1 , models2 . AlertRuleGen ( ) )
provenance := make ( map [ string ] models2 . Provenance )
2023-01-24 12:07:37 -06:00
numProvenanceNone := rand . Intn ( len ( rules ) )
for i := 0 ; i < numProvenanceNone ; i ++ {
2022-08-24 14:33:33 -05:00
provenance [ rules [ i ] . UID ] = models2 . ProvenanceNone
}
require . Falsef ( t , containsProvisionedAlerts ( provenance , rules ) , "the group of rules is not expected to be provisioned but it is. Provenances: %v" , provenance )
} )
}
2023-06-15 12:33:42 -05:00
type recordingConditionValidator struct {
recorded [ ] models2 . Condition
hook func ( c models2 . Condition ) error
}
func ( r * recordingConditionValidator ) Validate ( _ eval . EvaluationContext , condition models2 . Condition ) error {
r . recorded = append ( r . recorded , condition )
if r . hook != nil {
return r . hook ( condition )
}
return nil
}
var _ ConditionValidator = & recordingConditionValidator { }