2020-08-11 17:25:00 -04:00
// Copyright (c) HashiCorp, Inc.
2020-04-08 14:55:40 -04:00
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2020-04-08 14:55:40 -04:00
package oplog
import (
"context"
"fmt"
"testing"
2022-11-16 17:17:28 -06:00
"github.com/hashicorp/boundary/internal/oplog/oplog_test"
2020-06-10 06:56:46 -04:00
dbassert "github.com/hashicorp/dbassert/gorm"
2022-01-05 14:38:38 -05:00
"github.com/hashicorp/go-dbw"
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"
)
// Test_BasicOplog provides some basic unit tests for oplogs
func Test_BasicOplog ( t * testing . T ) {
2022-01-05 14:38:38 -05:00
testCtx := context . Background ()
2022-11-16 17:17:28 -06:00
db , wrapper := setup ( testCtx , t )
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 )
2022-11-16 17:17:28 -06:00
keyId , err := wrapper . KeyId ( testCtx )
require . NoError ( err )
2020-04-08 14:55:40 -04:00
// now let's us optimistic locking via a ticketing system for a serialized oplog
2022-01-05 14:38:38 -05:00
ticketer , err := NewTicketer ( testCtx , db , WithAggregateNames ( true ))
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
types , err := NewTypeCatalog ( testCtx , 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
2022-01-05 14:38:38 -05:00
err = queue . add ( testCtx , 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
l , err := NewEntry (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
l . Data = queue . Bytes ()
2022-01-05 14:38:38 -05:00
err = l . encryptData ( context . Background ())
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
err = dbw . New ( db ). Create ( testCtx , & l )
2020-06-10 06:56:46 -04:00
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
2022-10-25 18:29:38 -05:00
err = dbw . New ( db ). LookupWhere ( testCtx , & foundEntry , "id = ?" , [] any { entryId })
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-11-16 17:17:28 -06:00
foundEntry . Wrapper = wrapper
2020-04-08 14:55:40 -04:00
err = foundEntry . DecryptData ( context . Background ())
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-11-16 17:17:28 -06:00
require . Equal ( keyId , foundEntry . KeyId )
require . Equal ( "global" , foundEntry . ScopeId )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
foundUsers , err := foundEntry . UnmarshalData ( testCtx , types )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
assert . Equal ( foundUsers [ 0 ]. Message .( * oplog_test . TestUser ). Name , user . Name )
2022-01-05 14:38:38 -05:00
foundUsers , err = foundEntry . UnmarshalData ( testCtx , 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 )
2020-04-08 14:55:40 -04:00
// now let's us optimistic locking via a ticketing system for a serialized oplog
2022-01-05 14:38:38 -05:00
ticketer , err := NewTicketer ( testCtx , db , WithAggregateNames ( true ))
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
types , err := NewTypeCatalog ( testCtx , 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 , "" , "" )
2022-01-05 14:38:38 -05:00
ticket , err := ticketer . GetTicket ( testCtx , "default" )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
err = queue . add ( testCtx , 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
newLogEntry , err := NewEntry (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
newLogEntry . Data = queue . Bytes ()
2022-01-05 14:38:38 -05:00
err = newLogEntry . Write ( context . Background (), & Writer { 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 ) {
2022-01-05 14:38:38 -05:00
testCtx := context . Background ()
2022-11-16 17:17:28 -06:00
db , wrapper := setup ( testCtx , t )
2020-06-10 06:56:46 -04:00
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 )
2022-01-05 14:38:38 -05:00
ticketer , err := NewTicketer ( testCtx , db , WithAggregateNames ( true ))
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-11-16 17:17:28 -06:00
keyId , err := wrapper . KeyId ( testCtx )
require . NoError ( err )
2020-04-08 14:55:40 -04:00
2022-11-16 17:17:28 -06:00
entry , err := NewEntry (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-11-16 17:17:28 -06:00
require . Equal ( keyId , entry . KeyId )
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 )
2022-01-05 14:38:38 -05:00
ticketer , err := NewTicketer ( testCtx , db , WithAggregateNames ( true ))
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
_ , err = NewEntry (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
nil ,
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
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 )
2022-01-05 14:38:38 -05:00
ticketer , err := NewTicketer ( testCtx , db , WithAggregateNames ( true ))
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
_ , err = NewEntry (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
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
})
2022-11-16 17:17:28 -06:00
t . Run ( "bad wrapper" , func ( t * testing . T ) {
2020-06-10 06:56:46 -04:00
assert , require := assert . New ( t ), require . New ( t )
2022-01-05 14:38:38 -05:00
ticketer , err := NewTicketer ( testCtx , db , WithAggregateNames ( true ))
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
_ , err = NewEntry (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"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 )
2022-11-16 17:17:28 -06:00
assert . Equal ( "oplog.NewEntry: nil wrapper: 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 )
2020-04-08 14:55:40 -04:00
_ , err := NewEntry (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
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 ) {
2022-01-05 14:38:38 -05:00
testCtx := context . Background ()
2022-11-16 17:17:28 -06:00
db , wrapper := setup ( testCtx , t )
2020-04-08 14:55:40 -04:00
// now let's us optimistic locking via a ticketing system for a serialized oplog
2022-01-05 14:38:38 -05:00
ticketer , err := NewTicketer ( testCtx , db , WithAggregateNames ( true ))
2021-09-30 08:47:34 -04:00
require . NoError ( t , err )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
types , err := NewTypeCatalog ( testCtx , 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 ,
}
2022-01-05 14:38:38 -05:00
err = queue . add ( testCtx , & 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 (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
entry . Data = queue . Bytes ()
2022-01-05 14:38:38 -05:00
marshaledUsers , err := entry . UnmarshalData ( testCtx , 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
2022-01-05 14:38:38 -05:00
take2marshaledUsers , err := entry . UnmarshalData ( testCtx , 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 (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
entry . Data = queue . Bytes ()
2022-01-05 14:38:38 -05:00
_ , err = entry . UnmarshalData ( testCtx , 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 ,
}
2022-01-05 14:38:38 -05:00
err = queue . add ( testCtx , & 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 (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
_ , err = entry . UnmarshalData ( testCtx , 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 ,
}
2022-01-05 14:38:38 -05:00
err = queue . add ( testCtx , & 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 (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
entry . Data = queue . Bytes ()
2022-01-05 14:38:38 -05:00
types , err := NewTypeCatalog ( testCtx , Type { new ( oplog_test . TestUser ), "not-valid-name" })
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
_ , err = entry . UnmarshalData ( testCtx , 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 ) {
2022-01-05 14:38:38 -05:00
testCtx := context . Background ()
2022-11-16 17:17:28 -06:00
db , wrapper := setup ( testCtx , 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
// setup new tables for replay
tableSuffix := "_" + id
2022-01-05 14:38:38 -05:00
writer := Writer { db }
2020-04-20 16:42:16 -04:00
2020-06-10 06:56:46 -04:00
userModel := & oplog_test . TestUser {}
replayUserTable := fmt . Sprintf ( "%s%s" , userModel . TableName (), tableSuffix )
2022-01-05 14:38:38 -05:00
defer func () { require . NoError ( t , writer . dropTableIfExists ( testCtx , replayUserTable )) }()
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
ticketer , err := NewTicketer ( testCtx , db , WithAggregateNames ( true ))
2020-06-10 06:56:46 -04:00
require . NoError ( t , err )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
t . Run ( "replay:create/update/createitems" , func ( t * testing . T ) {
2020-06-10 06:56:46 -04:00
assert , require := assert . New ( t ), require . New ( t )
2022-01-05 14:38:38 -05:00
ticket , err := ticketer . GetTicket ( testCtx , "default" )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
newLogEntry , err := NewEntry (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
tx := dbw . New ( 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
}
2022-01-05 14:38:38 -05:00
version := uint32 ( 1 )
rowsUpdated , err := tx . Update ( testCtx , & userSave , [] string { "Email" }, nil , dbw . WithVersion ( & version ), dbw . WithWhere ( "name = ?" , loginName ))
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
require . Equal ( 1 , rowsUpdated )
2020-04-08 14:55:40 -04:00
2020-04-20 16:42:16 -04:00
userUpdate := oplog_test . TestUser {
2022-01-05 14:38:38 -05:00
Id : userCreate . Id ,
PhoneNumber : "867-5309" ,
2020-04-08 14:55:40 -04:00
}
2022-01-05 14:38:38 -05:00
tx . Update ( testCtx , & userUpdate , [] string { "PhoneNumber" }, [] string { "Name" })
require . NoError ( err )
underlyingDB , err := tx . DB (). SqlDB ( testCtx )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
_ , dialectName , err := tx . DB (). DbType ()
2021-09-30 08:47:34 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
dbassert := dbassert . New ( t , underlyingDB , dialectName )
2020-06-10 06:56:46 -04:00
dbassert . IsNull ( & userUpdate , "Name" )
2022-01-05 14:38:38 -05:00
foundCreateUser := testFindUser ( t , tx . DB (), userCreate . Id )
2020-06-10 06:56:46 -04:00
require . Equal ( foundCreateUser . Id , userCreate . Id )
require . Equal ( foundCreateUser . Name , "" )
require . Equal ( foundCreateUser . PhoneNumber , userUpdate . PhoneNumber )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
userCreateItems := & oplog_test . TestUser {
Name : "foo-" + testId ( t ),
}
2024-08-01 11:18:53 -04:00
require . NoError ( dbw . New ( db ). CreateItems ( context . Background (), [] * oplog_test . TestUser { userCreateItems }))
2022-01-05 14:38:38 -05:00
err = newLogEntry . WriteEntryWith ( context . Background (), & Writer { tx . DB ()}, ticket ,
2020-06-10 06:56:46 -04:00
& Message { Message : userCreate , TypeName : "user" , OpType : OpType_OP_TYPE_CREATE },
2022-01-05 14:38:38 -05:00
& Message { Message : & userSave , TypeName : "user" , OpType : OpType_OP_TYPE_UPDATE , FieldMaskPaths : [] string { "Email" }, SetToNullPaths : nil , Opts : [] dbw . Option { dbw . WithVersion ( & version ), dbw . WithWhere ( "name = ?" , loginName )}},
2020-06-10 06:56:46 -04:00
& 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" }},
2022-01-05 14:38:38 -05:00
& Message { Message : userCreateItems , TypeName : "user" , OpType : OpType_OP_TYPE_CREATE_ITEMS },
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
2022-01-05 14:38:38 -05:00
types , err := NewTypeCatalog ( testCtx , 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
2022-10-25 18:29:38 -05:00
require . NoError ( tx . LookupWhere ( testCtx , & foundEntry , "id = ?" , [] any { newLogEntry . Id }))
2022-11-16 17:17:28 -06:00
foundEntry . Wrapper = wrapper
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
2022-01-05 14:38:38 -05:00
err = foundEntry . Replay ( context . Background (), & Writer { tx . DB ()}, types , tableSuffix )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
foundUser := testFindUser ( t , tx . DB (), 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
2022-10-25 18:29:38 -05:00
require . NoError ( tx . LookupWhere ( testCtx , & foundReplayedUser , "id = ?" , [] any { userCreate . Id }))
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" )
2022-01-05 14:38:38 -05:00
foundReplayedUser . Id = 0
2022-10-25 18:29:38 -05:00
require . NoError ( tx . LookupWhere ( testCtx , & foundReplayedUser , "id = ?" , [] any { userCreateItems . Id }, dbw . WithDebug ( true )))
2022-01-05 14:38:38 -05:00
require . NoError ( err )
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...
2022-01-05 14:38:38 -05:00
tx2 , err := dbw . New ( db ). Begin ( testCtx )
require . NoError ( err )
defer tx2 . Commit ( testCtx )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
ticket2 , err := ticketer . GetTicket ( testCtx , "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
}
2022-01-05 14:38:38 -05:00
err = tx2 . Create ( testCtx , & userCreate2 )
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
}
2022-01-05 14:38:38 -05:00
_ , err = tx2 . Delete ( testCtx , & deleteUser2 )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
newLogEntry2 , err := NewEntry (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
err = newLogEntry2 . WriteEntryWith ( context . Background (), & Writer { tx2 . DB ()}, 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
2022-10-25 18:29:38 -05:00
err = tx2 . LookupWhere ( testCtx , & foundEntry2 , "id = ?" , [] any { newLogEntry2 . Id })
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-11-16 17:17:28 -06:00
foundEntry2 . Wrapper = wrapper
2020-04-08 14:55:40 -04:00
err = foundEntry2 . DecryptData ( context . Background ())
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
types , err := NewTypeCatalog ( testCtx , 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
2022-01-05 14:38:38 -05:00
err = foundEntry2 . Replay ( context . Background (), & Writer { tx2 . DB ()}, 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
2022-10-25 18:29:38 -05:00
err = tx2 . LookupWhere ( testCtx , & foundUser2 , "id = ?" , [] any { userCreate2 . Id })
2022-01-05 14:38:38 -05:00
assert . ErrorIs ( err , dbw . ErrRecordNotFound )
2020-04-08 14:55:40 -04:00
var foundReplayedUser2 oplog_test . TestUser
2022-10-25 18:29:38 -05:00
err = tx2 . LookupWhere ( testCtx , & foundReplayedUser2 , "id = ?" , [] any { userCreate2 . Id })
2022-01-05 14:38:38 -05:00
assert . ErrorIs ( err , dbw . ErrRecordNotFound )
})
t . Run ( "replay:deleteitems" , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
// we need to test delete replays now...
tx2 , err := dbw . New ( db ). Begin ( testCtx )
require . NoError ( err )
defer tx2 . Commit ( testCtx )
ticket2 , err := ticketer . GetTicket ( testCtx , "default" )
require . NoError ( err )
id4 := testId ( t )
loginName2 := "foo-" + id4
// create a user that's replayable
userCreate2 := oplog_test . TestUser {
Name : loginName2 ,
}
err = tx2 . Create ( testCtx , & userCreate2 )
require . NoError ( err )
deleteUser2 := oplog_test . TestUser {
Id : userCreate2 . Id ,
}
2024-08-01 11:18:53 -04:00
_ , err = tx2 . DeleteItems ( testCtx , [] * oplog_test . TestUser { & deleteUser2 })
2022-01-05 14:38:38 -05:00
require . NoError ( err )
newLogEntry2 , err := NewEntry (
testCtx ,
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2022-01-05 14:38:38 -05:00
ticketer ,
)
require . NoError ( err )
err = newLogEntry2 . WriteEntryWith ( context . Background (), & Writer { tx2 . DB ()}, ticket2 ,
& Message { Message : & userCreate2 , TypeName : "user" , OpType : OpType_OP_TYPE_CREATE },
& Message { Message : & deleteUser2 , TypeName : "user" , OpType : OpType_OP_TYPE_DELETE_ITEMS },
)
require . NoError ( err )
var foundEntry2 Entry
2022-10-25 18:29:38 -05:00
err = tx2 . LookupWhere ( testCtx , & foundEntry2 , "id = ?" , [] any { newLogEntry2 . Id })
2022-01-05 14:38:38 -05:00
require . NoError ( err )
2022-11-16 17:17:28 -06:00
foundEntry2 . Wrapper = wrapper
2022-01-05 14:38:38 -05:00
err = foundEntry2 . DecryptData ( context . Background ())
require . NoError ( err )
types , err := NewTypeCatalog ( testCtx , Type { new ( oplog_test . TestUser ), "user" })
require . NoError ( err )
err = foundEntry2 . Replay ( context . Background (), & Writer { tx2 . DB ()}, types , tableSuffix )
require . NoError ( err )
var foundUser2 oplog_test . TestUser
2022-10-25 18:29:38 -05:00
err = tx2 . LookupWhere ( testCtx , & foundUser2 , "id = ?" , [] any { userCreate2 . Id })
2022-01-05 14:38:38 -05:00
assert . ErrorIs ( err , dbw . ErrRecordNotFound )
var foundReplayedUser2 oplog_test . TestUser
2022-10-25 18:29:38 -05:00
err = tx2 . LookupWhere ( testCtx , & foundReplayedUser2 , "id = ?" , [] any { userCreate2 . Id })
2022-01-05 14:38:38 -05:00
assert . ErrorIs ( err , dbw . ErrRecordNotFound )
2020-04-08 14:55:40 -04:00
})
}
// Test_WriteEntryWith provides unit tests for oplog.WriteEntryWith
func Test_WriteEntryWith ( t * testing . T ) {
2022-01-05 14:38:38 -05:00
testCtx := context . Background ()
2022-11-16 17:17:28 -06:00
db , wrapper := setup ( testCtx , 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 )
2022-01-05 14:38:38 -05:00
ticketer , err := NewTicketer ( testCtx , db , WithAggregateNames ( true ))
2020-06-10 06:56:46 -04:00
require . NoError ( t , err )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
ticket , err := ticketer . GetTicket ( testCtx , "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 (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
err = newLogEntry . WriteEntryWith ( context . Background (), & Writer { 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
2022-10-25 18:29:38 -05:00
require . NoError ( dbw . New ( db ). LookupWhere ( testCtx , & foundEntry , "id = ?" , [] any { newLogEntry . Id }))
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-11-16 17:17:28 -06:00
foundEntry . Wrapper = wrapper
2022-01-05 14:38:38 -05:00
types , err := NewTypeCatalog ( testCtx , 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 )
2022-01-05 14:38:38 -05:00
foundUsers , err := foundEntry . UnmarshalData ( testCtx , 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 (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
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 (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
err = newLogEntry . WriteEntryWith ( context . Background (), & Writer { 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 (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
err = newLogEntry . WriteEntryWith ( context . Background (), & Writer { 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
})
}
2022-01-05 14:38:38 -05:00
func TestEntry_WriteEntryWith ( t * testing . T ) {
2022-11-16 17:17:28 -06:00
assert , require := assert . New ( t ), require . New ( t )
2022-01-05 14:38:38 -05:00
testCtx := context . Background ()
2022-11-16 17:17:28 -06:00
db , wrapper := setup ( testCtx , t )
2022-01-05 14:38:38 -05:00
db . Debug ( true )
// setup new tables for replay
id := testId ( t )
tableSuffix := "_" + id
ticketer , err := NewTicketer ( testCtx , db , WithAggregateNames ( true ))
2022-11-16 17:17:28 -06:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
newEntryFn := func () * Entry {
testEntry , err := NewEntry (
testCtx ,
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2022-01-05 14:38:38 -05:00
ticketer ,
)
2022-11-16 17:17:28 -06:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
return testEntry
}
tests := [] struct {
name string
e * Entry
w * Writer
msg * Message
wantErr bool
wantErrContains string
}{
{
name : "on-conflict-columns-do-nothing" ,
e : newEntryFn (),
w : & Writer { db },
msg : & Message {
Message : testUser ( t , db , "foo-" + testId ( t ), "" , "" ),
TypeName : "user" , OpType : OpType_OP_TYPE_CREATE ,
Opts : [] dbw . Option {
dbw . WithOnConflict ( & dbw . OnConflict {
Target : dbw . Columns { "name" },
Action : dbw . DoNothing ( true ),
}),
},
},
},
{
name : "on-conflict-columns-update-all" ,
e : newEntryFn (),
w : & Writer { db },
msg : & Message {
Message : testUser ( t , db , "foo-" + testId ( t ), "" , "" ),
TypeName : "user" , OpType : OpType_OP_TYPE_CREATE ,
Opts : [] dbw . Option {
dbw . WithOnConflict ( & dbw . OnConflict {
Target : dbw . Columns { "name" },
Action : dbw . UpdateAll ( true ),
}),
},
},
},
{
name : "on-conflict-columns-set-col-value-with-expr" ,
e : newEntryFn (),
w : & Writer { db },
msg : & Message {
Message : testUser ( t , db , "foo-" + testId ( t ), "" , "" ),
TypeName : "user" , OpType : OpType_OP_TYPE_CREATE ,
Opts : [] dbw . Option {
dbw . WithOnConflict ( & dbw . OnConflict {
Target : dbw . Columns { "name" },
2022-10-25 18:29:38 -05:00
Action : dbw . SetColumnValues ( map [ string ] any { "name" : dbw . Expr ( "NULL" )}),
2022-01-05 14:38:38 -05:00
}),
},
},
},
{
name : "on-conflict-columns-set-col-value" ,
e : newEntryFn (),
w : & Writer { db },
msg : & Message {
Message : testUser ( t , db , "foo-" + testId ( t ), "" , "" ),
TypeName : "user" , OpType : OpType_OP_TYPE_CREATE ,
Opts : [] dbw . Option {
dbw . WithOnConflict ( & dbw . OnConflict {
Target : dbw . Columns { "name" },
2022-10-25 18:29:38 -05:00
Action : dbw . SetColumnValues ( map [ string ] any { "name" : testId ( t )}),
2022-01-05 14:38:38 -05:00
}),
},
},
},
{
name : "on-conflict-columns-set-col-value" ,
e : newEntryFn (),
w : & Writer { db },
msg : & Message {
Message : testUser ( t , db , "foo-" + testId ( t ), "" , "" ),
TypeName : "user" , OpType : OpType_OP_TYPE_CREATE ,
Opts : [] dbw . Option {
dbw . WithOnConflict ( & dbw . OnConflict {
Target : dbw . Columns { "name" },
Action : dbw . SetColumns ([] string { "email" }),
}),
},
},
},
{
name : "missing-entry" ,
e : func () * Entry { e := newEntryFn (); e . Entry = nil ; return e }(),
w : & Writer { db },
msg : & Message {
Message : testUser ( t , db , "foo-" + testId ( t ), "" , "" ),
TypeName : "user" , OpType : OpType_OP_TYPE_CREATE ,
},
wantErr : true ,
wantErrContains : "nil entry" ,
},
{
name : "missing-entry-version" ,
e : func () * Entry { e := newEntryFn (); e . Entry . Version = "" ; return e }(),
w : & Writer { db },
msg : & Message {
Message : testUser ( t , db , "foo-" + testId ( t ), "" , "" ),
TypeName : "user" , OpType : OpType_OP_TYPE_CREATE ,
},
wantErr : true ,
wantErrContains : "missing entry version" ,
},
// TODO: jimlambrt (Dec 2021) - we need a way to create a replay table
// that contains the existing named constraints. Once that done, we can
// enable this test and write more. This is just an example of the type
// test we need to create using a constraint target
// {
// name: "on-conflict-column-value",
// e: testEntry,
// w: &Writer{db},
// msg: &Message{
// Message: testUser(t, db, "foo-"+testId(t), "", ""),
// TypeName: "user", OpType: OpType_OP_TYPE_CREATE,
// Opts: []dbw.Option{
// dbw.WithOnConflict(&dbw.OnConflict{
// Target: dbw.Constraint{"oplog_test_user_name_uq"},
// Action: dbw.SetColumnValues(map[string]interface{}{"name": dbw.Expr("NULL")}),
// })},
// },
// },
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
ticket , err := ticketer . GetTicket ( testCtx , "default" )
require . NoError ( err )
err = tt . e . WriteEntryWith (
testCtx ,
tt . w ,
ticket ,
tt . msg ,
)
if tt . wantErr {
require . Error ( err )
if tt . wantErrContains != "" {
assert . Contains ( err . Error (), tt . wantErrContains )
}
return
}
require . NoError ( err )
var foundEntry Entry
2022-10-25 18:29:38 -05:00
require . NoError ( dbw . New ( db ). LookupWhere ( testCtx , & foundEntry , "id = ?" , [] any { tt . e . Id }))
2022-01-05 14:38:38 -05:00
require . NoError ( err )
2022-11-16 17:17:28 -06:00
foundEntry . Wrapper = wrapper
2022-01-05 14:38:38 -05:00
types , err := NewTypeCatalog ( testCtx , Type { new ( oplog_test . TestUser ), "user" })
require . NoError ( err )
err = foundEntry . DecryptData ( context . Background ())
require . NoError ( err )
msgs , err := foundEntry . UnmarshalData ( testCtx , types )
require . NoError ( err )
require . Equal ( 1 , len ( msgs ))
entry := msgs [ 0 ]
entryUser := entry . Message .( * oplog_test . TestUser )
assert . Equal ( entryUser . Name , tt . msg . Message .( * oplog_test . TestUser ). Name )
assert . Equal ( entry . FieldMaskPaths , tt . msg . FieldMaskPaths )
assert . Equal ( entry . SetToNullPaths , tt . msg . SetToNullPaths )
assert . Equal ( entry . OpType , tt . msg . OpType )
assert . Equal ( entry . TypeName , tt . msg . TypeName )
entryOpts := dbw . GetOpts ( entry . Opts ... )
testMsgOpts := dbw . GetOpts ( tt . msg . Opts ... )
assert . Equal ( entryOpts , testMsgOpts )
2022-11-16 17:17:28 -06:00
foundEntry . Wrapper = wrapper
2022-01-05 14:38:38 -05:00
err = foundEntry . DecryptData ( context . Background ())
require . NoError ( err )
err = foundEntry . Replay ( context . Background (), tt . w , types , tableSuffix )
require . NoError ( err )
foundUser := testFindUser ( t , tt . w . DB , entryUser . Id )
var foundReplayedUser oplog_test . TestUser
foundReplayedUser . Table = foundReplayedUser . TableName () + tableSuffix
2022-10-25 18:29:38 -05:00
require . NoError ( dbw . New ( tt . w . DB ). LookupWhere ( testCtx , & foundReplayedUser , "id = ?" , [] any { entryUser . Id }))
2022-01-05 14:38:38 -05:00
require . NoError ( err )
assert . Equal ( foundUser . Id , foundReplayedUser . Id )
assert . Equal ( foundUser . Name , foundReplayedUser . Name )
assert . Equal ( foundUser . PhoneNumber , foundReplayedUser . PhoneNumber )
assert . Equal ( foundUser . Email , foundReplayedUser . Email )
})
}
}
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-06-10 06:56:46 -04:00
assert , require := assert . New ( t ), require . New ( t )
2022-01-05 14:38:38 -05:00
testCtx := context . Background ()
2022-11-16 17:17:28 -06:00
db , wrapper := setup ( testCtx , t )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
ticketer , err := NewTicketer ( testCtx , 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
id := testId ( t )
2022-01-05 14:38:38 -05:00
firstTx , err := dbw . New ( db ). Begin ( testCtx )
require . NoError ( err )
2020-04-08 14:55:40 -04:00
firstUser := oplog_test . TestUser {
Name : "foo-" + id ,
}
2022-01-05 14:38:38 -05:00
err = firstTx . Create ( testCtx , & firstUser )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
firstTicket , err := ticketer . GetTicket ( testCtx , "default" )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
firstQueue := Queue {}
2022-01-05 14:38:38 -05:00
err = firstQueue . add ( testCtx , & 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 (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"test-users" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
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 )
2022-01-05 14:38:38 -05:00
secondTx , err := dbw . New ( db ). Begin ( testCtx )
require . NoError ( err )
2020-04-08 14:55:40 -04:00
secondUser := oplog_test . TestUser {
Name : "foo-" + id2 ,
}
2022-01-05 14:38:38 -05:00
err = secondTx . Create ( testCtx , & secondUser )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2022-01-05 14:38:38 -05:00
secondTicket , err := ticketer . GetTicket ( testCtx , "default" )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
secondQueue := Queue {}
2022-01-05 14:38:38 -05:00
err = secondQueue . add ( testCtx , & 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 (
2022-01-05 14:38:38 -05:00
testCtx ,
2020-04-08 14:55:40 -04:00
"foobar" ,
Metadata {
"key-only" : nil ,
"deployment" : [] string { "amex" },
"project" : [] string { "central-info-systems" , "local-info-systems" },
},
2022-11-16 17:17:28 -06:00
wrapper ,
2020-04-08 14:55:40 -04:00
ticketer ,
)
2020-06-10 06:56:46 -04:00
require . NoError ( err )
2020-04-08 14:55:40 -04:00
secondLogEntry . Data = secondQueue . Bytes ()
2022-01-05 14:38:38 -05:00
err = secondLogEntry . Write ( context . Background (), & Writer { secondTx . DB ()}, 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 )
2022-01-05 14:38:38 -05:00
err = secondTx . Commit ( testCtx )
2020-06-10 06:56:46 -04:00
require . NoError ( err )
assert . NotNil ( secondLogEntry . Id )
2020-04-08 14:55:40 -04:00
2022-01-05 14:38:38 -05:00
err = firstLogEntry . Write ( context . Background (), & Writer { firstTx . DB ()}, firstTicket )
2020-04-08 14:55:40 -04:00
if err != nil {
2022-01-05 14:38:38 -05:00
firstTx . Rollback ( testCtx )
2020-04-08 14:55:40 -04:00
} else {
2022-01-05 14:38:38 -05:00
firstTx . Commit ( testCtx )
2020-04-08 14:55:40 -04:00
t . Error ( "should have failed to write firstLogEntry" )
}
}