2020-08-10 17:15:02 -04:00
// Copyright (c) HashiCorp, Inc.
2020-12-21 10:07:34 -08:00
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2020-06-11 16:36:47 -04:00
package iam
import (
"context"
"testing"
"time"
2022-08-11 17:24:14 -07:00
"github.com/google/go-cmp/cmp"
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"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/boundary/internal/types/action"
"github.com/hashicorp/boundary/internal/types/resource"
2020-06-11 16:36:47 -04:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
2022-08-11 17:24:14 -07:00
"google.golang.org/protobuf/testing/protocmp"
2020-06-11 16:36:47 -04:00
)
func TestNewGroup ( 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-08-19 16:47:18 -04:00
wrapper := db . TestWrapper ( t )
repo := TestRepo ( t , conn , wrapper )
org , proj := TestScopes ( t , repo )
2020-06-11 16:36:47 -04:00
id := testId ( t )
type args struct {
scopePublicId string
opt [] Option
}
tests := [] struct {
name string
args args
wantErr bool
wantErrMsg string
2020-12-23 11:00:00 -08:00
wantIsErr errors . Code
2020-06-11 16:36:47 -04:00
wantName string
wantDescription string
}{
{
name : "valid" ,
args : args {
scopePublicId : org . PublicId ,
opt : [] Option { WithName ( id ), WithDescription ( "description-" + id )},
},
wantErr : false ,
wantName : id ,
wantDescription : "description-" + id ,
},
{
name : "valid-proj" ,
args : args {
scopePublicId : proj . PublicId ,
opt : [] Option { WithName ( id ), WithDescription ( "description-" + id )},
},
wantErr : false ,
wantName : id ,
wantDescription : "description-" + id ,
},
{
name : "valid-with-no-options" + id ,
args : args {
scopePublicId : org . PublicId ,
},
wantErr : false ,
},
{
name : "no-scope" ,
args : args {
opt : [] Option { WithName ( id )},
},
wantErr : true ,
2020-12-23 11:00:00 -08:00
wantErrMsg : "iam.NewGroup: missing scope id: parameter violation: error #100" ,
wantIsErr : errors . InvalidParameter ,
2020-06-11 16:36:47 -04:00
},
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
2023-06-06 17:09:08 -04:00
got , err := NewGroup ( ctx , tt . args . scopePublicId , tt . args . opt ... )
2020-06-11 16:36:47 -04:00
if tt . wantErr {
require . Error ( err )
2020-11-05 16:54:03 -05:00
assert . Contains ( err . Error (), tt . wantErrMsg )
2021-01-12 08:50:19 -08:00
assert . True ( errors . Match ( errors . T ( tt . wantIsErr ), err ))
2020-06-11 16:36:47 -04:00
return
}
require . NoError ( err )
assert . Equal ( tt . wantName , got . Name )
assert . Equal ( tt . wantDescription , got . Description )
assert . Empty ( got . PublicId )
})
}
}
func Test_GroupCreate ( 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-08-19 16:47:18 -04:00
wrapper := db . TestWrapper ( t )
repo := TestRepo ( t , conn , wrapper )
org , proj := TestScopes ( t , repo )
2020-06-11 16:36:47 -04:00
type args struct {
group * Group
}
tests := [] struct {
name string
args args
wantDup bool
wantErr bool
wantErrMsg string
wantIsError error
}{
{
name : "valid-with-org" ,
args : args {
group : func () * Group {
id := testId ( t )
2023-06-06 17:09:08 -04:00
grp , err := NewGroup ( ctx , org . PublicId , WithName ( id ), WithDescription ( "description-" + id ))
2020-06-11 16:36:47 -04:00
require . NoError ( t , err )
2023-06-06 17:09:08 -04:00
grpId , err := newGroupId ( ctx )
2020-06-11 16:36:47 -04:00
require . NoError ( t , err )
grp . PublicId = grpId
return grp
}(),
},
wantErr : false ,
},
{
name : "valid-with-proj" ,
args : args {
group : func () * Group {
id := testId ( t )
2023-06-06 17:09:08 -04:00
grp , err := NewGroup ( ctx , proj . PublicId , WithName ( id ), WithDescription ( "description-" + id ))
2020-06-11 16:36:47 -04:00
require . NoError ( t , err )
2023-06-06 17:09:08 -04:00
grpId , err := newGroupId ( ctx )
2020-06-11 16:36:47 -04:00
require . NoError ( t , err )
grp . PublicId = grpId
return grp
}(),
},
wantErr : false ,
},
{
name : "valid-with-dup-null-names-and-descriptions" ,
args : args {
group : func () * Group {
2023-06-06 17:09:08 -04:00
grp , err := NewGroup ( ctx , org . PublicId )
2020-06-11 16:36:47 -04:00
require . NoError ( t , err )
2023-06-06 17:09:08 -04:00
grpId , err := newGroupId ( ctx )
2020-06-11 16:36:47 -04:00
require . NoError ( t , err )
grp . PublicId = grpId
return grp
}(),
},
wantDup : true ,
wantErr : false ,
},
{
name : "bad-scope-id" ,
args : args {
group : func () * Group {
id := testId ( t )
2023-06-06 17:09:08 -04:00
grp , err := NewGroup ( ctx , id )
2020-06-11 16:36:47 -04:00
require . NoError ( t , err )
2023-06-06 17:09:08 -04:00
grpId , err := newGroupId ( ctx )
2020-06-11 16:36:47 -04:00
require . NoError ( t , err )
grp . PublicId = grpId
return grp
}(),
},
wantErr : true ,
2022-01-05 14:38:38 -05:00
wantErrMsg : "iam.validateScopeForWrite: scope is not found: search issue: error #1100" ,
2020-06-11 16:36:47 -04:00
},
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
w := db . New ( conn )
if tt . wantDup {
g := tt . args . group . Clone ().( * Group )
2023-06-06 17:09:08 -04:00
grpId , err := newGroupId ( ctx )
2020-06-11 16:36:47 -04:00
require . NoError ( err )
g . PublicId = grpId
2023-06-06 17:09:08 -04:00
err = w . Create ( ctx , g )
2020-06-11 16:36:47 -04:00
require . NoError ( err )
}
g := tt . args . group . Clone ().( * Group )
2023-06-06 17:09:08 -04:00
err := w . Create ( ctx , g )
2020-06-11 16:36:47 -04:00
if tt . wantErr {
require . Error ( err )
2022-01-05 14:38:38 -05:00
assert . Contains ( err . Error (), tt . wantErrMsg )
2020-06-11 16:36:47 -04:00
return
}
assert . NoError ( err )
assert . NotEmpty ( tt . args . group . PublicId )
foundGrp := allocGroup ()
foundGrp . PublicId = tt . args . group . PublicId
2023-06-06 17:09:08 -04:00
err = w . LookupByPublicId ( ctx , & foundGrp )
2020-06-11 16:36:47 -04:00
require . NoError ( err )
2022-08-11 17:24:14 -07:00
assert . Empty ( cmp . Diff ( g , & foundGrp , protocmp . Transform ()))
2020-06-11 16:36:47 -04:00
})
}
}
func Test_GroupUpdate ( 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-08-19 16:47:18 -04:00
wrapper := db . TestWrapper ( t )
repo := TestRepo ( t , conn , wrapper )
2020-06-11 16:36:47 -04:00
id := testId ( t )
2020-08-19 16:47:18 -04:00
org , proj := TestScopes ( t , repo )
2020-06-11 16:36:47 -04:00
rw := db . New ( conn )
type args struct {
name string
description string
fieldMaskPaths [] string
nullPaths [] string
ScopeId string
}
tests := [] struct {
name string
args args
wantRowsUpdate int
wantErr bool
wantErrMsg string
wantDup bool
}{
{
name : "valid" ,
args : args {
name : "valid" + id ,
fieldMaskPaths : [] string { "Name" },
ScopeId : org . PublicId ,
},
wantErr : false ,
wantRowsUpdate : 1 ,
},
{
name : "proj-scope-id" ,
args : args {
name : "proj-scope-id" + id ,
fieldMaskPaths : [] string { "ScopeId" },
ScopeId : proj . PublicId ,
},
wantErr : true ,
2022-01-05 14:38:38 -05:00
wantErrMsg : "db.Update: dbw.Update: error before write: iam.(Group).VetForWrite: iam.validateScopeForWrite: not allowed to change a resource's scope: parameter violation: error #100" ,
2020-06-11 16:36:47 -04:00
},
{
name : "proj-scope-id-not-in-mask" ,
args : args {
name : "proj-scope-id" + id ,
fieldMaskPaths : [] string { "Name" },
ScopeId : proj . PublicId ,
},
wantErr : false ,
wantRowsUpdate : 1 ,
},
{
name : "empty-scope-id" ,
args : args {
name : "empty-scope-id" + id ,
fieldMaskPaths : [] string { "Name" },
ScopeId : "" ,
},
wantErr : false ,
wantRowsUpdate : 1 ,
},
{
name : "dup-name" ,
args : args {
name : "dup-name" + id ,
fieldMaskPaths : [] string { "Name" },
ScopeId : org . PublicId ,
},
wantErr : true ,
wantDup : true ,
2023-05-01 12:40:10 -07:00
wantErrMsg : `db.Update: duplicate key value violates unique constraint "iam_group_name_scope_id_uq": unique constraint violation: integrity violation: error #1002` ,
2020-06-11 16:36:47 -04:00
},
{
name : "set description null" ,
args : args {
name : "set description null" + id ,
fieldMaskPaths : [] string { "Name" },
nullPaths : [] string { "Description" },
ScopeId : org . PublicId ,
},
wantErr : false ,
wantRowsUpdate : 1 ,
},
{
name : "set name null" ,
args : args {
description : "set description null" + id ,
fieldMaskPaths : [] string { "Description" },
nullPaths : [] string { "Name" },
ScopeId : org . PublicId ,
},
wantDup : true ,
wantErr : false ,
wantRowsUpdate : 1 ,
},
{
name : "set description null" ,
args : args {
name : "set name null" + id ,
fieldMaskPaths : [] string { "Name" },
nullPaths : [] string { "Description" },
ScopeId : org . PublicId ,
},
wantErr : false ,
wantRowsUpdate : 1 ,
},
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
if tt . wantDup {
grp := TestGroup ( t , conn , org . PublicId )
grp . Name = tt . args . name
_ , err := rw . Update ( context . Background (), grp , tt . args . fieldMaskPaths , tt . args . nullPaths )
require . NoError ( err )
}
id := testId ( t )
grp := TestGroup ( t , conn , org . PublicId , WithDescription ( id ), WithName ( id ))
updateGrp := allocGroup ()
updateGrp . PublicId = grp . PublicId
updateGrp . ScopeId = tt . args . ScopeId
updateGrp . Name = tt . args . name
updateGrp . Description = tt . args . description
updatedRows , err := rw . Update ( context . Background (), & updateGrp , tt . args . fieldMaskPaths , tt . args . nullPaths )
if tt . wantErr {
require . Error ( err )
assert . Equal ( 0 , updatedRows )
assert . Equal ( tt . wantErrMsg , err . Error ())
err = db . TestVerifyOplog ( t , rw , grp . PublicId , db . WithOperation ( oplog . OpType_OP_TYPE_UPDATE ), db . WithCreateNotBefore ( 10 * time . Second ))
require . Error ( err )
2020-11-05 16:54:03 -05:00
assert . Contains ( err . Error (), "record not found" )
2020-06-11 16:36:47 -04:00
return
}
require . NoError ( err )
assert . Equal ( tt . wantRowsUpdate , updatedRows )
assert . NotEqual ( grp . UpdateTime , updateGrp . UpdateTime )
foundGrp := allocGroup ()
foundGrp . PublicId = grp . GetPublicId ()
err = rw . LookupByPublicId ( context . Background (), & foundGrp )
require . NoError ( err )
assert . True ( proto . Equal ( updateGrp , foundGrp ))
if len ( tt . args . nullPaths ) != 0 {
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-11 16:36:47 -04:00
for _ , f := range tt . args . nullPaths {
dbassert . IsNull ( & foundGrp , f )
}
}
})
}
t . Run ( "update dup names in diff scopes" , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
id := testId ( t )
_ = TestGroup ( t , conn , org . PublicId , WithDescription ( id ), WithName ( id ))
projGrp := TestGroup ( t , conn , proj . PublicId )
projGrp . Name = id
updatedRows , err := rw . Update ( context . Background (), projGrp , [] string { "Name" }, nil )
require . NoError ( err )
assert . Equal ( 1 , updatedRows )
foundGrp := allocGroup ()
foundGrp . PublicId = projGrp . GetPublicId ()
err = rw . LookupByPublicId ( context . Background (), & foundGrp )
require . NoError ( err )
assert . Equal ( id , projGrp . Name )
})
}
func Test_GroupDelete ( t * testing . T ) {
t . Parallel ()
2020-07-06 10:15:01 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
2020-08-19 16:47:18 -04:00
wrapper := db . TestWrapper ( t )
repo := TestRepo ( t , conn , wrapper )
2020-06-11 16:36:47 -04:00
rw := db . New ( conn )
id := testId ( t )
2020-08-19 16:47:18 -04:00
org , _ := TestScopes ( t , repo )
2020-06-11 16:36:47 -04:00
tests := [] struct {
name string
group * Group
wantRowsDeleted int
wantErr bool
wantErrMsg string
}{
{
name : "valid" ,
group : TestGroup ( t , conn , org . PublicId ),
wantErr : false ,
wantRowsDeleted : 1 ,
},
{
name : "bad-id" ,
group : func () * Group { g := allocGroup (); g . PublicId = id ; return & g }(),
wantErr : false ,
wantRowsDeleted : 0 ,
},
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
deleteGroup := allocGroup ()
deleteGroup . PublicId = tt . group . GetPublicId ()
deletedRows , err := rw . Delete ( context . Background (), & deleteGroup )
if tt . wantErr {
require . Error ( err )
return
}
require . NoError ( err )
if tt . wantRowsDeleted == 0 {
assert . Equal ( tt . wantRowsDeleted , deletedRows )
return
}
assert . Equal ( tt . wantRowsDeleted , deletedRows )
foundGrp := allocGroup ()
foundGrp . PublicId = tt . group . GetPublicId ()
err = rw . LookupByPublicId ( context . Background (), & foundGrp )
require . Error ( err )
2020-12-21 10:07:34 -08:00
assert . True ( errors . IsNotFoundError ( err ))
2020-06-11 16:36:47 -04:00
})
}
}
func TestGroup_Actions ( t * testing . T ) {
assert := assert . New ( t )
r := & Group {}
a := r . Actions ()
2020-06-26 11:00:14 -04:00
assert . Equal ( a [ action . Create . String ()], action . Create )
assert . Equal ( a [ action . Update . String ()], action . Update )
assert . Equal ( a [ action . Read . String ()], action . Read )
assert . Equal ( a [ action . Delete . String ()], action . Delete )
2020-06-11 16:36:47 -04:00
}
func TestGroup_ResourceType ( t * testing . T ) {
assert := assert . New ( t )
r := & Group {}
2023-10-23 15:53:29 -07:00
ty := r . GetResourceType ()
2020-07-31 17:46:04 -04:00
assert . Equal ( ty , resource . Group )
2020-06-11 16:36:47 -04:00
}
func TestGroup_GetScope ( t * testing . T ) {
t . Parallel ()
2020-07-06 10:15:01 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
2020-08-19 16:47:18 -04:00
wrapper := db . TestWrapper ( t )
repo := TestRepo ( t , conn , wrapper )
org , proj := TestScopes ( t , repo )
2020-06-11 16:36:47 -04:00
t . Run ( "valid-org" , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
w := db . New ( conn )
grp := TestGroup ( t , conn , org . PublicId )
scope , err := grp . GetScope ( context . Background (), w )
require . NoError ( err )
assert . True ( proto . Equal ( org , scope ))
})
t . Run ( "valid-proj" , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
w := db . New ( conn )
grp := TestGroup ( t , conn , proj . PublicId )
scope , err := grp . GetScope ( context . Background (), w )
require . NoError ( err )
assert . True ( proto . Equal ( proj , scope ))
})
}
func TestGroup_Clone ( t * testing . T ) {
t . Parallel ()
2020-07-06 10:15:01 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
2020-08-19 16:47:18 -04:00
wrapper := db . TestWrapper ( t )
repo := TestRepo ( t , conn , wrapper )
org , _ := TestScopes ( t , repo )
2020-06-11 16:36:47 -04:00
t . Run ( "valid" , func ( t * testing . T ) {
assert := assert . New ( t )
grp := TestGroup ( t , conn , org . PublicId )
cp := grp . Clone ()
assert . True ( proto . Equal ( cp .( * Group ). Group , grp . Group ))
})
t . Run ( "not-equal" , func ( t * testing . T ) {
assert := assert . New ( t )
grp := TestGroup ( t , conn , org . PublicId )
grp2 := TestGroup ( t , conn , org . PublicId )
cp := grp . Clone ()
assert . True (! proto . Equal ( cp .( * Group ). Group , grp2 . Group ))
})
}
2020-07-17 16:20:56 -04:00
func TestGroup_SetTableName ( t * testing . T ) {
defaultTableName := defaultGroupTableName
tests := [] struct {
name string
initialName string
setNameTo string
want string
}{
{
name : "new-name" ,
initialName : "" ,
setNameTo : "new-name" ,
want : "new-name" ,
},
{
name : "reset to default" ,
initialName : "initial" ,
setNameTo : "" ,
want : defaultTableName ,
},
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
def := allocGroup ()
require . Equal ( defaultTableName , def . TableName ())
s := & Group {
Group : & store . Group {},
tableName : tt . initialName ,
}
s . SetTableName ( tt . setNameTo )
assert . Equal ( tt . want , s . TableName ())
})
}
}