Files
threshold/internal/auth/password/repository_authmethod_test.go
T
Jim 8d6dee09a9 refact: Add db.DB wrapper and refact all test fixtures to use it. (#1535)
* refact: Changes required for gorm v2

* refact: Add db.DB wrapper and refact all test fixtures to use it

Stop leaking the gorm abstraction within our unit tests.

* refact: Migrate direct calls to pq to pgx driver

The refactor will remove the remaining direct dependencies on
the pq driver which has been deprecated in favor of the pgx
driver.

It includes the addition of common.SqlOpen which is a wrapper around
sql.Open, which is needed to deal with the driver name changing from
"postgres" to "pgx" but in our code base the dialect and driver are
synonyms.
2021-09-30 09:17:27 -04:00

795 lines
22 KiB
Go

package password
import (
"context"
"strings"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/boundary/internal/auth/password/store"
"github.com/hashicorp/boundary/internal/db"
dbassert "github.com/hashicorp/boundary/internal/db/assert"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
)
func TestRepository_CreateAuthMethod(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
org, _ := iam.TestScopes(t, iamRepo)
tests := []struct {
name string
in *AuthMethod
opts []Option
want *AuthMethod
wantIsErr errors.Code
wantErrMsg string
}{
{
name: "nil-AuthMethod",
wantIsErr: errors.InvalidParameter,
wantErrMsg: "password.(Repository).CreateAuthMethod: missing AuthMethod: parameter violation: error #100",
},
{
name: "nil-embedded-AuthMethod",
in: &AuthMethod{},
wantIsErr: errors.InvalidParameter,
wantErrMsg: "password.(Repository).CreateAuthMethod: missing embedded AuthMethod: parameter violation: error #100",
},
{
name: "invalid-no-scope-id",
in: &AuthMethod{
AuthMethod: &store.AuthMethod{},
},
wantIsErr: errors.InvalidParameter,
wantErrMsg: "password.(Repository).CreateAuthMethod: missing scope id: parameter violation: error #100",
},
{
name: "invalid-public-id-set",
in: &AuthMethod{
AuthMethod: &store.AuthMethod{
ScopeId: org.PublicId,
PublicId: "hcst_OOOOOOOOOO",
},
},
wantIsErr: errors.InvalidParameter,
wantErrMsg: "password.(Repository).CreateAuthMethod: public id not empty: parameter violation: error #100",
},
{
name: "valid-no-options",
in: &AuthMethod{
AuthMethod: &store.AuthMethod{
ScopeId: org.PublicId,
},
},
want: &AuthMethod{
AuthMethod: &store.AuthMethod{
ScopeId: org.PublicId,
},
},
},
{
name: "valid-with-name",
in: &AuthMethod{
AuthMethod: &store.AuthMethod{
ScopeId: org.PublicId,
Name: "test-name-repo",
},
},
want: &AuthMethod{
AuthMethod: &store.AuthMethod{
ScopeId: org.PublicId,
Name: "test-name-repo",
},
},
},
{
name: "valid-with-description",
in: &AuthMethod{
AuthMethod: &store.AuthMethod{
ScopeId: org.PublicId,
Description: ("test-description-repo"),
},
},
want: &AuthMethod{
AuthMethod: &store.AuthMethod{
ScopeId: org.PublicId,
Description: ("test-description-repo"),
},
},
},
{
name: "invalid-with-config-nil-embedded-config",
in: &AuthMethod{
AuthMethod: &store.AuthMethod{
ScopeId: org.PublicId,
},
},
opts: []Option{
WithConfiguration(&Argon2Configuration{}),
},
wantIsErr: errors.PasswordInvalidConfiguration,
wantErrMsg: "password.(Repository).CreateAuthMethod: password.(Argon2Configuration).validate: missing embedded config: password violation: error #202",
},
{
name: "invalid-with-config-unknown-config-type",
in: &AuthMethod{
AuthMethod: &store.AuthMethod{
ScopeId: org.PublicId,
},
},
opts: []Option{
WithConfiguration(tconf(0)),
},
wantIsErr: errors.PasswordUnsupportedConfiguration,
wantErrMsg: "password.(Repository).CreateAuthMethod: unknown configuration: password violation: error #201",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
repo, err := NewRepository(rw, rw, kms)
require.NoError(err)
require.NotNil(repo)
got, err := repo.CreateAuthMethod(context.Background(), tt.in, tt.opts...)
if tt.wantIsErr != 0 {
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "Unexpected error %s", err)
assert.Equal(tt.wantErrMsg, err.Error())
return
}
require.NoError(err)
assert.Empty(tt.in.PublicId)
require.NotNil(got)
assertPublicId(t, AuthMethodPrefix, got.PublicId)
assert.NotSame(tt.in, got)
assert.Equal(tt.want.Name, got.Name)
assert.Equal(tt.want.Description, got.Description)
assert.Equal(got.CreateTime, got.UpdateTime)
})
}
}
func TestRepository_CreateAuthMethod_DupeNames(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
t.Run("invalid-duplicate-names", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
repo, err := NewRepository(rw, rw, kms)
require.NoError(err)
require.NotNil(repo)
org, _ := iam.TestScopes(t, iamRepo)
in := &AuthMethod{
AuthMethod: &store.AuthMethod{
ScopeId: org.GetPublicId(),
Name: "test-name-repo",
},
}
got, err := repo.CreateAuthMethod(context.Background(), in)
require.NoError(err)
require.NotNil(got)
assertPublicId(t, AuthMethodPrefix, got.PublicId)
assert.NotSame(in, got)
assert.Equal(in.Name, got.Name)
assert.Equal(in.Description, got.Description)
assert.Equal(got.CreateTime, got.UpdateTime)
got2, err := repo.CreateAuthMethod(context.Background(), in)
assert.Truef(errors.Match(errors.T(errors.NotUnique), err), "Unexpected error %s", err)
assert.Nil(got2)
})
t.Run("valid-duplicate-names-diff-scopes", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
repo, err := NewRepository(rw, rw, kms)
require.NoError(err)
require.NotNil(repo)
org1, _ := iam.TestScopes(t, iamRepo)
in := &AuthMethod{
AuthMethod: &store.AuthMethod{
Name: "test-name-repo",
},
}
in2 := in.Clone()
in.ScopeId = org1.GetPublicId()
got, err := repo.CreateAuthMethod(context.Background(), in)
require.NoError(err)
require.NotNil(got)
assertPublicId(t, AuthMethodPrefix, got.PublicId)
assert.NotSame(in, got)
assert.Equal(in.Name, got.Name)
assert.Equal(in.Description, got.Description)
assert.Equal(got.CreateTime, got.UpdateTime)
org2, _ := iam.TestScopes(t, iamRepo)
in2.ScopeId = org2.GetPublicId()
got2, err := repo.CreateAuthMethod(context.Background(), in2)
require.NoError(err)
require.NotNil(got2)
assertPublicId(t, AuthMethodPrefix, got2.PublicId)
assert.NotSame(in2, got2)
assert.Equal(in2.Name, got2.Name)
assert.Equal(in2.Description, got2.Description)
assert.Equal(got2.CreateTime, got2.UpdateTime)
})
}
func TestRepository_CreateAuthMethod_PublicId(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
t.Run("valid-with-publicid", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
repo, err := NewRepository(rw, rw, kms)
require.NoError(err)
require.NotNil(repo)
org1, _ := iam.TestScopes(t, iamRepo)
in := allocAuthMethod()
amId, err := newAuthMethodId()
require.NoError(err)
in.ScopeId = org1.GetPublicId()
got, err := repo.CreateAuthMethod(context.Background(), &in, WithPublicId(amId))
require.NoError(err)
require.NotNil(got)
assert.Equal(amId, got.GetPublicId())
assert.Equal(got.CreateTime, got.UpdateTime)
})
t.Run("invalid-with-badpublicid", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
repo, err := NewRepository(rw, rw, kms)
require.NoError(err)
require.NotNil(repo)
org1, _ := iam.TestScopes(t, iamRepo)
in := allocAuthMethod()
in.ScopeId = org1.GetPublicId()
got, err := repo.CreateAuthMethod(context.Background(), &in, WithPublicId("invalid_idwithabadprefix"))
assert.Error(err)
assert.Nil(got)
assert.Truef(errors.Match(errors.T(errors.InvalidPublicId), err), "Unexpected error %s", err)
})
}
func TestRepository_LookupAuthMethod(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
o, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
authMethod := TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
amId, err := newAuthMethodId()
require.NoError(t, err)
tests := []struct {
name string
in string
want *AuthMethod
wantIsErr errors.Code
wantErrMsg string
}{
{
name: "With no public id",
wantIsErr: errors.InvalidPublicId,
wantErrMsg: "password.(Repository).LookupAuthMethod: missing public id: parameter violation: error #102",
},
{
name: "With non existing auth method id",
in: amId,
},
{
name: "With existing auth method id",
in: authMethod.GetPublicId(),
want: authMethod,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
repo, err := NewRepository(rw, rw, kms)
assert.NoError(err)
require.NotNil(repo)
got, err := repo.LookupAuthMethod(context.Background(), tt.in)
if tt.wantIsErr != 0 {
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "Unexpected error %s", err)
assert.Equal(tt.wantErrMsg, err.Error())
return
}
require.NoError(err)
assert.EqualValues(tt.want, got)
})
}
}
func TestRepository_DeleteAuthMethod(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
o, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
authMethod := TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
newAuthMethodId, err := newAuthMethodId()
require.NoError(t, err)
tests := []struct {
name string
in string
want int
wantIsErr errors.Code
wantErrMsg string
}{
{
name: "With no public id",
wantIsErr: errors.InvalidPublicId,
wantErrMsg: "password.(Repository).DeleteAuthMethod: missing public id: parameter violation: error #102",
},
{
name: "With non existing auth method id",
in: newAuthMethodId,
want: 0,
},
{
name: "With existing auth method id",
in: authMethod.GetPublicId(),
want: 1,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
repo, err := NewRepository(rw, rw, kms)
assert.NoError(err)
require.NotNil(repo)
got, err := repo.DeleteAuthMethod(context.Background(), o.GetPublicId(), tt.in)
if tt.wantIsErr != 0 {
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "Unexpected error %s", err)
assert.Equal(tt.wantErrMsg, err.Error())
return
}
require.NoError(err)
assert.EqualValues(tt.want, got)
})
}
}
func TestRepository_ListAuthMethods(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
noAuthMethodOrg, _ := iam.TestScopes(t, iamRepo)
o, _ := iam.TestScopes(t, iamRepo)
authMethods := TestAuthMethods(t, conn, o.GetPublicId(), 3)
tests := []struct {
name string
in []string
opts []Option
want []*AuthMethod
wantIsErr errors.Code
wantErrMsg string
}{
{
name: "With no scope id",
wantIsErr: errors.InvalidParameter,
wantErrMsg: "password.(Repository).ListAuthMethods: missing scope id: parameter violation: error #100",
},
{
name: "Scope with no auth methods",
in: []string{noAuthMethodOrg.GetPublicId()},
want: nil,
},
{
name: "With populated scope id",
in: []string{o.GetPublicId()},
want: authMethods,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
repo, err := NewRepository(rw, rw, kms)
assert.NoError(err)
require.NotNil(repo)
got, err := repo.ListAuthMethods(context.Background(), tt.in, tt.opts...)
if tt.wantIsErr != 0 {
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "Unexpected error %s", err)
assert.Equal(tt.wantErrMsg, err.Error())
return
}
require.NoError(err)
assert.Empty(cmp.Diff(tt.want, got, protocmp.Transform()))
})
}
}
func TestRepository_ListAuthMethods_Multiple_Scopes(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
repo, err := NewRepository(rw, rw, kms)
require.NoError(t, err)
var total int
const numPerScope = 10
TestAuthMethods(t, conn, "global", numPerScope)
total += numPerScope
scopeIds := []string{"global"}
for i := 0; i < 10; i++ {
o := iam.TestOrg(t, iamRepo)
scopeIds = append(scopeIds, o.GetPublicId())
ams := TestAuthMethods(t, conn, o.GetPublicId(), numPerScope)
iam.TestSetPrimaryAuthMethod(t, iam.TestRepo(t, conn, wrapper), o, ams[0].PublicId)
total += numPerScope
}
got, err := repo.ListAuthMethods(context.Background(), scopeIds, WithOrderByCreateTime(true))
require.NoError(t, err)
assert.Equal(t, total, len(got))
found := map[string]struct{}{}
for _, am := range got {
switch {
case am.Clone().ScopeId == "global":
assert.Equalf(t, false, am.IsPrimaryAuthMethod, "expected the the global auth method to not be primary")
default:
if _, ok := found[am.ScopeId]; !ok {
found[am.ScopeId] = struct{}{}
assert.Equalf(t, true, am.IsPrimaryAuthMethod, "expected the first auth method created for the scope %s to be primary", am.ScopeId)
}
}
}
}
func TestRepository_ListAuthMethods_Limits(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
o, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
authMethodCount := 10
ams := TestAuthMethods(t, conn, o.GetPublicId(), authMethodCount)
primaryAuthMethod := ams[0]
iam.TestSetPrimaryAuthMethod(t, iam.TestRepo(t, conn, wrapper), o, primaryAuthMethod.PublicId)
tests := []struct {
name string
repoOpts []Option
listOpts []Option
wantLen int
}{
{
name: "With no limits",
wantLen: authMethodCount,
listOpts: []Option{WithOrderByCreateTime(true)},
},
{
name: "With repo limit",
repoOpts: []Option{WithLimit(3)},
listOpts: []Option{WithOrderByCreateTime(true)},
wantLen: 3,
},
{
name: "With negative repo limit",
repoOpts: []Option{WithLimit(-1)},
wantLen: authMethodCount,
},
{
name: "With List limit",
listOpts: []Option{WithLimit(3), WithOrderByCreateTime(true)},
wantLen: 3,
},
{
name: "With negative List limit",
listOpts: []Option{WithLimit(-1), WithOrderByCreateTime(true)},
wantLen: authMethodCount,
},
{
name: "With repo smaller than list limit",
repoOpts: []Option{WithLimit(2)},
listOpts: []Option{WithLimit(6), WithOrderByCreateTime(true)},
wantLen: 6,
},
{
name: "With repo larger than list limit",
repoOpts: []Option{WithLimit(6)},
listOpts: []Option{WithLimit(2), WithOrderByCreateTime(true)},
wantLen: 2,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
repo, err := NewRepository(rw, rw, kms, tt.repoOpts...)
assert.NoError(err)
require.NotNil(repo)
got, err := repo.ListAuthMethods(context.Background(), []string{ams[0].GetScopeId()}, tt.listOpts...)
require.NoError(err)
assert.Len(got, tt.wantLen)
if tt.wantLen > 0 {
assert.Equal(true, got[0].IsPrimaryAuthMethod)
}
})
}
}
func TestRepository_UpdateAuthMethod(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
repo, err := NewRepository(rw, rw, kms)
require.NoError(t, err)
iamRepo := iam.TestRepo(t, conn, wrapper)
ctx := context.Background()
type args struct {
updates *store.AuthMethod
fieldMaskPaths []string
}
tests := []struct {
name string
args args
wantRowsUpdate int
wantErr bool
skipVersionCheck bool
}{
{
name: "change name",
args: args{
updates: &store.AuthMethod{
Name: "updated",
},
fieldMaskPaths: []string{"Name"},
},
wantErr: false,
wantRowsUpdate: 1,
},
{
name: "null name",
args: args{
updates: &store.AuthMethod{},
fieldMaskPaths: []string{"Name"},
},
wantErr: false,
wantRowsUpdate: 1,
},
{
name: "change description",
args: args{
updates: &store.AuthMethod{
Description: "updated",
},
fieldMaskPaths: []string{"Description"},
},
wantErr: false,
wantRowsUpdate: 1,
},
{
name: "null description",
args: args{
updates: &store.AuthMethod{},
fieldMaskPaths: []string{"Description"},
},
wantErr: false,
wantRowsUpdate: 1,
skipVersionCheck: true,
},
{
name: "null name ignored description",
args: args{
updates: &store.AuthMethod{Description: "ignored"},
fieldMaskPaths: []string{"name"},
},
wantErr: false,
wantRowsUpdate: 1,
},
{
name: "change min pw",
args: args{
updates: &store.AuthMethod{
MinPasswordLength: 13,
},
fieldMaskPaths: []string{"MinPasswordLength"},
},
wantErr: false,
wantRowsUpdate: 1,
},
{
name: "null min pw",
args: args{
updates: &store.AuthMethod{},
fieldMaskPaths: []string{"MinPasswordLength"},
},
wantErr: false,
wantRowsUpdate: 1,
skipVersionCheck: true,
},
{
name: "change min login name",
args: args{
updates: &store.AuthMethod{
MinLoginNameLength: 13,
},
fieldMaskPaths: []string{"MinLoginNameLength"},
},
wantErr: false,
wantRowsUpdate: 1,
},
{
name: "null min login name",
args: args{
updates: &store.AuthMethod{},
fieldMaskPaths: []string{"MinLoginNameLength"},
},
wantErr: false,
wantRowsUpdate: 1,
skipVersionCheck: true,
},
{
name: "noop update",
args: args{
updates: &store.AuthMethod{
Name: "default",
},
fieldMaskPaths: []string{"name"},
},
wantErr: false,
wantRowsUpdate: 1,
skipVersionCheck: true,
},
{
name: "not fround",
args: args{
updates: &store.AuthMethod{
PublicId: func() string {
s, err := newAuthMethodId()
require.NoError(t, err)
return s
}(),
},
fieldMaskPaths: []string{"name"},
},
wantErr: true,
wantRowsUpdate: 0,
},
{
name: "empty field mask",
args: args{
updates: &store.AuthMethod{Name: "Test"},
fieldMaskPaths: []string{},
},
wantErr: true,
wantRowsUpdate: 0,
},
{
name: "nil field mask",
args: args{
updates: &store.AuthMethod{Name: "Test"},
fieldMaskPaths: nil,
},
wantErr: true,
wantRowsUpdate: 0,
},
{
name: "read-only-fields",
args: args{
updates: &store.AuthMethod{Name: "Test"},
fieldMaskPaths: []string{"CreateTime"},
},
wantErr: true,
wantRowsUpdate: 0,
},
{
name: "unknown fields",
args: args{
updates: &store.AuthMethod{Name: "Test"},
fieldMaskPaths: []string{"RandomUnknownName"},
},
wantErr: true,
wantRowsUpdate: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
// create the initial auth method
o, _ := iam.TestScopes(t, iamRepo)
am, err := NewAuthMethod(o.GetPublicId(), WithName("default"), WithDescription("default"))
require.NoError(err)
origAM, err := repo.CreateAuthMethod(ctx, am)
require.NoError(err)
assert.EqualValues(1, origAM.Version)
amToUpdate, err := NewAuthMethod(o.GetPublicId())
require.NoError(err)
amToUpdate.PublicId = origAM.GetPublicId()
amToUpdate.Version = origAM.Version
proto.Merge(amToUpdate.AuthMethod, tt.args.updates)
assert.EqualValues(1, amToUpdate.Version)
updatedAM, updatedRows, err := repo.UpdateAuthMethod(ctx, amToUpdate, amToUpdate.Version, tt.args.fieldMaskPaths)
assert.Equal(tt.wantRowsUpdate, updatedRows)
if tt.wantErr {
require.Error(err)
assert.Nil(updatedAM)
err = db.TestVerifyOplog(t, rw, amToUpdate.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second))
require.Error(err)
assert.Contains(err.Error(), "record not found")
return
}
require.NoError(err)
if !tt.skipVersionCheck {
assert.EqualValues(2, updatedAM.Version)
}
assert.NotEqual(origAM.UpdateTime, updatedAM.UpdateTime)
foundAuthMethod, err := repo.LookupAuthMethod(ctx, origAM.PublicId)
require.NoError(err)
assert.Empty(cmp.Diff(updatedAM, foundAuthMethod, protocmp.Transform()))
underlyingDB, err := conn.SqlDB(ctx)
require.NoError(err)
dbassert := dbassert.New(t, underlyingDB)
if amToUpdate.Name == "" && contains(tt.args.fieldMaskPaths, "name") {
dbassert.IsNull(foundAuthMethod, "name")
}
if amToUpdate.Description == "" && contains(tt.args.fieldMaskPaths, "description") {
dbassert.IsNull(foundAuthMethod, "description")
}
err = db.TestVerifyOplog(t, rw, updatedAM.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second))
assert.NoError(err)
})
}
}
func assertPublicId(t *testing.T, prefix, actual string) {
t.Helper()
assert.NotEmpty(t, actual)
parts := strings.Split(actual, "_")
assert.Equalf(t, 2, len(parts), "want one '_' in PublicId, got multiple in %q", actual)
assert.Equalf(t, prefix, parts[0], "PublicId want prefix: %q, got: %q in %q", prefix, parts[0], actual)
}