2020-08-10 17:15:02 -04:00
// Copyright (c) HashiCorp, Inc.
2020-12-23 11:00:00 -08:00
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2020-06-15 12:42:08 -04:00
package iam
import (
"context"
2020-07-17 09:31:10 -07:00
"fmt"
2020-06-15 12:42:08 -04:00
"testing"
"time"
2020-08-10 17:15:02 -04:00
"github.com/hashicorp/boundary/internal/db"
dbassert "github.com/hashicorp/boundary/internal/db/assert"
2020-11-05 16:54:03 -05:00
"github.com/hashicorp/boundary/internal/errors"
2020-08-10 17:15:02 -04:00
"github.com/hashicorp/boundary/internal/iam/store"
2023-12-15 11:49:59 -08:00
"github.com/hashicorp/boundary/internal/kms"
2020-08-10 17:15:02 -04:00
"github.com/hashicorp/boundary/internal/oplog"
2020-06-15 12:42:08 -04:00
"github.com/hashicorp/go-uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
func TestRepository_CreateRole ( t * testing . T ) {
t . Parallel ()
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2020-07-06 10:15:01 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
2020-06-15 12:42:08 -04:00
rw := db . New ( conn )
wrapper := db . TestWrapper ( t )
2020-08-19 16:47:18 -04:00
repo := TestRepo ( t , conn , wrapper )
2020-06-15 12:42:08 -04:00
id := testId ( t )
2020-08-19 16:47:18 -04:00
org , proj := TestScopes ( t , repo )
2020-06-15 12:42:08 -04:00
type args struct {
role * Role
opt [] Option
}
tests := [] struct {
name string
args args
wantDup bool
wantErr bool
wantErrMsg string
2020-12-23 11:00:00 -08:00
wantIsError errors . Code
2020-06-15 12:42:08 -04:00
}{
{
name : "valid-org" ,
args : args {
role : func () * Role {
2023-06-06 17:09:08 -04:00
r , err := NewRole ( ctx , org . PublicId , WithName ( "valid-org" + id ), WithDescription ( id ))
2020-06-15 12:42:08 -04:00
assert . NoError ( t , err )
return r
}(),
},
wantErr : false ,
},
{
name : "valid-proj" ,
args : args {
role : func () * Role {
2023-06-06 17:09:08 -04:00
r , err := NewRole ( ctx , proj . PublicId , WithName ( "valid-proj" + id ), WithDescription ( id ))
2020-06-15 12:42:08 -04:00
assert . NoError ( t , err )
return r
}(),
},
wantErr : false ,
},
{
name : "bad-public-id" ,
args : args {
role : func () * Role {
2023-06-06 17:09:08 -04:00
r , err := NewRole ( ctx , proj . PublicId , WithName ( "valid-proj" + id ), WithDescription ( id ))
2020-06-15 12:42:08 -04:00
assert . NoError ( t , err )
r . PublicId = id
return r
}(),
},
2020-12-23 11:00:00 -08:00
wantErrMsg : "am.(Repository).CreateRole: public id not empty: parameter violation: error #100" ,
wantIsError : errors . InvalidParameter ,
2020-06-15 12:42:08 -04:00
wantErr : true ,
},
{
name : "nil-role" ,
args : args {
role : nil ,
},
wantErr : true ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.(Repository).CreateRole: missing role: parameter violation: error #100" ,
wantIsError : errors . InvalidParameter ,
2020-06-15 12:42:08 -04:00
},
{
name : "nil-store" ,
args : args {
role : func () * Role {
return & Role {
Role : nil ,
}
}(),
},
wantErr : true ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.(Repository).CreateRole: missing role store: parameter violation: error #100" ,
wantIsError : errors . InvalidParameter ,
2020-06-15 12:42:08 -04:00
},
{
name : "bad-scope-id" ,
args : args {
role : func () * Role {
2023-06-06 17:09:08 -04:00
r , err := NewRole ( ctx , id )
2020-06-15 12:42:08 -04:00
assert . NoError ( t , err )
return r
}(),
},
wantErr : true ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.(Repository).create: error getting metadata: iam.(Repository).stdMetadata: unable to get scope: iam.LookupScope: db.LookupWhere: record not found, search issue: error #1100" ,
wantIsError : errors . RecordNotFound ,
2020-06-15 12:42:08 -04:00
},
{
name : "dup-name" ,
args : args {
role : func () * Role {
2023-06-06 17:09:08 -04:00
r , err := NewRole ( ctx , org . PublicId , WithName ( "dup-name" + id ), WithDescription ( id ))
2020-06-15 12:42:08 -04:00
assert . NoError ( t , err )
return r
}(),
opt : [] Option { WithName ( "dup-name" + id )},
},
wantDup : true ,
wantErr : true ,
wantErrMsg : "already exists in scope " ,
2020-12-23 11:00:00 -08:00
wantIsError : errors . NotUnique ,
2020-06-15 12:42:08 -04:00
},
{
name : "dup-name-but-diff-scope" ,
args : args {
role : func () * Role {
2023-06-06 17:09:08 -04:00
r , err := NewRole ( ctx , proj . PublicId , WithName ( "dup-name-but-diff-scope" + id ), WithDescription ( id ))
2020-06-15 12:42:08 -04:00
assert . NoError ( t , err )
return r
}(),
opt : [] Option { WithName ( "dup-name-but-diff-scope" + id )},
},
wantDup : true ,
wantErr : false ,
},
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert := assert . New ( t )
if tt . wantDup {
2023-06-06 17:09:08 -04:00
dup , err := NewRole ( ctx , org . PublicId , tt . args . opt ... )
2020-06-15 12:42:08 -04:00
assert . NoError ( err )
2024-01-23 14:33:09 -05:00
dup , _ , _ , _ , err = repo . CreateRole ( context . Background (), dup , tt . args . opt ... )
2020-06-15 12:42:08 -04:00
assert . NoError ( err )
assert . NotNil ( dup )
}
2024-01-23 14:33:09 -05:00
grp , _ , _ , _ , err := repo . CreateRole ( context . Background (), tt . args . role , tt . args . opt ... )
2020-06-15 12:42:08 -04:00
if tt . wantErr {
assert . Error ( err )
assert . Nil ( grp )
assert . Contains ( err . Error (), tt . wantErrMsg )
2020-12-23 11:00:00 -08:00
assert . True ( errors . Match ( errors . T ( tt . wantIsError ), err ))
2020-06-15 12:42:08 -04:00
return
}
assert . NoError ( err )
assert . NotNil ( grp . CreateTime )
assert . NotNil ( grp . UpdateTime )
2024-01-23 14:33:09 -05:00
foundGrp , _ , _ , _ , err := repo . LookupRole ( context . Background (), grp . PublicId )
2020-06-15 12:42:08 -04:00
assert . NoError ( err )
assert . True ( proto . Equal ( foundGrp , grp ))
err = db . TestVerifyOplog ( t , rw , grp . PublicId , db . WithOperation ( oplog . OpType_OP_TYPE_CREATE ), db . WithCreateNotBefore ( 10 * time . Second ))
assert . NoError ( err )
})
}
}
func TestRepository_UpdateRole ( t * testing . T ) {
t . Parallel ()
2021-09-30 09:17:27 -04:00
ctx := context . Background ()
2020-07-06 10:15:01 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
2020-06-15 12:42:08 -04:00
rw := db . New ( conn )
wrapper := db . TestWrapper ( t )
2020-08-19 16:47:18 -04:00
repo := TestRepo ( t , conn , wrapper )
2020-06-15 12:42:08 -04:00
id , err := uuid . GenerateUUID ()
require . NoError ( t , err )
2020-08-19 16:47:18 -04:00
org , proj := TestScopes ( t , repo )
u := TestUser ( t , repo , org . GetPublicId ())
2020-07-17 09:31:10 -07:00
2020-06-15 12:42:08 -04:00
pubId := func ( s string ) * string { return & s }
type args struct {
name string
description string
fieldMaskPaths [] string
opt [] Option
ScopeId string
PublicId * string
}
tests := [] struct {
name string
newScopeId string
2020-07-17 09:31:10 -07:00
newRoleOpts [] Option
2020-06-15 12:42:08 -04:00
args args
wantRowsUpdate int
wantErr bool
wantErrMsg string
2020-12-21 10:07:34 -08:00
wantIsError errors . Code
2020-06-15 12:42:08 -04:00
wantDup bool
}{
{
name : "valid" ,
args : args {
name : "valid" + id ,
fieldMaskPaths : [] string { "Name" },
ScopeId : org . PublicId ,
},
newScopeId : org . PublicId ,
wantErr : false ,
wantRowsUpdate : 1 ,
},
{
name : "valid-no-op" ,
args : args {
name : "valid-no-op" + id ,
fieldMaskPaths : [] string { "Name" },
ScopeId : org . PublicId ,
},
newScopeId : org . PublicId ,
2020-07-17 09:31:10 -07:00
newRoleOpts : [] Option { WithName ( "valid-no-op" + id )},
2020-06-15 12:42:08 -04:00
wantErr : false ,
wantRowsUpdate : 1 ,
},
{
name : "not-found" ,
args : args {
name : "not-found" + id ,
fieldMaskPaths : [] string { "Name" },
ScopeId : org . PublicId ,
PublicId : func () * string { s := "1" ; return & s }(),
},
newScopeId : org . PublicId ,
wantErr : true ,
wantRowsUpdate : 0 ,
2022-01-05 14:38:38 -05:00
wantErrMsg : "error #1100" ,
2020-12-21 10:07:34 -08:00
wantIsError : errors . RecordNotFound ,
2020-06-15 12:42:08 -04:00
},
{
name : "null-name" ,
args : args {
name : "" ,
fieldMaskPaths : [] string { "Name" },
ScopeId : org . PublicId ,
},
newScopeId : org . PublicId ,
2020-07-17 09:31:10 -07:00
newRoleOpts : [] Option { WithName ( "null-name" + id )},
2020-06-15 12:42:08 -04:00
wantErr : false ,
wantRowsUpdate : 1 ,
},
{
name : "null-description" ,
args : args {
name : "" ,
fieldMaskPaths : [] string { "Description" },
ScopeId : org . PublicId ,
},
newScopeId : org . PublicId ,
2020-07-17 09:31:10 -07:00
newRoleOpts : [] Option { WithDescription ( "null-description" + id )},
2020-06-15 12:42:08 -04:00
wantErr : false ,
wantRowsUpdate : 1 ,
},
{
name : "empty-field-mask" ,
args : args {
name : "valid" + id ,
fieldMaskPaths : [] string {},
ScopeId : org . PublicId ,
},
newScopeId : org . PublicId ,
wantErr : true ,
wantRowsUpdate : 0 ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.(Repository).UpdateRole: empty field mask, parameter violation: error #104" ,
2020-12-21 10:07:34 -08:00
wantIsError : errors . EmptyFieldMask ,
2020-06-15 12:42:08 -04:00
},
{
name : "nil-fieldmask" ,
args : args {
name : "valid" + id ,
fieldMaskPaths : nil ,
ScopeId : org . PublicId ,
},
newScopeId : org . PublicId ,
wantErr : true ,
wantRowsUpdate : 0 ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.(Repository).UpdateRole: empty field mask, parameter violation: error #104" ,
2020-12-21 10:07:34 -08:00
wantIsError : errors . EmptyFieldMask ,
2020-06-15 12:42:08 -04:00
},
{
name : "read-only-fields" ,
args : args {
name : "valid" + id ,
fieldMaskPaths : [] string { "CreateTime" },
ScopeId : org . PublicId ,
},
newScopeId : org . PublicId ,
wantErr : true ,
wantRowsUpdate : 0 ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.(Repository).UpdateRole: invalid field mask: CreateTime: parameter violation: error #103" ,
2020-12-21 10:07:34 -08:00
wantIsError : errors . InvalidFieldMask ,
2020-06-15 12:42:08 -04:00
},
{
name : "unknown-fields" ,
args : args {
name : "valid" + id ,
fieldMaskPaths : [] string { "Alice" },
ScopeId : org . PublicId ,
},
newScopeId : org . PublicId ,
wantErr : true ,
wantRowsUpdate : 0 ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.(Repository).UpdateRole: invalid field mask: Alice: parameter violation: error #103" ,
2020-12-21 10:07:34 -08:00
wantIsError : errors . InvalidFieldMask ,
2020-06-15 12:42:08 -04:00
},
{
name : "no-public-id" ,
args : args {
name : "valid" + id ,
fieldMaskPaths : [] string { "Name" },
ScopeId : org . PublicId ,
PublicId : pubId ( "" ),
},
newScopeId : org . PublicId ,
wantErr : true ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.(Repository).UpdateRole: missing public id: parameter violation: error #100" ,
2020-12-21 10:07:34 -08:00
wantIsError : errors . InvalidParameter ,
2020-06-15 12:42:08 -04:00
wantRowsUpdate : 0 ,
},
{
name : "proj-scope-id-no-mask" ,
args : args {
name : "proj-scope-id" + id ,
ScopeId : proj . PublicId ,
},
newScopeId : org . PublicId ,
wantErr : true ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.(Repository).UpdateRole: empty field mask, parameter violation: error #104" ,
2020-12-21 10:07:34 -08:00
wantIsError : errors . EmptyFieldMask ,
2020-06-15 12:42:08 -04:00
},
{
name : "empty-scope-id-with-name-mask" ,
args : args {
name : "empty-scope-id" + id ,
fieldMaskPaths : [] string { "Name" },
ScopeId : "" ,
},
newScopeId : org . PublicId ,
wantErr : false ,
wantRowsUpdate : 1 ,
},
{
name : "dup-name-in-diff-scope" ,
args : args {
name : "dup-name-in-diff-scope" + id ,
fieldMaskPaths : [] string { "Name" },
ScopeId : proj . PublicId ,
},
newScopeId : proj . PublicId ,
2020-07-17 09:31:10 -07:00
newRoleOpts : [] Option { WithName ( "dup-name-in-diff-scope-pre-update" + id )},
2020-06-15 12:42:08 -04:00
wantErr : false ,
wantRowsUpdate : 1 ,
wantDup : true ,
},
{
name : "dup-name" ,
args : args {
name : "dup-name" + id ,
fieldMaskPaths : [] string { "Name" },
ScopeId : org . PublicId ,
},
newScopeId : org . PublicId ,
wantErr : true ,
wantDup : true ,
2020-07-11 12:00:49 -04:00
wantErrMsg : " already exists in org " + org . PublicId ,
2020-12-21 10:07:34 -08:00
wantIsError : errors . NotUnique ,
2020-06-15 12:42:08 -04:00
},
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2020-07-10 15:46:26 -04:00
require , assert := require . New ( t ), assert . New ( t )
2020-06-15 12:42:08 -04:00
if tt . wantDup {
r := TestRole ( t , conn , org . PublicId )
2020-07-17 09:31:10 -07:00
_ = TestUserRole ( t , conn , r . GetPublicId (), u . GetPublicId ())
2024-01-17 23:54:49 -08:00
_ = TestRoleGrant ( t , conn , r . GetPublicId (), "ids=*;type=*;actions=*" )
2020-06-15 12:42:08 -04:00
r . Name = tt . args . name
2024-01-23 14:33:09 -05:00
_ , _ , _ , _ , _ , err := repo . UpdateRole ( context . Background (), r , r . Version , tt . args . fieldMaskPaths , tt . args . opt ... )
2020-06-15 12:42:08 -04:00
assert . NoError ( err )
}
2020-07-17 09:31:10 -07:00
r := TestRole ( t , conn , tt . newScopeId , tt . newRoleOpts ... )
ur := TestUserRole ( t , conn , r . GetPublicId (), u . GetPublicId ())
2022-08-10 17:20:06 -04:00
princRole := & PrincipalRole { PrincipalRoleView : & store . PrincipalRoleView {
2020-07-17 09:31:10 -07:00
Type : UserRoleType . String (),
CreateTime : ur . CreateTime ,
RoleId : ur . RoleId ,
PrincipalId : ur . PrincipalId ,
PrincipalScopeId : org . GetPublicId (),
ScopedPrincipalId : ur . PrincipalId ,
RoleScopeId : org . GetPublicId (),
}}
if tt . newScopeId != org . GetPublicId () {
// If the project is in a different scope from the created user we need to update the
// scope specific fields.
princRole . RoleScopeId = tt . newScopeId
princRole . ScopedPrincipalId = fmt . Sprintf ( "%s:%s" , org . PublicId , ur . PrincipalId )
}
2024-01-17 23:54:49 -08:00
rGrant := TestRoleGrant ( t , conn , r . GetPublicId (), "ids=*;type=*;actions=*" )
2020-06-15 12:42:08 -04:00
updateRole := allocRole ()
updateRole . PublicId = r . PublicId
if tt . args . PublicId != nil {
updateRole . PublicId = * tt . args . PublicId
}
updateRole . ScopeId = tt . args . ScopeId
updateRole . Name = tt . args . name
updateRole . Description = tt . args . description
2024-01-23 14:33:09 -05:00
roleAfterUpdate , principals , grants , _ , updatedRows , err := repo . UpdateRole ( context . Background (), & updateRole , r . Version , tt . args . fieldMaskPaths , tt . args . opt ... )
2020-06-15 12:42:08 -04:00
if tt . wantErr {
2024-06-17 12:09:33 -07:00
require . Error ( err )
2021-01-12 08:50:19 -08:00
assert . True ( errors . Match ( errors . T ( tt . wantIsError ), err ))
2020-06-15 12:42:08 -04:00
assert . Nil ( roleAfterUpdate )
assert . Equal ( 0 , updatedRows )
assert . Contains ( err . Error (), tt . wantErrMsg )
err = db . TestVerifyOplog ( t , rw , r . PublicId , db . WithOperation ( oplog . OpType_OP_TYPE_UPDATE ), db . WithCreateNotBefore ( 10 * time . Second ))
assert . Error ( err )
2020-12-21 10:07:34 -08:00
assert . True ( errors . IsNotFoundError ( err ))
2020-06-15 12:42:08 -04:00
return
}
2020-07-10 15:46:26 -04:00
require . NoError ( err )
require . NotNil ( roleAfterUpdate )
2020-06-15 12:42:08 -04:00
assert . Equal ( tt . wantRowsUpdate , updatedRows )
2022-08-10 17:20:06 -04:00
assert . Equal ([] * PrincipalRole { princRole }, principals )
2020-07-17 09:31:10 -07:00
assert . Equal ([] * RoleGrant { rGrant }, grants )
2020-06-15 12:42:08 -04:00
switch tt . name {
case "valid-no-op" :
assert . Equal ( r . UpdateTime , roleAfterUpdate . UpdateTime )
default :
assert . NotEqual ( r . UpdateTime , roleAfterUpdate . UpdateTime )
}
2024-01-23 14:33:09 -05:00
foundRole , _ , _ , _ , err := repo . LookupRole ( context . Background (), r . PublicId )
2020-06-15 12:42:08 -04:00
assert . NoError ( err )
assert . True ( proto . Equal ( roleAfterUpdate , foundRole ))
2021-09-30 09:17:27 -04:00
underlyingDB , err := conn . SqlDB ( ctx )
2021-09-30 08:47:34 -04:00
require . NoError ( err )
dbassert := dbassert . New ( t , underlyingDB )
2020-06-15 12:42:08 -04:00
if tt . args . name == "" {
assert . Equal ( foundRole . Name , "" )
dbassert . IsNull ( foundRole , "name" )
}
if tt . args . description == "" {
assert . Equal ( foundRole . Description , "" )
dbassert . IsNull ( foundRole , "description" )
}
err = db . TestVerifyOplog ( t , rw , r . PublicId , db . WithOperation ( oplog . OpType_OP_TYPE_UPDATE ), db . WithCreateNotBefore ( 10 * time . Second ))
assert . NoError ( err )
})
}
}
func TestRepository_DeleteRole ( t * testing . T ) {
t . Parallel ()
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2020-07-06 10:15:01 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
2020-06-15 12:42:08 -04:00
rw := db . New ( conn )
wrapper := db . TestWrapper ( t )
2020-08-19 16:47:18 -04:00
repo := TestRepo ( t , conn , wrapper )
org , _ := TestScopes ( t , repo )
2020-06-15 12:42:08 -04:00
2023-06-06 17:09:08 -04:00
roleId , err := newRoleId ( ctx )
2020-12-23 11:00:00 -08:00
require . NoError ( t , err )
2020-06-15 12:42:08 -04:00
type args struct {
role * Role
opt [] Option
}
tests := [] struct {
name string
args args
wantRowsDeleted int
wantErr bool
wantErrMsg string
}{
{
name : "valid" ,
args : args {
role : TestRole ( t , conn , org . PublicId ),
},
wantRowsDeleted : 1 ,
wantErr : false ,
},
{
name : "no-public-id" ,
args : args {
role : func () * Role {
2020-09-21 16:50:39 -04:00
r := allocRole ()
return & r
2020-06-15 12:42:08 -04:00
}(),
},
wantRowsDeleted : 0 ,
wantErr : true ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.(Repository).DeleteRole: missing public id: parameter violation: error #100" ,
2020-06-15 12:42:08 -04:00
},
2020-10-01 10:51:54 -04:00
2020-06-15 12:42:08 -04:00
{
name : "not-found" ,
args : args {
role : func () * Role {
2023-06-06 17:09:08 -04:00
r , err := NewRole ( ctx , org . PublicId )
2020-12-23 11:00:00 -08:00
r . PublicId = roleId
2020-06-15 12:42:08 -04:00
require . NoError ( t , err )
return r
}(),
},
wantRowsDeleted : 0 ,
wantErr : true ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.(Repository).DeleteRole: failed for " + roleId + ": db.LookupById: record not found, search issue: error #1100" ,
2020-06-15 12:42:08 -04:00
},
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert := assert . New ( t )
2023-06-06 17:09:08 -04:00
deletedRows , err := repo . DeleteRole ( ctx , tt . args . role . PublicId , tt . args . opt ... )
2020-06-15 12:42:08 -04:00
if tt . wantErr {
assert . Error ( err )
assert . Equal ( 0 , deletedRows )
assert . Contains ( err . Error (), tt . wantErrMsg )
err = db . TestVerifyOplog ( t , rw , tt . args . role . PublicId , db . WithOperation ( oplog . OpType_OP_TYPE_DELETE ), db . WithCreateNotBefore ( 10 * time . Second ))
assert . Error ( err )
2020-12-21 10:07:34 -08:00
assert . True ( errors . IsNotFoundError ( err ))
2020-06-15 12:42:08 -04:00
return
}
assert . NoError ( err )
assert . Equal ( tt . wantRowsDeleted , deletedRows )
2024-01-23 14:33:09 -05:00
foundRole , _ , _ , _ , err := repo . LookupRole ( ctx , tt . args . role . PublicId )
2020-09-04 14:48:11 -07:00
assert . NoError ( err )
2020-06-15 12:42:08 -04:00
assert . Nil ( foundRole )
err = db . TestVerifyOplog ( t , rw , tt . args . role . PublicId , db . WithOperation ( oplog . OpType_OP_TYPE_DELETE ), db . WithCreateNotBefore ( 10 * time . Second ))
assert . NoError ( err )
})
}
}
2020-06-19 12:06:25 -04:00
2023-12-15 11:49:59 -08:00
func TestRepository_listRoles ( t * testing . T ) {
2020-06-19 12:06:25 -04:00
t . Parallel ()
2020-07-06 10:15:01 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
2023-12-15 11:49:59 -08:00
rw := db . New ( conn )
2020-06-19 12:06:25 -04:00
const testLimit = 10
wrapper := db . TestWrapper ( t )
2023-12-15 11:49:59 -08:00
kms := kms . TestKms ( t , conn , wrapper )
2020-08-19 16:47:18 -04:00
repo := TestRepo ( t , conn , wrapper , WithLimit ( testLimit ))
2023-12-15 11:49:59 -08:00
org , proj := TestScopes ( t , repo , WithSkipDefaultRoleCreation ( true ))
2020-06-19 12:06:25 -04:00
type args struct {
withScopeId string
opt [] Option
}
tests := [] struct {
name string
createCnt int
createScopeId string
args args
wantCnt int
wantErr bool
}{
{
2023-12-15 11:49:59 -08:00
name : "negative-limit" ,
2020-06-19 12:06:25 -04:00
createCnt : repo . defaultLimit + 1 ,
createScopeId : org . PublicId ,
args : args {
withScopeId : org . PublicId ,
opt : [] Option { WithLimit ( - 1 )},
},
2021-01-23 13:39:04 -05:00
wantCnt : repo . defaultLimit + 1 ,
2023-12-15 11:49:59 -08:00
wantErr : true ,
2020-06-19 12:06:25 -04:00
},
{
2023-12-15 11:49:59 -08:00
name : "negative-limit-proj-role" ,
2020-06-19 12:06:25 -04:00
createCnt : repo . defaultLimit + 1 ,
createScopeId : proj . PublicId ,
args : args {
withScopeId : proj . PublicId ,
opt : [] Option { WithLimit ( - 1 )},
},
2020-10-13 13:56:21 -04:00
wantCnt : repo . defaultLimit + 1 ,
2023-12-15 11:49:59 -08:00
wantErr : true ,
2020-06-19 12:06:25 -04:00
},
{
name : "default-limit" ,
createCnt : repo . defaultLimit + 1 ,
createScopeId : org . PublicId ,
args : args {
withScopeId : org . PublicId ,
},
wantCnt : repo . defaultLimit ,
wantErr : false ,
},
{
name : "custom-limit" ,
createCnt : repo . defaultLimit + 1 ,
createScopeId : org . PublicId ,
args : args {
withScopeId : org . PublicId ,
opt : [] Option { WithLimit ( 3 )},
},
wantCnt : 3 ,
wantErr : false ,
},
{
name : "bad-org" ,
createCnt : 1 ,
createScopeId : org . PublicId ,
args : args {
withScopeId : "bad-id" ,
},
wantCnt : 0 ,
wantErr : false ,
},
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
2023-12-15 11:49:59 -08:00
t . Cleanup ( func () {
db . TestDeleteWhere ( t , conn , func () any { r := allocRole (); return & r }(), "1=1" )
})
2020-06-19 12:06:25 -04:00
testRoles := [] * Role {}
for i := 0 ; i < tt . createCnt ; i ++ {
testRoles = append ( testRoles , TestRole ( t , conn , tt . createScopeId ))
}
assert . Equal ( tt . createCnt , len ( testRoles ))
2023-12-15 11:49:59 -08:00
got , ttime , err := repo . listRoles ( context . Background (), [] string { tt . args . withScopeId }, tt . args . opt ... )
2020-06-19 12:06:25 -04:00
if tt . wantErr {
require . Error ( err )
return
}
require . NoError ( err )
assert . Equal ( tt . wantCnt , len ( got ))
2023-12-15 11:49:59 -08:00
// Transaction timestamp should be within ~10 seconds of now
assert . True ( time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( time . Now (). After ( ttime . Add ( - 10 * time . Second )))
2020-06-19 12:06:25 -04:00
})
}
2023-12-15 11:49:59 -08:00
t . Run ( "withStartPageAfter" , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
ctx := context . Background ()
for i := 0 ; i < 10 ; i ++ {
_ = TestRole ( t , conn , org . GetPublicId ())
}
repo , err := NewRepository ( ctx , rw , rw , kms )
require . NoError ( err )
page1 , ttime , err := repo . listRoles ( ctx , [] string { org . GetPublicId ()}, WithLimit ( 2 ))
require . NoError ( err )
require . Len ( page1 , 2 )
// Transaction timestamp should be within ~10 seconds of now
assert . True ( time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( time . Now (). After ( ttime . Add ( - 10 * time . Second )))
page2 , ttime , err := repo . listRoles ( ctx , [] string { org . GetPublicId ()}, WithLimit ( 2 ), WithStartPageAfterItem ( page1 [ 1 ]))
require . NoError ( err )
require . Len ( page2 , 2 )
assert . True ( time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( time . Now (). After ( ttime . Add ( - 10 * time . Second )))
for _ , item := range page1 {
assert . NotEqual ( item . GetPublicId (), page2 [ 0 ]. GetPublicId ())
assert . NotEqual ( item . GetPublicId (), page2 [ 1 ]. GetPublicId ())
}
page3 , ttime , err := repo . listRoles ( ctx , [] string { org . GetPublicId ()}, WithLimit ( 2 ), WithStartPageAfterItem ( page2 [ 1 ]))
require . NoError ( err )
require . Len ( page3 , 2 )
assert . True ( time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( time . Now (). After ( ttime . Add ( - 10 * time . Second )))
for _ , item := range page2 {
assert . NotEqual ( item . GetPublicId (), page3 [ 0 ]. GetPublicId ())
assert . NotEqual ( item . GetPublicId (), page3 [ 1 ]. GetPublicId ())
}
page4 , ttime , err := repo . listRoles ( ctx , [] string { org . GetPublicId ()}, WithLimit ( 2 ), WithStartPageAfterItem ( page3 [ 1 ]))
require . NoError ( err )
assert . Len ( page4 , 2 )
assert . True ( time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( time . Now (). After ( ttime . Add ( - 10 * time . Second )))
for _ , item := range page3 {
assert . NotEqual ( item . GetPublicId (), page4 [ 0 ]. GetPublicId ())
assert . NotEqual ( item . GetPublicId (), page4 [ 1 ]. GetPublicId ())
}
page5 , ttime , err := repo . listRoles ( ctx , [] string { org . GetPublicId ()}, WithLimit ( 2 ), WithStartPageAfterItem ( page4 [ 1 ]))
require . NoError ( err )
assert . Len ( page5 , 2 )
assert . True ( time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( time . Now (). After ( ttime . Add ( - 10 * time . Second )))
for _ , item := range page4 {
assert . NotEqual ( item . GetPublicId (), page5 [ 0 ]. GetPublicId ())
assert . NotEqual ( item . GetPublicId (), page5 [ 1 ]. GetPublicId ())
}
page6 , ttime , err := repo . listRoles ( ctx , [] string { org . GetPublicId ()}, WithLimit ( 2 ), WithStartPageAfterItem ( page5 [ 1 ]))
require . NoError ( err )
assert . Empty ( page6 )
assert . True ( time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( time . Now (). After ( ttime . Add ( - 10 * time . Second )))
// Create 2 new roles
newR1 := TestRole ( t , conn , org . GetPublicId ())
newR2 := TestRole ( t , conn , org . GetPublicId ())
// since it will return newest to oldest, we get page1[1] first
page7 , ttime , err := repo . listRolesRefresh (
ctx ,
time . Now (). Add ( - 1 * time . Second ),
[] string { org . GetPublicId ()},
WithLimit ( 1 ),
)
require . NoError ( err )
require . Len ( page7 , 1 )
require . Equal ( page7 [ 0 ]. GetPublicId (), newR2 . GetPublicId ())
assert . True ( time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( time . Now (). After ( ttime . Add ( - 10 * time . Second )))
page8 , ttime , err := repo . listRolesRefresh (
context . Background (),
time . Now (). Add ( - 1 * time . Second ),
[] string { org . GetPublicId ()},
WithLimit ( 1 ),
WithStartPageAfterItem ( page7 [ 0 ]),
)
require . NoError ( err )
require . Len ( page8 , 1 )
require . Equal ( page8 [ 0 ]. GetPublicId (), newR1 . GetPublicId ())
assert . True ( time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( time . Now (). After ( ttime . Add ( - 10 * time . Second )))
})
2020-06-19 12:06:25 -04:00
}
2021-01-23 13:39:04 -05:00
func TestRepository_ListRoles_Multiple_Scopes ( t * testing . T ) {
t . Parallel ()
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
repo := TestRepo ( t , conn , wrapper )
org , proj := TestScopes ( t , repo )
2022-10-25 18:29:38 -05:00
db . TestDeleteWhere ( t , conn , func () any { i := allocRole (); return & i }(), "1=1" )
2021-01-23 13:39:04 -05:00
2021-01-25 19:37:40 -05:00
const numPerScope = 10
var total int
for i := 0 ; i < numPerScope ; i ++ {
TestRole ( t , conn , "global" )
total ++
TestRole ( t , conn , org . GetPublicId ())
total ++
TestRole ( t , conn , proj . GetPublicId ())
total ++
2021-01-23 13:39:04 -05:00
}
2023-12-15 11:49:59 -08:00
got , ttime , err := repo . listRoles ( context . Background (), [] string { "global" , org . GetPublicId (), proj . GetPublicId ()})
require . NoError ( t , err )
2023-12-20 16:51:57 -08:00
assert . Equal ( t , total , len ( got ))
// Transaction timestamp should be within ~10 seconds of now
2023-12-15 11:49:59 -08:00
assert . True ( t , time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( t , time . Now (). After ( ttime . Add ( - 10 * time . Second )))
}
func Test_listRoleDeletedIds ( t * testing . T ) {
t . Parallel ()
ctx := context . Background ()
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
repo := TestRepo ( t , conn , wrapper )
org , _ := TestScopes ( t , repo , WithSkipDefaultRoleCreation ( true ))
r := TestRole ( t , conn , org . GetPublicId ())
// Expect no entries at the start
deletedIds , ttime , err := repo . listRoleDeletedIds ( ctx , time . Now (). AddDate ( - 1 , 0 , 0 ))
require . NoError ( t , err )
require . Empty ( t , deletedIds )
// Transaction timestamp should be within ~10 seconds of now
assert . True ( t , time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( t , time . Now (). After ( ttime . Add ( - 10 * time . Second )))
// Delete a role
_ , err = repo . DeleteRole ( ctx , r . GetPublicId ())
require . NoError ( t , err )
// Expect a single entry
deletedIds , ttime , err = repo . listRoleDeletedIds ( ctx , time . Now (). AddDate ( - 1 , 0 , 0 ))
require . NoError ( t , err )
require . Equal ( t , [] string { r . GetPublicId ()}, deletedIds )
// Transaction timestamp should be within ~10 seconds of now
assert . True ( t , time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( t , time . Now (). After ( ttime . Add ( - 10 * time . Second )))
// Try again with the time set to now, expect no entries
deletedIds , ttime , err = repo . listRoleDeletedIds ( ctx , time . Now ())
require . NoError ( t , err )
require . Empty ( t , deletedIds )
// Transaction timestamp should be within ~10 seconds of now
assert . True ( t , time . Now (). Before ( ttime . Add ( 10 * time . Second )))
assert . True ( t , time . Now (). After ( ttime . Add ( - 10 * time . Second )))
}
func Test_estimatedRoleCount ( t * testing . T ) {
t . Parallel ()
ctx := context . Background ()
conn , _ := db . TestSetup ( t , "postgres" )
sqlDb , err := conn . SqlDB ( ctx )
require . NoError ( t , err )
rw := db . New ( conn )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
repo , err := NewRepository ( ctx , rw , rw , kms )
require . NoError ( t , err )
// Run analyze to update estimate
_ , err = sqlDb . ExecContext ( ctx , "analyze" )
require . NoError ( t , err )
// Check total entries at start, expect 0
numItems , err := repo . estimatedRoleCount ( ctx )
require . NoError ( t , err )
assert . Equal ( t , 0 , numItems )
iamRepo := TestRepo ( t , conn , wrapper )
org , _ := TestScopes ( t , iamRepo , WithSkipDefaultRoleCreation ( true ))
// Create a role, expect 1 entry
r := TestRole ( t , conn , org . GetPublicId ())
// Run analyze to update estimate
_ , err = sqlDb . ExecContext ( ctx , "analyze" )
require . NoError ( t , err )
numItems , err = repo . estimatedRoleCount ( ctx )
require . NoError ( t , err )
assert . Equal ( t , 1 , numItems )
// Delete the role, expect 0 again
_ , err = repo . DeleteRole ( ctx , r . GetPublicId ())
require . NoError ( t , err )
// Run analyze to update estimate
_ , err = sqlDb . ExecContext ( ctx , "analyze" )
require . NoError ( t , err )
numItems , err = repo . estimatedRoleCount ( ctx )
2021-01-23 13:39:04 -05:00
require . NoError ( t , err )
2023-12-15 11:49:59 -08:00
assert . Equal ( t , 0 , numItems )
2021-01-23 13:39:04 -05:00
}