diff --git a/common_test.go b/common_test.go new file mode 100644 index 00000000..89f7dc69 --- /dev/null +++ b/common_test.go @@ -0,0 +1,131 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcdb_test + +import ( + "fmt" + "github.com/conformal/btcdb" + _ "github.com/conformal/btcdb/ldb" + _ "github.com/conformal/btcdb/sqlite3" + "github.com/conformal/btcutil" + "github.com/conformal/btcwire" + "os" + "path/filepath" +) + +var zeroHash = btcwire.ShaHash{} + +// testDbRoot is the root directory used to create all test databases. +const testDbRoot = "testdbs" + +// filesExists returns whether or not the named file or directory exists. +func fileExists(name string) bool { + if _, err := os.Stat(name); err != nil { + if os.IsNotExist(err) { + return false + } + } + return true +} + +// openDB is used to open an existing database based on the database type and +// name. +func openDB(dbType, dbName string) (btcdb.Db, error) { + // Handle memdb specially since it has no files on disk. + if dbType == "memdb" { + db, err := btcdb.OpenDB(dbType, "") + if err != nil { + return nil, fmt.Errorf("error opening db: %v", err) + } + return db, nil + } + + dbPath := filepath.Join(testDbRoot, dbName) + db, err := btcdb.OpenDB(dbType, dbPath) + if err != nil { + return nil, fmt.Errorf("error opening db: %v", err) + } + + return db, nil +} + +// createDB creates a new db instance and returns a teardown function the caller +// should invoke when done testing to clean up. The close flag indicates +// whether or not the teardown function should sync and close the database +// during teardown. +func createDB(dbType, dbName string, close bool) (btcdb.Db, func(), error) { + // Handle memory database specially since it doesn't need the disk + // specific handling. + if dbType == "memdb" { + db, err := btcdb.CreateDB(dbType, "") + if err != nil { + return nil, nil, fmt.Errorf("error creating db: %v", err) + } + + // Setup a teardown function for cleaning up. This function is + // returned to the caller to be invoked when it is done testing. + teardown := func() { + if close { + db.Close() + } + } + + return db, teardown, nil + } + + // Create the root directory for test databases. + if !fileExists(testDbRoot) { + if err := os.MkdirAll(testDbRoot, 0700); err != nil { + err := fmt.Errorf("unable to create test db "+ + "root: %v", err) + return nil, nil, err + } + } + + // Create a new database to store the accepted blocks into. + dbPath := filepath.Join(testDbRoot, dbName) + _ = os.RemoveAll(dbPath) + db, err := btcdb.CreateDB(dbType, dbPath) + if err != nil { + return nil, nil, fmt.Errorf("error creating db: %v", err) + } + + // Setup a teardown function for cleaning up. This function is + // returned to the caller to be invoked when it is done testing. + teardown := func() { + dbVersionPath := filepath.Join(testDbRoot, dbName+".ver") + if close { + db.Sync() + db.Close() + } + os.RemoveAll(dbPath) + os.Remove(dbVersionPath) + os.RemoveAll(testDbRoot) + } + + return db, teardown, nil +} + +// setupDB is used to create a new db instance with the genesis block already +// inserted. In addition to the new db instance, it returns a teardown function +// the caller should invoke when done testing to clean up. +func setupDB(dbType, dbName string) (btcdb.Db, func(), error) { + db, teardown, err := createDB(dbType, dbName, true) + if err != nil { + return nil, nil, err + } + + // Insert the main network genesis block. This is part of the initial + // database setup. + genesisBlock := btcutil.NewBlock(&btcwire.GenesisBlock) + _, err = db.InsertBlock(genesisBlock) + if err != nil { + teardown() + err := fmt.Errorf("failed to insert genesis block: %v", err) + return nil, nil, err + } + + return db, teardown, nil +} diff --git a/interface_test.go b/interface_test.go new file mode 100644 index 00000000..ce3c50a8 --- /dev/null +++ b/interface_test.go @@ -0,0 +1,54 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcdb_test + +import ( + "github.com/conformal/btcdb" + "testing" +) + +// testNewestShaEmpty ensures the NewestSha returns the values expected by +// the interface contract. +func testNewestShaEmpty(t *testing.T, db btcdb.Db) { + sha, height, err := db.NewestSha() + if err != nil { + t.Errorf("NewestSha error %v", err) + } + if !sha.IsEqual(&zeroHash) { + t.Errorf("NewestSha wrong hash got: %s, want %s", sha, &zeroHash) + + } + if height != -1 { + t.Errorf("NewestSha wrong height got: %s, want %s", height, -1) + } +} + +// TestEmptyDB tests that empty databases are handled properly. +func TestEmptyDB(t *testing.T) { + for _, dbType := range btcdb.SupportedDBs() { + // Ensure NewestSha returns expected values for a newly created + // db. + db, teardown, err := createDB(dbType, "emptydb", false) + if err != nil { + t.Errorf("Failed to create test database %v", err) + return + } + testNewestShaEmpty(t, db) + + // Ensure NewestSha still returns expected values for an empty + // database after reopen. + db.Close() + db, err = openDB(dbType, "emptydb") + if err != nil { + t.Errorf("Failed to open test database %v", err) + return + } + testNewestShaEmpty(t, db) + db.Close() + + // Clean up the old db. + teardown() + } +}