Files
threshold/internal/oplog/oplog_test.go
T

694 lines
20 KiB
Go
Raw Normal View History

2020-04-08 14:55:40 -04:00
package oplog
import (
"context"
"fmt"
"testing"
2020-06-10 06:56:46 -04:00
dbassert "github.com/hashicorp/dbassert/gorm"
2020-08-10 17:15:02 -04:00
"github.com/hashicorp/boundary/internal/oplog/oplog_test"
2020-04-08 14:55:40 -04:00
"github.com/jinzhu/gorm"
2020-06-10 06:56:46 -04:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2020-04-08 14:55:40 -04:00
_ "github.com/golang-migrate/migrate/v4/database/postgres"
_ "github.com/golang-migrate/migrate/v4/source/file"
)
// setup the tests (initialize the database one-time and intialized testDatabaseURL)
2020-09-28 16:05:15 -04:00
func setup(t *testing.T) (func() error, *gorm.DB) {
2020-06-10 06:56:46 -04:00
t.Helper()
require := require.New(t)
cleanup, url, err := testInitDbInDocker(t)
require.NoError(err)
db, err := gorm.Open("postgres", url)
2020-06-10 06:56:46 -04:00
require.NoError(err)
oplog_test.Init(db)
return cleanup, db
2020-04-08 14:55:40 -04:00
}
// Test_BasicOplog provides some basic unit tests for oplogs
func Test_BasicOplog(t *testing.T) {
cleanup, db := setup(t)
2020-06-10 06:56:46 -04:00
defer testCleanup(t, cleanup, db)
2020-04-08 14:55:40 -04:00
t.Run("EncryptData/DecryptData/UnmarshalData", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
cipherer := testWrapper(t)
2020-04-08 14:55:40 -04:00
// now let's us optimistic locking via a ticketing system for a serialized oplog
ticketer, err := NewGormTicketer(db, WithAggregateNames(true))
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
types, err := NewTypeCatalog(Type{new(oplog_test.TestUser), "user"})
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
queue := Queue{Catalog: types}
2020-06-10 06:56:46 -04:00
id := testId(t)
user := testUser(t, db, "foo-"+id, "", "")
2020-04-08 14:55:40 -04:00
2020-06-10 06:56:46 -04:00
err = queue.Add(user, "user", OpType_OP_TYPE_CREATE)
require.NoError(err)
2020-04-08 14:55:40 -04:00
l, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
l.Data = queue.Bytes()
err = l.EncryptData(context.Background())
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
2020-06-10 06:56:46 -04:00
err = db.Create(&l).Error
require.NoError(err)
assert.NotNil(l.CreateTime)
assert.NotNil(l.UpdateTime)
2020-04-08 14:55:40 -04:00
entryId := l.Id
var foundEntry Entry
err = db.Where("id = ?", entryId).First(&foundEntry).Error
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
foundEntry.Cipherer = cipherer
err = foundEntry.DecryptData(context.Background())
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
foundUsers, err := foundEntry.UnmarshalData(types)
2020-06-10 06:56:46 -04:00
require.NoError(err)
assert.Equal(foundUsers[0].Message.(*oplog_test.TestUser).Name, user.Name)
2020-04-08 14:55:40 -04:00
foundUsers, err = foundEntry.UnmarshalData(types)
2020-06-10 06:56:46 -04:00
require.NoError(err)
assert.Equal(foundUsers[0].Message.(*oplog_test.TestUser).Name, user.Name)
2020-04-08 14:55:40 -04:00
})
t.Run("write entry", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
cipherer := testWrapper(t)
2020-04-08 14:55:40 -04:00
// now let's us optimistic locking via a ticketing system for a serialized oplog
ticketer, err := NewGormTicketer(db, WithAggregateNames(true))
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
types, err := NewTypeCatalog(Type{new(oplog_test.TestUser), "user"})
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
queue := Queue{Catalog: types}
2020-06-10 06:56:46 -04:00
id := testId(t)
user := testUser(t, db, "foo-"+id, "", "")
2020-04-08 14:55:40 -04:00
ticket, err := ticketer.GetTicket("default")
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
queue = Queue{}
2020-06-10 06:56:46 -04:00
err = queue.Add(user, "user", OpType_OP_TYPE_CREATE)
require.NoError(err)
2020-04-08 14:55:40 -04:00
newLogEntry, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
newLogEntry.Data = queue.Bytes()
err = newLogEntry.Write(context.Background(), &GormWriter{db}, ticket)
2020-06-10 06:56:46 -04:00
require.NoError(err)
assert.NotEmpty(newLogEntry.Id)
2020-04-08 14:55:40 -04:00
})
}
// Test_NewEntry provides some basic unit tests for NewEntry
func Test_NewEntry(t *testing.T) {
cleanup, db := setup(t)
2020-06-10 06:56:46 -04:00
defer testCleanup(t, cleanup, db)
2020-04-08 14:55:40 -04:00
t.Run("valid", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
require := require.New(t)
cipherer := testWrapper(t)
2020-04-08 14:55:40 -04:00
ticketer, err := NewGormTicketer(db, WithAggregateNames(true))
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
_, err = NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
})
t.Run("no metadata success", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
require := require.New(t)
cipherer := testWrapper(t)
2020-04-08 14:55:40 -04:00
ticketer, err := NewGormTicketer(db, WithAggregateNames(true))
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
_, err = NewEntry(
"test-users",
nil,
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
})
t.Run("no aggregateName", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
cipherer := testWrapper(t)
2020-04-08 14:55:40 -04:00
ticketer, err := NewGormTicketer(db, WithAggregateNames(true))
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
_, err = NewEntry(
"",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.Error(err)
assert.Equal("oplog.NewEntry: oplog.(Entry).validate: missing entry aggregate name: parameter violation: error #100", err.Error())
2020-04-08 14:55:40 -04:00
})
t.Run("bad cipherer", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
2020-04-08 14:55:40 -04:00
ticketer, err := NewGormTicketer(db, WithAggregateNames(true))
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
_, err = NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
nil,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.Error(err)
assert.Equal("oplog.NewEntry: oplog.(Entry).validate: nil cipherer: parameter violation: error #100", err.Error())
2020-04-08 14:55:40 -04:00
})
t.Run("bad ticket", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
cipherer := testWrapper(t)
2020-04-08 14:55:40 -04:00
_, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
nil,
)
2020-06-10 06:56:46 -04:00
require.Error(err)
assert.Equal("oplog.NewEntry: oplog.(Entry).validate: nil ticketer: parameter violation: error #100", err.Error())
2020-04-08 14:55:40 -04:00
})
}
func Test_UnmarshalData(t *testing.T) {
cleanup, db := setup(t)
2020-06-10 06:56:46 -04:00
defer testCleanup(t, cleanup, db)
2020-04-08 14:55:40 -04:00
2020-06-10 06:56:46 -04:00
cipherer := testWrapper(t)
2020-04-08 14:55:40 -04:00
// now let's us optimistic locking via a ticketing system for a serialized oplog
ticketer, err := NewGormTicketer(db, WithAggregateNames(true))
types, err := NewTypeCatalog(Type{new(oplog_test.TestUser), "user"})
2020-06-10 06:56:46 -04:00
require.NoError(t, err)
2020-04-08 14:55:40 -04:00
2020-06-10 06:56:46 -04:00
id := testId(t)
2020-04-08 14:55:40 -04:00
t.Run("valid", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
2020-04-08 14:55:40 -04:00
queue := Queue{Catalog: types}
user := oplog_test.TestUser{
Name: "foo-" + id,
}
err = queue.Add(&user, "user", OpType_OP_TYPE_CREATE)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
entry, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
entry.Data = queue.Bytes()
marshaledUsers, err := entry.UnmarshalData(types)
2020-06-10 06:56:46 -04:00
require.NoError(err)
assert.Equal(marshaledUsers[0].Message.(*oplog_test.TestUser).Name, user.Name)
2020-04-08 14:55:40 -04:00
take2marshaledUsers, err := entry.UnmarshalData(types)
2020-06-10 06:56:46 -04:00
require.NoError(err)
assert.Equal(take2marshaledUsers[0].Message.(*oplog_test.TestUser).Name, user.Name)
2020-04-08 14:55:40 -04:00
})
t.Run("no data", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
2020-04-08 14:55:40 -04:00
queue := Queue{Catalog: types}
entry, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
entry.Data = queue.Bytes()
_, err = entry.UnmarshalData(types)
2020-06-10 06:56:46 -04:00
require.Error(err)
assert.Equal("oplog.(Entry).UnmarshalData: missing data: parameter violation: error #100", err.Error())
2020-04-08 14:55:40 -04:00
})
t.Run("nil types", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
2020-04-08 14:55:40 -04:00
queue := Queue{Catalog: types}
user := oplog_test.TestUser{
Name: "foo-" + id,
}
err = queue.Add(&user, "user", OpType_OP_TYPE_CREATE)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
entry, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
_, err = entry.UnmarshalData(nil)
2020-06-10 06:56:46 -04:00
require.Error(err)
assert.Equal("oplog.(Entry).UnmarshalData: nil type catalog: parameter violation: error #100", err.Error())
2020-04-08 14:55:40 -04:00
})
t.Run("missing type", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
2020-04-08 14:55:40 -04:00
queue := Queue{Catalog: types}
user := oplog_test.TestUser{
Name: "foo-" + id,
}
err = queue.Add(&user, "user", OpType_OP_TYPE_CREATE)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
entry, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
entry.Data = queue.Bytes()
types, err := NewTypeCatalog(Type{new(oplog_test.TestUser), "not-valid-name"})
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
_, err = entry.UnmarshalData(types)
2020-06-10 06:56:46 -04:00
require.Error(err)
2021-04-08 20:54:32 -04:00
assert.Equal("oplog.(Entry).UnmarshalData: error removing item from queue: oplog.(Queue).Remove: error getting the TypeName: user: oplog.(TypeCatalog).Get: type name not found: integrity violation: error #105", err.Error())
2020-04-08 14:55:40 -04:00
})
}
// Test_Replay provides some basic unit tests for replaying entries
func Test_Replay(t *testing.T) {
cleanup, db := setup(t)
2020-06-10 06:56:46 -04:00
defer testCleanup(t, cleanup, db)
2020-04-08 14:55:40 -04:00
2020-06-10 06:56:46 -04:00
cipherer := testWrapper(t)
id := testId(t)
2020-04-08 14:55:40 -04:00
// setup new tables for replay
tableSuffix := "_" + id
writer := GormWriter{Tx: db}
2020-06-10 06:56:46 -04:00
userModel := &oplog_test.TestUser{}
replayUserTable := fmt.Sprintf("%s%s", userModel.TableName(), tableSuffix)
defer func() { require.NoError(t, writer.dropTableIfExists(replayUserTable)) }()
2020-04-08 14:55:40 -04:00
ticketer, err := NewGormTicketer(db, WithAggregateNames(true))
2020-06-10 06:56:46 -04:00
require.NoError(t, err)
2020-04-08 14:55:40 -04:00
t.Run("replay:create/update", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
ticket, err := ticketer.GetTicket("default")
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
newLogEntry, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
2020-06-10 06:56:46 -04:00
tx := db
2020-08-11 17:25:00 -04:00
loginName := "foo-" + testId(t)
userCreate := testUser(t, db, loginName, "", "")
userSave := oplog_test.TestUser{
Id: userCreate.Id,
Name: userCreate.Name,
2020-08-11 17:25:00 -04:00
Email: loginName + "@hashicorp.com",
2020-04-08 14:55:40 -04:00
}
err = tx.Save(&userSave).Error
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
userUpdate := oplog_test.TestUser{
2020-06-10 06:56:46 -04:00
Id: userCreate.Id,
2020-04-08 14:55:40 -04:00
}
2020-06-10 06:56:46 -04:00
err = tx.Model(&userUpdate).Updates(map[string]interface{}{"PhoneNumber": "867-5309", "Name": gorm.Expr("NULL")}).Error
require.NoError(err)
dbassert := dbassert.New(t, tx.DB(), "postgres")
dbassert.IsNull(&userUpdate, "Name")
foundCreateUser := testFindUser(t, tx, userCreate.Id)
require.Equal(foundCreateUser.Id, userCreate.Id)
require.Equal(foundCreateUser.Name, "")
require.Equal(foundCreateUser.PhoneNumber, userUpdate.PhoneNumber)
2020-04-08 14:55:40 -04:00
err = newLogEntry.WriteEntryWith(context.Background(), &GormWriter{tx}, ticket,
2020-06-10 06:56:46 -04:00
&Message{Message: userCreate, TypeName: "user", OpType: OpType_OP_TYPE_CREATE},
&Message{Message: &userSave, TypeName: "user", OpType: OpType_OP_TYPE_UPDATE, FieldMaskPaths: []string{"Name", "Email"}},
&Message{Message: &userSave, TypeName: "user", OpType: OpType_OP_TYPE_UPDATE, FieldMaskPaths: []string{"Name", "Email"}, SetToNullPaths: nil},
&Message{Message: &userUpdate, TypeName: "user", OpType: OpType_OP_TYPE_UPDATE, SetToNullPaths: []string{"Name"}},
&Message{Message: &userUpdate, TypeName: "user", OpType: OpType_OP_TYPE_UPDATE, FieldMaskPaths: nil, SetToNullPaths: []string{"Name"}},
&Message{Message: &userUpdate, TypeName: "user", OpType: OpType_OP_TYPE_UPDATE, FieldMaskPaths: []string{"PhoneNumber"}, SetToNullPaths: []string{"Name"}},
2020-04-08 14:55:40 -04:00
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
types, err := NewTypeCatalog(Type{new(oplog_test.TestUser), "user"})
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
var foundEntry Entry
err = tx.Where("id = ?", newLogEntry.Id).First(&foundEntry).Error
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
foundEntry.Cipherer = cipherer
err = foundEntry.DecryptData(context.Background())
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
err = foundEntry.Replay(context.Background(), &GormWriter{tx}, types, tableSuffix)
2020-06-10 06:56:46 -04:00
require.NoError(err)
foundUser := testFindUser(t, tx, userCreate.Id)
2020-04-08 14:55:40 -04:00
var foundReplayedUser oplog_test.TestUser
2020-06-10 06:56:46 -04:00
foundReplayedUser.Table = foundReplayedUser.TableName() + tableSuffix
2020-04-08 14:55:40 -04:00
err = tx.Where("id = ?", userCreate.Id).First(&foundReplayedUser).Error
2020-06-10 06:56:46 -04:00
require.NoError(err)
assert.Equal(foundUser.Id, foundReplayedUser.Id)
assert.Equal(foundUser.Name, foundReplayedUser.Name)
assert.Equal(foundUser.PhoneNumber, foundReplayedUser.PhoneNumber)
assert.Equal(foundReplayedUser.PhoneNumber, "867-5309")
assert.Equal(foundUser.Email, foundReplayedUser.Email)
2020-08-11 17:25:00 -04:00
assert.Equal(foundReplayedUser.Email, loginName+"@hashicorp.com")
2020-04-08 14:55:40 -04:00
})
t.Run("replay:delete", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
2020-04-08 14:55:40 -04:00
// we need to test delete replays now...
tx2 := db.Begin()
2020-06-10 06:56:46 -04:00
defer tx2.Commit()
2020-04-08 14:55:40 -04:00
ticket2, err := ticketer.GetTicket("default")
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
2020-06-10 06:56:46 -04:00
id4 := testId(t)
2020-08-11 17:25:00 -04:00
loginName2 := "foo-" + id4
2020-04-08 14:55:40 -04:00
// create a user that's replayable
userCreate2 := oplog_test.TestUser{
2020-08-11 17:25:00 -04:00
Name: loginName2,
2020-04-08 14:55:40 -04:00
}
err = tx2.Create(&userCreate2).Error
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
deleteUser2 := oplog_test.TestUser{
Id: userCreate2.Id,
2020-04-08 14:55:40 -04:00
}
err = tx2.Delete(&deleteUser2).Error
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
newLogEntry2, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
err = newLogEntry2.WriteEntryWith(context.Background(), &GormWriter{tx2}, ticket2,
&Message{Message: &userCreate2, TypeName: "user", OpType: OpType_OP_TYPE_CREATE},
&Message{Message: &deleteUser2, TypeName: "user", OpType: OpType_OP_TYPE_DELETE},
2020-04-08 14:55:40 -04:00
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
var foundEntry2 Entry
err = tx2.Where("id = ?", newLogEntry2.Id).First(&foundEntry2).Error
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
foundEntry2.Cipherer = cipherer
err = foundEntry2.DecryptData(context.Background())
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
types, err := NewTypeCatalog(Type{new(oplog_test.TestUser), "user"})
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
err = foundEntry2.Replay(context.Background(), &GormWriter{tx2}, types, tableSuffix)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
var foundUser2 oplog_test.TestUser
err = tx2.Where("id = ?", userCreate2.Id).First(&foundUser2).Error
2021-01-05 17:34:04 -08:00
assert.Equal(gorm.ErrRecordNotFound, err, err.Error())
2020-04-08 14:55:40 -04:00
var foundReplayedUser2 oplog_test.TestUser
err = tx2.Where("id = ?", userCreate2.Id).First(&foundReplayedUser2).Error
2021-01-05 17:34:04 -08:00
assert.Equal(gorm.ErrRecordNotFound, err, err.Error())
2020-04-08 14:55:40 -04:00
})
}
// Test_WriteEntryWith provides unit tests for oplog.WriteEntryWith
func Test_WriteEntryWith(t *testing.T) {
cleanup, db := setup(t)
2020-06-10 06:56:46 -04:00
defer testCleanup(t, cleanup, db)
cipherer := testWrapper(t)
2020-04-08 14:55:40 -04:00
2020-06-10 06:56:46 -04:00
id := testId(t)
2020-04-08 14:55:40 -04:00
u := oplog_test.TestUser{
Name: "foo-" + id,
}
t.Log(&u)
2020-06-10 06:56:46 -04:00
id2 := testId(t)
2020-04-08 14:55:40 -04:00
u2 := oplog_test.TestUser{
Name: "foo-" + id2,
}
t.Log(&u2)
ticketer, err := NewGormTicketer(db, WithAggregateNames(true))
2020-06-10 06:56:46 -04:00
require.NoError(t, err)
2020-04-08 14:55:40 -04:00
ticket, err := ticketer.GetTicket("default")
2020-06-10 06:56:46 -04:00
require.NoError(t, err)
2020-04-08 14:55:40 -04:00
t.Run("successful", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
2020-04-08 14:55:40 -04:00
newLogEntry, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
err = newLogEntry.WriteEntryWith(context.Background(), &GormWriter{db}, ticket,
&Message{Message: &u, TypeName: "user", OpType: OpType_OP_TYPE_CREATE},
&Message{Message: &u2, TypeName: "user", OpType: OpType_OP_TYPE_CREATE})
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
var foundEntry Entry
err = db.Where("id = ?", newLogEntry.Id).First(&foundEntry).Error
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
foundEntry.Cipherer = cipherer
types, err := NewTypeCatalog(Type{new(oplog_test.TestUser), "user"})
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
err = foundEntry.DecryptData(context.Background())
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
foundUsers, err := foundEntry.UnmarshalData(types)
2020-06-10 06:56:46 -04:00
require.NoError(err)
assert.Equal(foundUsers[0].Message.(*oplog_test.TestUser).Name, u.Name)
2020-04-08 14:55:40 -04:00
})
t.Run("nil writer", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
2020-04-08 14:55:40 -04:00
newLogEntry, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
err = newLogEntry.WriteEntryWith(context.Background(), nil, ticket,
&Message{Message: &u, TypeName: "user", OpType: OpType_OP_TYPE_CREATE},
&Message{Message: &u2, TypeName: "user", OpType: OpType_OP_TYPE_CREATE})
2020-06-10 06:56:46 -04:00
require.Error(err)
assert.Equal("oplog.(Entry).WriteEntryWith: nil writer: parameter violation: error #100", err.Error())
2020-04-08 14:55:40 -04:00
})
t.Run("nil ticket", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
2020-04-08 14:55:40 -04:00
newLogEntry, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
err = newLogEntry.WriteEntryWith(context.Background(), &GormWriter{db}, nil,
&Message{Message: &u, TypeName: "user", OpType: OpType_OP_TYPE_CREATE},
&Message{Message: &u2, TypeName: "user", OpType: OpType_OP_TYPE_CREATE})
2020-06-10 06:56:46 -04:00
require.Error(err)
assert.Equal("oplog.(Entry).WriteEntryWith: nil ticket: parameter violation: error #100", err.Error())
2020-04-08 14:55:40 -04:00
})
t.Run("nil ticket", func(t *testing.T) {
2020-06-10 06:56:46 -04:00
assert, require := assert.New(t), require.New(t)
2020-04-08 14:55:40 -04:00
newLogEntry, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
err = newLogEntry.WriteEntryWith(context.Background(), &GormWriter{db}, ticket, nil)
2020-06-10 06:56:46 -04:00
require.Error(err)
assert.Equal("oplog.(Entry).WriteEntryWith: nil message: parameter violation: error #100", err.Error())
2020-04-08 14:55:40 -04:00
})
}
// Test_TicketSerialization provides unit tests for making sure oplog.Tickets properly serialize writes to oplog entries
func Test_TicketSerialization(t *testing.T) {
cleanup, db := setup(t)
2020-06-10 06:56:46 -04:00
defer testCleanup(t, cleanup, db)
assert, require := assert.New(t), require.New(t)
2020-04-08 14:55:40 -04:00
ticketer, err := NewGormTicketer(db, WithAggregateNames(true))
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
2020-06-10 06:56:46 -04:00
cipherer := testWrapper(t)
2020-04-08 14:55:40 -04:00
2020-06-10 06:56:46 -04:00
id := testId(t)
2020-04-08 14:55:40 -04:00
firstTx := db.Begin()
firstUser := oplog_test.TestUser{
Name: "foo-" + id,
}
err = firstTx.Create(&firstUser).Error
2020-06-10 06:56:46 -04:00
require.NoError(err)
firstTicket, err := ticketer.GetTicket("default")
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
firstQueue := Queue{}
err = firstQueue.Add(&firstUser, "user", OpType_OP_TYPE_CREATE)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
firstLogEntry, err := NewEntry(
"test-users",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
firstLogEntry.Data = firstQueue.Bytes()
2020-06-10 06:56:46 -04:00
id2 := testId(t)
2020-04-08 14:55:40 -04:00
secondTx := db.Begin()
secondUser := oplog_test.TestUser{
Name: "foo-" + id2,
}
err = secondTx.Create(&secondUser).Error
2020-06-10 06:56:46 -04:00
require.NoError(err)
secondTicket, err := ticketer.GetTicket("default")
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
secondQueue := Queue{}
err = secondQueue.Add(&secondUser, "user", OpType_OP_TYPE_CREATE)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
secondLogEntry, err := NewEntry(
"foobar",
Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
cipherer,
ticketer,
)
2020-06-10 06:56:46 -04:00
require.NoError(err)
2020-04-08 14:55:40 -04:00
secondLogEntry.Data = secondQueue.Bytes()
err = secondLogEntry.Write(context.Background(), &GormWriter{secondTx}, secondTicket)
2020-06-10 06:56:46 -04:00
require.NoError(err)
assert.NotEmpty(secondLogEntry.Id, 0)
assert.NotNil(secondLogEntry.CreateTime)
assert.NotNil(secondLogEntry.UpdateTime)
2020-04-08 14:55:40 -04:00
err = secondTx.Commit().Error
2020-06-10 06:56:46 -04:00
require.NoError(err)
assert.NotNil(secondLogEntry.Id)
2020-04-08 14:55:40 -04:00
err = firstLogEntry.Write(context.Background(), &GormWriter{firstTx}, firstTicket)
if err != nil {
firstTx.Rollback()
} else {
firstTx.Commit()
t.Error("should have failed to write firstLogEntry")
}
}