You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/oplog/writer_test.go

344 lines
9.2 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package oplog
import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/oplog/oplog_test"
dbassert "github.com/hashicorp/dbassert/gorm"
"github.com/hashicorp/go-dbw"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
_ "gorm.io/driver/postgres"
)
// Test_WriterCreate provides unit tests for Writer Create
func Test_WriterCreate(t *testing.T) {
testCtx := context.Background()
db, _ := setup(testCtx, t)
t.Run("valid", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tx, err := dbw.New(db).Begin(testCtx)
require.NoError(err)
defer func() {
assert.NoError(tx.Rollback(testCtx))
}()
w := Writer{tx.DB()}
user := oplog_test.TestUser{
Name: "foo-" + testId(t),
}
require.NoError(dbw.New(w.DB).Create(testCtx, &user))
foundUser := testFindUser(t, tx.DB(), user.Id)
assert.Equal(user.Name, foundUser.Name)
})
t.Run("nil tx", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
w := Writer{}
err := dbw.New(w.DB).Create(testCtx, &oplog_test.TestUser{})
require.Error(err)
assert.Contains(err.Error(), " missing underlying db: invalid parameter")
})
t.Run("nil model", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tx, err := dbw.New(db).Begin(testCtx)
require.NoError(err)
defer func() {
assert.NoError(tx.Rollback(testCtx))
}()
w := Writer{tx.DB()}
err = dbw.New(w.DB).Create(testCtx, nil)
require.Error(err)
assert.Contains(err.Error(), "missing interface")
})
}
// Test_WriterDelete provides unit tests for Writer Delete
func Test_WriterDelete(t *testing.T) {
testCtx := context.Background()
db, _ := setup(testCtx, t)
t.Run("valid", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tx, err := dbw.New(db).Begin(testCtx)
require.NoError(err)
defer func() {
assert.NoError(tx.Rollback(testCtx))
}()
w := Writer{tx.DB()}
id := testId(t)
user := testUser(t, db, "foo-"+id, "", "")
foundUser := testFindUser(t, db, user.Id)
_, err = dbw.New(w.DB).Delete(testCtx, &user)
require.NoError(err)
err = dbw.New(w.DB).LookupWhere(testCtx, &foundUser, "id = ?", []any{user.Id})
require.Error(err)
assert.ErrorIs(err, dbw.ErrRecordNotFound)
})
t.Run("nil tx", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
w := Writer{}
_, err := dbw.New(w.DB).Delete(testCtx, &oplog_test.TestUser{})
require.Error(err)
assert.Contains(err.Error(), "missing underlying db")
})
t.Run("nil model", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tx, err := dbw.New(db).Begin(testCtx)
require.NoError(err)
defer tx.Rollback(testCtx)
w := Writer{tx.DB()}
_, err = dbw.New(w.DB).Delete(testCtx, nil)
require.Error(err)
assert.Contains(err.Error(), "missing interface")
})
}
// TestWriter_hasTable provides unit tests for Writer HasTable
func TestWriter_hasTable(t *testing.T) {
testCtx := context.Background()
db, _ := setup(testCtx, t)
w := Writer{db}
t.Run("success", func(t *testing.T) {
assert := require.New(t)
ok, _ := w.hasTable(testCtx, "oplog_test_user")
assert.Equal(true, ok)
})
t.Run("no table", func(t *testing.T) {
assert := assert.New(t)
badTableName := testId(t)
ok, _ := w.hasTable(testCtx, badTableName)
assert.Equal(ok, false)
})
t.Run("blank table name", func(t *testing.T) {
assert := assert.New(t)
ok, _ := w.hasTable(testCtx, "")
assert.Equal(ok, false)
})
}
// TestWriter_createTableLike provides unit tests for Writer createTable
func TestWriter_createTableLike(t *testing.T) {
testCtx := context.Background()
db, _ := setup(testCtx, t)
t.Run("success", func(t *testing.T) {
assert := assert.New(t)
w := Writer{db}
suffix := testId(t)
u := &oplog_test.TestUser{}
newTableName := u.TableName() + "_" + suffix
defer func() { assert.NoError(w.dropTableIfExists(testCtx, newTableName)) }()
err := w.createTableLike(testCtx, u.TableName(), newTableName)
assert.NoError(err)
})
t.Run("call twice", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
w := Writer{db}
suffix := testId(t)
u := &oplog_test.TestUser{}
newTableName := u.TableName() + "_" + suffix
defer func() { assert.NoError(w.dropTableIfExists(testCtx, newTableName)) }()
err := w.createTableLike(testCtx, u.TableName(), newTableName)
require.NoError(err)
// should be an error to create the same table twice
err = w.createTableLike(testCtx, u.TableName(), newTableName)
require.Error(err)
assert.Error(err, err.Error(), nil)
})
t.Run("empty existing", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
w := Writer{db}
suffix := testId(t)
u := &oplog_test.TestUser{}
newTableName := u.TableName() + "_" + suffix
defer func() { assert.NoError(w.dropTableIfExists(testCtx, newTableName)) }()
err := w.createTableLike(testCtx, "", newTableName)
require.Error(err)
assert.Error(err, err.Error(), nil)
assert.Contains(err.Error(), "missing existing table name")
})
t.Run("blank name", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
w := Writer{db}
u := &oplog_test.TestUser{}
err := w.createTableLike(testCtx, u.TableName(), "")
require.Error(err)
assert.Error(err, err.Error(), nil)
assert.Contains(err.Error(), "missing new table name")
})
}
// Test_WriterDropTableIfExists provides unit tests for Writer dropTableIfExists
func Test_WriterDropTableIfExists(t *testing.T) {
testCtx := context.Background()
db, _ := setup(testCtx, t)
t.Run("success", func(t *testing.T) {
assert := assert.New(t)
w := Writer{db}
suffix := testId(t)
u := &oplog_test.TestUser{}
newTableName := u.TableName() + "_" + suffix
assert.NoError(w.createTableLike(testCtx, u.TableName(), newTableName))
defer func() { assert.NoError(w.dropTableIfExists(testCtx, newTableName)) }()
})
t.Run("success with blank", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
w := Writer{db}
err := w.dropTableIfExists(testCtx, "")
require.Error(err)
assert.Contains(err.Error(), "missing table name")
})
}
func TestWriter_Update(t *testing.T) {
db, _ := setup(context.Background(), t)
id := testId(t)
type args struct {
user *oplog_test.TestUser
fieldMaskPaths []string
setToNullPaths []string
}
tests := []struct {
name string
Tx *dbw.DB
args args
wantUser *oplog_test.TestUser
wantErr bool
}{
{
name: "valid-fieldmask",
Tx: db,
args: args{
user: &oplog_test.TestUser{
Name: "valid-fieldmask",
},
fieldMaskPaths: []string{"name"},
},
wantUser: &oplog_test.TestUser{
Name: "valid-fieldmask",
Email: id,
PhoneNumber: id,
Version: 2,
},
wantErr: false,
},
{
name: "valid-setToNull",
Tx: db,
args: args{
user: &oplog_test.TestUser{
Name: "valid-setToNull",
},
fieldMaskPaths: nil,
setToNullPaths: []string{"name"},
},
wantUser: &oplog_test.TestUser{
Name: "",
Email: id,
PhoneNumber: id,
Version: 2,
},
wantErr: false,
},
{
name: "valid-setToNull-and-fieldMask",
Tx: db,
args: args{
user: &oplog_test.TestUser{
Email: "valid-setToNull-and-fieldMask",
},
fieldMaskPaths: []string{"email"},
setToNullPaths: []string{"name"},
},
wantUser: &oplog_test.TestUser{
Name: "",
Email: "valid-setToNull-and-fieldMask",
PhoneNumber: id,
Version: 2,
},
wantErr: false,
},
{
name: "no-field-mask",
Tx: db,
args: args{
user: &oplog_test.TestUser{
Name: "no-field-mask",
},
fieldMaskPaths: []string{""},
},
wantErr: true,
},
{
name: "nil-field-mask",
Tx: db,
args: args{
user: &oplog_test.TestUser{
Name: "nil-field-mask",
},
fieldMaskPaths: nil,
},
wantErr: true,
},
{
name: "nil-tx",
Tx: nil,
args: args{
user: &oplog_test.TestUser{
Name: "nil-txt",
},
fieldMaskPaths: []string{"name"},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
underlyingDB, err := db.SqlDB(context.Background())
require.NoError(err)
_, name, err := db.DbType()
require.NoError(err)
dbassert := dbassert.New(t, underlyingDB, name)
w := &Writer{
tt.Tx,
}
u := testUser(t, db, tt.name+id, id, id) // intentionally, not relying on tt.Tx
u.Name = tt.args.user.Name
u.Email = tt.args.user.Email
u.PhoneNumber = tt.args.user.PhoneNumber
_, err = dbw.New(w.DB).Update(context.Background(), u, tt.args.fieldMaskPaths, tt.args.setToNullPaths)
if tt.wantErr {
require.Error(err)
return
}
require.NoError(err)
var foundUser oplog_test.TestUser
foundUser.Id = u.Id
require.NoError(dbw.New(db).LookupBy(context.Background(), &foundUser))
tt.wantUser.Id = u.Id
assert.Equal(tt.wantUser, &foundUser)
for _, f := range tt.args.setToNullPaths {
dbassert.IsNull(u, f)
}
})
}
t.Run("nil model", func(t *testing.T) {
assert := assert.New(t)
w := Writer{db}
err := dbw.New(w.DB).Create(context.Background(), nil)
assert.Error(err)
})
}