kaspad/database/ffldb/ff/flatfile_test.go
stasatdaglabs 2e2492cc5d
[NOD-849] Database tests (#695)
* [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.
2020-05-03 12:19:09 +03:00

176 lines
4.9 KiB
Go

package ff
import (
"bytes"
"github.com/kaspanet/kaspad/database"
"io/ioutil"
"os"
"reflect"
"testing"
)
func prepareStoreForTest(t *testing.T, testName string) (store *flatFileStore, teardownFunc func()) {
// Create a temp db to run tests against
path, err := ioutil.TempDir("", testName)
if err != nil {
t.Fatalf("%s: TempDir unexpectedly "+
"failed: %s", testName, err)
}
name := "test"
store, err = openFlatFileStore(path, name)
if err != nil {
t.Fatalf("%s: openFlatFileStore "+
"unexpectedly failed: %s", testName, err)
}
teardownFunc = func() {
err = store.Close()
if err != nil {
t.Fatalf("%s: Close unexpectedly "+
"failed: %s", testName, err)
}
}
return store, teardownFunc
}
func TestFlatFileStoreSanity(t *testing.T) {
store, teardownFunc := prepareStoreForTest(t, "TestFlatFileStoreSanity")
defer teardownFunc()
// Write something to the store
writeData := []byte("Hello world!")
location, err := store.write(writeData)
if err != nil {
t.Fatalf("TestFlatFileStoreSanity: Write returned "+
"unexpected error: %s", err)
}
// Read from the location previously written to
readData, err := store.read(location)
if err != nil {
t.Fatalf("TestFlatFileStoreSanity: read returned "+
"unexpected error: %s", err)
}
// Make sure that the written data and the read data are equal
if !reflect.DeepEqual(readData, writeData) {
t.Fatalf("TestFlatFileStoreSanity: read data and "+
"write data are not equal. Wrote: %s, read: %s",
string(writeData), string(readData))
}
}
func TestFlatFilePath(t *testing.T) {
tests := []struct {
dbPath string
storeName string
fileNumber uint32
expectedPath string
}{
{
dbPath: "path",
storeName: "store",
fileNumber: 0,
expectedPath: "path/store-000000000.fdb",
},
{
dbPath: "path/to/database",
storeName: "blocks",
fileNumber: 123456789,
expectedPath: "path/to/database/blocks-123456789.fdb",
},
}
for _, test := range tests {
path := flatFilePath(test.dbPath, test.storeName, test.fileNumber)
if path != test.expectedPath {
t.Errorf("TestFlatFilePath: unexpected path. Want: %s, got: %s",
test.expectedPath, path)
}
}
}
func TestFlatFileMultiFileRollback(t *testing.T) {
store, teardownFunc := prepareStoreForTest(t, "TestFlatFileMultiFileRollback")
defer teardownFunc()
// Set the maxFileSize to 16 bytes so that we don't have to write
// an enormous amount of data to disk to get multiple files, all
// for the sake of this test.
currentMaxFileSize := maxFileSize
maxFileSize = 16
defer func() {
maxFileSize = currentMaxFileSize
}()
// Write five 8 byte chunks and keep the last location written to
var lastWriteLocation1 *flatFileLocation
for i := byte(0); i < 5; i++ {
writeData := []byte{i, i, i, i, i, i, i, i}
var err error
lastWriteLocation1, err = store.write(writeData)
if err != nil {
t.Fatalf("TestFlatFileMultiFileRollback: write returned "+
"unexpected error: %s", err)
}
}
// Grab the current location and the current file number
currentLocation := store.currentLocation()
fileNumberBeforeWriting := store.writeCursor.currentFileNumber
// Write (2 * maxOpenFiles) more 8 byte chunks and keep the last location written to
var lastWriteLocation2 *flatFileLocation
for i := byte(0); i < byte(2*maxFileSize); i++ {
writeData := []byte{0, 1, 2, 3, 4, 5, 6, 7}
var err error
lastWriteLocation2, err = store.write(writeData)
if err != nil {
t.Fatalf("TestFlatFileMultiFileRollback: write returned "+
"unexpected error: %s", err)
}
}
// Grab the file number again to later make sure its file no longer exists
fileNumberAfterWriting := store.writeCursor.currentFileNumber
// Rollback
err := store.rollback(currentLocation)
if err != nil {
t.Fatalf("TestFlatFileMultiFileRollback: rollback returned "+
"unexpected error: %s", err)
}
// Make sure that lastWriteLocation1 still exists
expectedData := []byte{4, 4, 4, 4, 4, 4, 4, 4}
data, err := store.read(lastWriteLocation1)
if err != nil {
t.Fatalf("TestFlatFileMultiFileRollback: read returned "+
"unexpected error: %s", err)
}
if !bytes.Equal(data, expectedData) {
t.Fatalf("TestFlatFileMultiFileRollback: read returned "+
"unexpected data. Want: %s, got: %s", string(expectedData),
string(data))
}
// Make sure that lastWriteLocation2 does NOT exist
_, err = store.read(lastWriteLocation2)
if err == nil {
t.Fatalf("TestFlatFileMultiFileRollback: read " +
"unexpectedly succeeded")
}
if !database.IsNotFoundError(err) {
t.Fatalf("TestFlatFileMultiFileRollback: read "+
"returned unexpected error: %s", err)
}
// Make sure that all the appropriate files have been deleted
for i := fileNumberAfterWriting; i > fileNumberBeforeWriting; i-- {
filePath := flatFilePath(store.basePath, store.storeName, i)
if _, err := os.Stat(filePath); err == nil || !os.IsNotExist(err) {
t.Fatalf("TestFlatFileMultiFileRollback: file "+
"unexpectedly still exists: %s", filePath)
}
}
}