dcrd/database/common_test.go
cjepson df701d8cdf Revert sync merge
The sync merge does not build and needs further testing. It is
being reverted.
2016-03-08 22:16:06 -05:00

185 lines
5.1 KiB
Go

// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package database_test
import (
"bytes"
"compress/bzip2"
"encoding/gob"
"fmt"
"os"
"path/filepath"
"testing"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/database"
_ "github.com/decred/dcrd/database/ldb"
_ "github.com/decred/dcrd/database/memdb"
"github.com/decred/dcrd/wire"
"github.com/decred/dcrutil"
)
var (
// network is the expected decred network in the test block data.
network = wire.SimNet
// savedBlocks is used to store blocks loaded from the blockDataFile
// so multiple invocations to loadBlocks from the various test functions
// do not have to reload them from disk.
savedBlocks []*dcrutil.Block
// blockDataFile is the path to a file containing the first 168 blocks
// of a simulated blockchain designed to abuse network rules.
blockDataFile = filepath.Join("../blockchain/testdata", "blocks0to168.bz2")
)
var zeroHash = chainhash.Hash{}
// 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) (database.Db, error) {
// Handle memdb specially since it has no files on disk.
if dbType == "memdb" {
db, err := database.OpenDB(dbType)
if err != nil {
return nil, fmt.Errorf("error opening db: %v", err)
}
return db, nil
}
dbPath := filepath.Join(testDbRoot, dbName)
db, err := database.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) (database.Db, func(), error) {
// Handle memory database specially since it doesn't need the disk
// specific handling.
if dbType == "memdb" {
db, err := database.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 := database.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) (database.Db, func(), error) {
db, teardown, err := createDB(dbType, dbName, true)
if err != nil {
return nil, nil, err
}
return db, teardown, nil
}
// loadBlocks loads the blocks contained in the testdata directory and returns
// a slice of them.
func loadBlocks(t *testing.T) ([]*dcrutil.Block, error) {
if len(savedBlocks) != 0 {
return savedBlocks, nil
}
fi, err := os.Open(blockDataFile)
if err != nil {
t.Errorf("failed to open file %v, err %v", blockDataFile, err)
return nil, err
}
bcStream := bzip2.NewReader(fi)
defer fi.Close()
// Create a buffer of the read file
bcBuf := new(bytes.Buffer)
bcBuf.ReadFrom(bcStream)
// Create decoder from the buffer and a map to store the data
bcDecoder := gob.NewDecoder(bcBuf)
blockchain := make(map[int64][]byte)
// Decode the blockchain into the map
if err := bcDecoder.Decode(&blockchain); err != nil {
t.Errorf("error decoding test blockchain")
}
blocks := make([]*dcrutil.Block, 0, len(blockchain))
for height := int64(1); height < int64(len(blockchain)); height++ {
block, err := dcrutil.NewBlockFromBytes(blockchain[height])
if err != nil {
t.Errorf("failed to parse block %v", height)
return nil, err
}
block.SetHeight(height - 1)
blocks = append(blocks, block)
}
savedBlocks = blocks
return blocks, nil
}