mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00

* [NOD-849] Cover ffldb/transaction with tests. * [NOD-849] Cover cursor.go with tests. * [NOD-849] Cover ldb/transaction with tests. * [NOD-849] Cover location.go with tests. * [NOD-849] Write TestFlatFileMultiFileRollback. * [NOD-849] Fix merge errors. * [NOD-849] Fix a comment. * [NOD-849] Fix a comment. * [NOD-849] Add a test that makes sure that files get deleted on rollback. * [NOD-849] Add a test that makes sure that serializeLocation serialized to an expected value. * [NOD-849] Improve TestFlatFileLocationDeserializationErrors. * [NOD-849] Fix a copy+paste error. * [NOD-849] Explain maxFileSize = 16. * [NOD-849] Remove redundant RollbackUnlessClosed call. * [NOD-849] Extract bucket to a variable in TestCursorSanity. * [NOD-849] Rename TestKeyValueTransactionCommit to TestTransactionCommitForLevelDBMethods. * [NOD-849] Extract prepareXXX into separate functions. * [NOD-849] Simplify function calls in TestTransactionCloseErrors. * [NOD-849] Extract validateCurrentCursorKeyAndValue to a separate function. * [NOD-849] Add a comment over TestCursorSanity. * [NOD-849] Add a comment over function in TestCursorCloseErrors. * [NOD-849] Add a comment over function in TestTransactionCloseErrors. * [NOD-849] Separate TestTransactionCloseErrors to TestTransactionCommitErrors and TestTransactionRollbackErrors. * [NOD-849] Separate TestTransactionCloseErrors to TestTransactionCommitErrors and TestTransactionRollbackErrors. * [NOD-849] Fix copy+paste error in comments. * [NOD-849] Fix merge errors. * [NOD-849] Merge TestTransactionCommitErrors and TestTransactionRollbackErrors into TestTransactionCloseErrors. * [NOD-849] Move prepareDatabaseForTest into ffldb_test.go. * [NOD-849] Add cursorKey to Value error messages in validateCurrentCursorKeyAndValue.
501 lines
14 KiB
Go
501 lines
14 KiB
Go
package ffldb
|
|
|
|
import (
|
|
"bytes"
|
|
"github.com/kaspanet/kaspad/database"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestTransactionCommitForLevelDBMethods(t *testing.T) {
|
|
db, teardownFunc := prepareDatabaseForTest(t, "TestTransactionCommitForLevelDBMethods")
|
|
defer teardownFunc()
|
|
|
|
// Put a value into the database
|
|
key1 := database.MakeBucket().Key([]byte("key1"))
|
|
value1 := []byte("value1")
|
|
err := db.Put(key1, value1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Put "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Begin a new transaction
|
|
dbTx, err := db.Begin()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Begin "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
defer func() {
|
|
err := dbTx.RollbackUnlessClosed()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: RollbackUnlessClosed "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
}()
|
|
|
|
// Make sure that Has returns that the original value exists
|
|
exists, err := dbTx.Has(key1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Has "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if !exists {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Has " +
|
|
"unexpectedly returned that the value does not exist")
|
|
}
|
|
|
|
// Get the existing value and make sure it's equal to the original
|
|
existingValue, err := dbTx.Get(key1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Get "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if !bytes.Equal(existingValue, value1) {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Get "+
|
|
"returned unexpected value. Want: %s, got: %s",
|
|
string(value1), string(existingValue))
|
|
}
|
|
|
|
// Delete the existing value
|
|
err = dbTx.Delete(key1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Delete "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Try to get a value that does not exist and make sure it returns ErrNotFound
|
|
_, err = dbTx.Get(database.MakeBucket().Key([]byte("doesn't exist")))
|
|
if err == nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Get " +
|
|
"unexpectedly succeeded")
|
|
}
|
|
if !database.IsNotFoundError(err) {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Get "+
|
|
"returned unexpected error: %s", err)
|
|
}
|
|
|
|
// Put a new value
|
|
key2 := database.MakeBucket().Key([]byte("key2"))
|
|
value2 := []byte("value2")
|
|
err = dbTx.Put(key2, value2)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Put "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Commit the transaction
|
|
err = dbTx.Commit()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Commit "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Make sure that Has returns that the original value does NOT exist
|
|
exists, err = db.Has(key1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Has "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if exists {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Has " +
|
|
"unexpectedly returned that the value exists")
|
|
}
|
|
|
|
// Try to Get the existing value and make sure an ErrNotFound is returned
|
|
_, err = db.Get(key1)
|
|
if err == nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Get " +
|
|
"unexpectedly succeeded")
|
|
}
|
|
if !database.IsNotFoundError(err) {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Get "+
|
|
"returned unexpected err: %s", err)
|
|
}
|
|
|
|
// Make sure that Has returns that the new value exists
|
|
exists, err = db.Has(key2)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Has "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if !exists {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Has " +
|
|
"unexpectedly returned that the value does not exist")
|
|
}
|
|
|
|
// Get the new value and make sure it's equal to the original
|
|
existingValue, err = db.Get(key2)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Get "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if !bytes.Equal(existingValue, value2) {
|
|
t.Fatalf("TestTransactionCommitForLevelDBMethods: Get "+
|
|
"returned unexpected value. Want: %s, got: %s",
|
|
string(value2), string(existingValue))
|
|
}
|
|
}
|
|
|
|
func TestTransactionRollbackForLevelDBMethods(t *testing.T) {
|
|
db, teardownFunc := prepareDatabaseForTest(t, "TestTransactionRollbackForLevelDBMethods")
|
|
defer teardownFunc()
|
|
|
|
// Put a value into the database
|
|
key1 := database.MakeBucket().Key([]byte("key1"))
|
|
value1 := []byte("value1")
|
|
err := db.Put(key1, value1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Put "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Begin a new transaction
|
|
dbTx, err := db.Begin()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Begin "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
defer func() {
|
|
err := dbTx.RollbackUnlessClosed()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: RollbackUnlessClosed "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
}()
|
|
|
|
// Make sure that Has returns that the original value exists
|
|
exists, err := dbTx.Has(key1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Has "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if !exists {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Has " +
|
|
"unexpectedly returned that the value does not exist")
|
|
}
|
|
|
|
// Get the existing value and make sure it's equal to the original
|
|
existingValue, err := dbTx.Get(key1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Get "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if !bytes.Equal(existingValue, value1) {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Get "+
|
|
"returned unexpected value. Want: %s, got: %s",
|
|
string(value1), string(existingValue))
|
|
}
|
|
|
|
// Delete the existing value
|
|
err = dbTx.Delete(key1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Delete "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Put a new value
|
|
key2 := database.MakeBucket().Key([]byte("key2"))
|
|
value2 := []byte("value2")
|
|
err = dbTx.Put(key2, value2)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Put "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Rollback the transaction
|
|
err = dbTx.Rollback()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Rollback "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Make sure that Has returns that the original value still exists
|
|
exists, err = db.Has(key1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Has "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if !exists {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Has " +
|
|
"unexpectedly returned that the value does not exist")
|
|
}
|
|
|
|
// Get the existing value and make sure it is still returned
|
|
existingValue, err = db.Get(key1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Get "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if !bytes.Equal(existingValue, value1) {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Get "+
|
|
"returned unexpected value. Want: %s, got: %s",
|
|
string(value1), string(existingValue))
|
|
}
|
|
|
|
// Make sure that Has returns that the new value does NOT exist
|
|
exists, err = db.Has(key2)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Has "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if exists {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Has " +
|
|
"unexpectedly returned that the value exists")
|
|
}
|
|
|
|
// Try to Get the new value and make sure it returns an ErrNotFound
|
|
_, err = db.Get(key2)
|
|
if err == nil {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Get " +
|
|
"unexpectedly succeeded")
|
|
}
|
|
if !database.IsNotFoundError(err) {
|
|
t.Fatalf("TestTransactionRollbackForLevelDBMethods: Get "+
|
|
"returned unexpected error: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestTransactionCloseErrors(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
function func(dbTx database.Transaction) error
|
|
shouldReturnError bool
|
|
}{
|
|
{
|
|
name: "Put",
|
|
function: func(dbTx database.Transaction) error {
|
|
return dbTx.Put(database.MakeBucket().Key([]byte("key")), []byte("value"))
|
|
},
|
|
shouldReturnError: true,
|
|
},
|
|
{
|
|
name: "Get",
|
|
function: func(dbTx database.Transaction) error {
|
|
_, err := dbTx.Get(database.MakeBucket().Key([]byte("key")))
|
|
return err
|
|
},
|
|
shouldReturnError: true,
|
|
},
|
|
{
|
|
name: "Has",
|
|
function: func(dbTx database.Transaction) error {
|
|
_, err := dbTx.Has(database.MakeBucket().Key([]byte("key")))
|
|
return err
|
|
},
|
|
shouldReturnError: true,
|
|
},
|
|
{
|
|
name: "Delete",
|
|
function: func(dbTx database.Transaction) error {
|
|
return dbTx.Delete(database.MakeBucket().Key([]byte("key")))
|
|
},
|
|
shouldReturnError: true,
|
|
},
|
|
{
|
|
name: "Cursor",
|
|
function: func(dbTx database.Transaction) error {
|
|
_, err := dbTx.Cursor(database.MakeBucket([]byte("bucket")))
|
|
return err
|
|
},
|
|
shouldReturnError: true,
|
|
},
|
|
{
|
|
name: "AppendToStore",
|
|
function: func(dbTx database.Transaction) error {
|
|
_, err := dbTx.AppendToStore("store", []byte("data"))
|
|
return err
|
|
},
|
|
shouldReturnError: true,
|
|
},
|
|
{
|
|
name: "RetrieveFromStore",
|
|
function: func(dbTx database.Transaction) error {
|
|
_, err := dbTx.RetrieveFromStore("store", []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
|
return err
|
|
},
|
|
shouldReturnError: true,
|
|
},
|
|
{
|
|
name: "Rollback",
|
|
function: func(dbTx database.Transaction) error {
|
|
return dbTx.Rollback()
|
|
},
|
|
shouldReturnError: true,
|
|
},
|
|
{
|
|
name: "Commit",
|
|
function: func(dbTx database.Transaction) error {
|
|
return dbTx.Commit()
|
|
},
|
|
shouldReturnError: true,
|
|
},
|
|
{
|
|
name: "RollbackUnlessClosed",
|
|
function: func(dbTx database.Transaction) error {
|
|
return dbTx.RollbackUnlessClosed()
|
|
},
|
|
shouldReturnError: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
func() {
|
|
db, teardownFunc := prepareDatabaseForTest(t, "TestTransactionCloseErrors")
|
|
defer teardownFunc()
|
|
|
|
// Begin a new transaction to test Commit
|
|
commitTx, err := db.Begin()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCloseErrors: Begin "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
defer func() {
|
|
err := commitTx.RollbackUnlessClosed()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCloseErrors: RollbackUnlessClosed "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
}()
|
|
|
|
// Commit the Commit test transaction
|
|
err = commitTx.Commit()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCloseErrors: Commit "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Begin a new transaction to test Rollback
|
|
rollbackTx, err := db.Begin()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCloseErrors: Begin "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
defer func() {
|
|
err := rollbackTx.RollbackUnlessClosed()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCloseErrors: RollbackUnlessClosed "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
}()
|
|
|
|
// Rollback the Rollback test transaction
|
|
err = rollbackTx.Rollback()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCloseErrors: Rollback "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
expectedErrContainsString := "closed transaction"
|
|
|
|
// Make sure that the test function returns a "closed transaction" error
|
|
// for both the commitTx and the rollbackTx
|
|
for _, closedTx := range []database.Transaction{commitTx, rollbackTx} {
|
|
err = test.function(closedTx)
|
|
if test.shouldReturnError {
|
|
if err == nil {
|
|
t.Fatalf("TestTransactionCloseErrors: %s "+
|
|
"unexpectedly succeeded", test.name)
|
|
}
|
|
if !strings.Contains(err.Error(), expectedErrContainsString) {
|
|
t.Fatalf("TestTransactionCloseErrors: %s "+
|
|
"returned wrong error. Want: %s, got: %s",
|
|
test.name, expectedErrContainsString, err)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCloseErrors: %s "+
|
|
"unexpectedly failed: %s", test.name, err)
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
func TestTransactionRollbackUnlessClosed(t *testing.T) {
|
|
db, teardownFunc := prepareDatabaseForTest(t, "TestTransactionRollbackUnlessClosed")
|
|
defer teardownFunc()
|
|
|
|
// Begin a new transaction
|
|
dbTx, err := db.Begin()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackUnlessClosed: Begin "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Roll it back
|
|
err = dbTx.RollbackUnlessClosed()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionRollbackUnlessClosed: RollbackUnlessClosed "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestTransactionCommitForFlatFileMethods(t *testing.T) {
|
|
db, teardownFunc := prepareDatabaseForTest(t, "TestTransactionCommitForFlatFileMethods")
|
|
defer teardownFunc()
|
|
|
|
// Put a value into the database
|
|
store := "store"
|
|
value1 := []byte("value1")
|
|
location1, err := db.AppendToStore(store, value1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForFlatFileMethods: AppendToStore "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Begin a new transaction
|
|
dbTx, err := db.Begin()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForFlatFileMethods: Begin "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
defer func() {
|
|
err := dbTx.RollbackUnlessClosed()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForFlatFileMethods: RollbackUnlessClosed "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
}()
|
|
|
|
// Retrieve the existing value and make sure it's equal to the original
|
|
existingValue, err := dbTx.RetrieveFromStore(store, location1)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForFlatFileMethods: RetrieveFromStore "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if !bytes.Equal(existingValue, value1) {
|
|
t.Fatalf("TestTransactionCommitForFlatFileMethods: RetrieveFromStore "+
|
|
"returned unexpected value. Want: %s, got: %s",
|
|
string(value1), string(existingValue))
|
|
}
|
|
|
|
// Put a new value
|
|
value2 := []byte("value2")
|
|
location2, err := dbTx.AppendToStore(store, value2)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForFlatFileMethods: AppendToStore "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Commit the transaction
|
|
err = dbTx.Commit()
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForFlatFileMethods: Commit "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
|
|
// Retrieve the new value and make sure it's equal to the original
|
|
newValue, err := db.RetrieveFromStore(store, location2)
|
|
if err != nil {
|
|
t.Fatalf("TestTransactionCommitForFlatFileMethods: RetrieveFromStore "+
|
|
"unexpectedly failed: %s", err)
|
|
}
|
|
if !bytes.Equal(newValue, value2) {
|
|
t.Fatalf("TestTransactionCommitForFlatFileMethods: RetrieveFromStore "+
|
|
"returned unexpected value. Want: %s, got: %s",
|
|
string(value2), string(newValue))
|
|
}
|
|
}
|