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 )
2020-05-11 10:30:44 -04:00
db , err := gorm . Open ( "postgres" , url )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-05-11 10:30:44 -04:00
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 ) {
2020-05-11 10:30:44 -04:00
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
2020-05-11 10:30:44 -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 ) {
2020-05-11 10:30:44 -04:00
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 )
2021-01-13 15:50:07 -08:00
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 )
2021-01-13 15:50:07 -08:00
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 )
2021-01-13 15:50:07 -08:00
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 ) {
2020-05-11 10:30:44 -04:00
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 ,
}
2020-04-28 11:20:37 -07:00
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 )
2021-01-13 15:50:07 -08:00
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 ,
}
2020-04-28 11:20:37 -07:00
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 )
2021-01-13 15:50:07 -08:00
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 ,
}
2020-04-28 11:20:37 -07:00
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 ) {
2020-05-11 10:30:44 -04:00
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
2020-04-20 16:42:16 -04:00
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 )
2020-05-11 10:30:44 -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
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 , "" , "" )
2020-04-20 16:42:16 -04:00
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
2020-04-20 16:42:16 -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
2020-04-20 16:42:16 -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
2020-05-11 10:30:44 -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
2020-04-20 16:42:16 -04:00
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
2020-04-20 16:42:16 -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 ,
2020-04-28 11:20:37 -07:00
& 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
2020-04-20 16:42:16 -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 ) {
2020-05-11 10:30:44 -04:00
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
2020-05-11 10:30:44 -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 ,
2020-04-28 11:20:37 -07:00
& 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 ,
2020-04-28 11:20:37 -07:00
& 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 )
2021-01-13 15:50:07 -08:00
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 ,
2020-04-28 11:20:37 -07:00
& 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 )
2021-01-13 15:50:07 -08:00
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 )
2021-01-13 15:50:07 -08:00
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 ) {
2020-05-11 10:30:44 -04:00
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 )
2020-05-11 10:30:44 -04:00
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 {}
2020-04-28 11:20:37 -07:00
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 )
2020-05-11 10:30:44 -04:00
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 {}
2020-04-28 11:20:37 -07:00
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" )
}
}