github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/database/ffldb/driver_test.go (about)

     1  // Copyright (c) 2015-2016 The btcsuite developers
     2  // Copyright (c) 2016 The Dash developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package ffldb_test
     7  
     8  import (
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  	"reflect"
    13  	"runtime"
    14  	"testing"
    15  
    16  	"github.com/BlockABC/godash/chaincfg"
    17  	"github.com/BlockABC/godash/database"
    18  	"github.com/BlockABC/godash/database/ffldb"
    19  	"github.com/BlockABC/godashutil"
    20  )
    21  
    22  // dbType is the database type name for this driver.
    23  const dbType = "ffldb"
    24  
    25  // TestCreateOpenFail ensures that errors related to creating and opening a
    26  // database are handled properly.
    27  func TestCreateOpenFail(t *testing.T) {
    28  	t.Parallel()
    29  
    30  	// Ensure that attempting to open a database that doesn't exist returns
    31  	// the expected error.
    32  	wantErrCode := database.ErrDbDoesNotExist
    33  	_, err := database.Open(dbType, "noexist", blockDataNet)
    34  	if !checkDbError(t, "Open", err, wantErrCode) {
    35  		return
    36  	}
    37  
    38  	// Ensure that attempting to open a database with the wrong number of
    39  	// parameters returns the expected error.
    40  	wantErr := fmt.Errorf("invalid arguments to %s.Open -- expected "+
    41  		"database path and block network", dbType)
    42  	_, err = database.Open(dbType, 1, 2, 3)
    43  	if err.Error() != wantErr.Error() {
    44  		t.Errorf("Open: did not receive expected error - got %v, "+
    45  			"want %v", err, wantErr)
    46  		return
    47  	}
    48  
    49  	// Ensure that attempting to open a database with an invalid type for
    50  	// the first parameter returns the expected error.
    51  	wantErr = fmt.Errorf("first argument to %s.Open is invalid -- "+
    52  		"expected database path string", dbType)
    53  	_, err = database.Open(dbType, 1, blockDataNet)
    54  	if err.Error() != wantErr.Error() {
    55  		t.Errorf("Open: did not receive expected error - got %v, "+
    56  			"want %v", err, wantErr)
    57  		return
    58  	}
    59  
    60  	// Ensure that attempting to open a database with an invalid type for
    61  	// the second parameter returns the expected error.
    62  	wantErr = fmt.Errorf("second argument to %s.Open is invalid -- "+
    63  		"expected block network", dbType)
    64  	_, err = database.Open(dbType, "noexist", "invalid")
    65  	if err.Error() != wantErr.Error() {
    66  		t.Errorf("Open: did not receive expected error - got %v, "+
    67  			"want %v", err, wantErr)
    68  		return
    69  	}
    70  
    71  	// Ensure that attempting to create a database with the wrong number of
    72  	// parameters returns the expected error.
    73  	wantErr = fmt.Errorf("invalid arguments to %s.Create -- expected "+
    74  		"database path and block network", dbType)
    75  	_, err = database.Create(dbType, 1, 2, 3)
    76  	if err.Error() != wantErr.Error() {
    77  		t.Errorf("Create: did not receive expected error - got %v, "+
    78  			"want %v", err, wantErr)
    79  		return
    80  	}
    81  
    82  	// Ensure that attempting to create a database with an invalid type for
    83  	// the first parameter returns the expected error.
    84  	wantErr = fmt.Errorf("first argument to %s.Create is invalid -- "+
    85  		"expected database path string", dbType)
    86  	_, err = database.Create(dbType, 1, blockDataNet)
    87  	if err.Error() != wantErr.Error() {
    88  		t.Errorf("Create: did not receive expected error - got %v, "+
    89  			"want %v", err, wantErr)
    90  		return
    91  	}
    92  
    93  	// Ensure that attempting to create a database with an invalid type for
    94  	// the second parameter returns the expected error.
    95  	wantErr = fmt.Errorf("second argument to %s.Create is invalid -- "+
    96  		"expected block network", dbType)
    97  	_, err = database.Create(dbType, "noexist", "invalid")
    98  	if err.Error() != wantErr.Error() {
    99  		t.Errorf("Create: did not receive expected error - got %v, "+
   100  			"want %v", err, wantErr)
   101  		return
   102  	}
   103  
   104  	// Ensure operations against a closed database return the expected
   105  	// error.
   106  	dbPath := filepath.Join(os.TempDir(), "ffldb-createfail")
   107  	_ = os.RemoveAll(dbPath)
   108  	db, err := database.Create(dbType, dbPath, blockDataNet)
   109  	if err != nil {
   110  		t.Errorf("Create: unexpected error: %v", err)
   111  		return
   112  	}
   113  	defer os.RemoveAll(dbPath)
   114  	db.Close()
   115  
   116  	wantErrCode = database.ErrDbNotOpen
   117  	err = db.View(func(tx database.Tx) error {
   118  		return nil
   119  	})
   120  	if !checkDbError(t, "View", err, wantErrCode) {
   121  		return
   122  	}
   123  
   124  	wantErrCode = database.ErrDbNotOpen
   125  	err = db.Update(func(tx database.Tx) error {
   126  		return nil
   127  	})
   128  	if !checkDbError(t, "Update", err, wantErrCode) {
   129  		return
   130  	}
   131  
   132  	wantErrCode = database.ErrDbNotOpen
   133  	_, err = db.Begin(false)
   134  	if !checkDbError(t, "Begin(false)", err, wantErrCode) {
   135  		return
   136  	}
   137  
   138  	wantErrCode = database.ErrDbNotOpen
   139  	_, err = db.Begin(true)
   140  	if !checkDbError(t, "Begin(true)", err, wantErrCode) {
   141  		return
   142  	}
   143  
   144  	wantErrCode = database.ErrDbNotOpen
   145  	err = db.Close()
   146  	if !checkDbError(t, "Close", err, wantErrCode) {
   147  		return
   148  	}
   149  }
   150  
   151  // TestPersistence ensures that values stored are still valid after closing and
   152  // reopening the database.
   153  func TestPersistence(t *testing.T) {
   154  	t.Parallel()
   155  
   156  	// Create a new database to run tests against.
   157  	dbPath := filepath.Join(os.TempDir(), "ffldb-persistencetest")
   158  	_ = os.RemoveAll(dbPath)
   159  	db, err := database.Create(dbType, dbPath, blockDataNet)
   160  	if err != nil {
   161  		t.Errorf("Failed to create test database (%s) %v", dbType, err)
   162  		return
   163  	}
   164  	defer os.RemoveAll(dbPath)
   165  	defer db.Close()
   166  
   167  	// Create a bucket, put some values into it, and store a block so they
   168  	// can be tested for existence on re-open.
   169  	bucket1Key := []byte("bucket1")
   170  	storeValues := map[string]string{
   171  		"b1key1": "foo1",
   172  		"b1key2": "foo2",
   173  		"b1key3": "foo3",
   174  	}
   175  	genesisBlock := godashutil.NewBlock(chaincfg.MainNetParams.GenesisBlock)
   176  	genesisHash := chaincfg.MainNetParams.GenesisHash
   177  	err = db.Update(func(tx database.Tx) error {
   178  		metadataBucket := tx.Metadata()
   179  		if metadataBucket == nil {
   180  			return fmt.Errorf("Metadata: unexpected nil bucket")
   181  		}
   182  
   183  		bucket1, err := metadataBucket.CreateBucket(bucket1Key)
   184  		if err != nil {
   185  			return fmt.Errorf("CreateBucket: unexpected error: %v",
   186  				err)
   187  		}
   188  
   189  		for k, v := range storeValues {
   190  			err := bucket1.Put([]byte(k), []byte(v))
   191  			if err != nil {
   192  				return fmt.Errorf("Put: unexpected error: %v",
   193  					err)
   194  			}
   195  		}
   196  
   197  		if err := tx.StoreBlock(genesisBlock); err != nil {
   198  			return fmt.Errorf("StoreBlock: unexpected error: %v",
   199  				err)
   200  		}
   201  
   202  		return nil
   203  	})
   204  	if err != nil {
   205  		t.Errorf("Update: unexpected error: %v", err)
   206  		return
   207  	}
   208  
   209  	// Close and reopen the database to ensure the values persist.
   210  	db.Close()
   211  	db, err = database.Open(dbType, dbPath, blockDataNet)
   212  	if err != nil {
   213  		t.Errorf("Failed to open test database (%s) %v", dbType, err)
   214  		return
   215  	}
   216  	defer db.Close()
   217  
   218  	// Ensure the values previously stored in the 3rd namespace still exist
   219  	// and are correct.
   220  	err = db.View(func(tx database.Tx) error {
   221  		metadataBucket := tx.Metadata()
   222  		if metadataBucket == nil {
   223  			return fmt.Errorf("Metadata: unexpected nil bucket")
   224  		}
   225  
   226  		bucket1 := metadataBucket.Bucket(bucket1Key)
   227  		if bucket1 == nil {
   228  			return fmt.Errorf("Bucket1: unexpected nil bucket")
   229  		}
   230  
   231  		for k, v := range storeValues {
   232  			gotVal := bucket1.Get([]byte(k))
   233  			if !reflect.DeepEqual(gotVal, []byte(v)) {
   234  				return fmt.Errorf("Get: key '%s' does not "+
   235  					"match expected value - got %s, want %s",
   236  					k, gotVal, v)
   237  			}
   238  		}
   239  
   240  		genesisBlockBytes, _ := genesisBlock.Bytes()
   241  		gotBytes, err := tx.FetchBlock(genesisHash)
   242  		if err != nil {
   243  			return fmt.Errorf("FetchBlock: unexpected error: %v",
   244  				err)
   245  		}
   246  		if !reflect.DeepEqual(gotBytes, genesisBlockBytes) {
   247  			return fmt.Errorf("FetchBlock: stored block mismatch")
   248  		}
   249  
   250  		return nil
   251  	})
   252  	if err != nil {
   253  		t.Errorf("View: unexpected error: %v", err)
   254  		return
   255  	}
   256  }
   257  
   258  // TestInterface performs all interfaces tests for this database driver.
   259  func TestInterface(t *testing.T) {
   260  	t.Parallel()
   261  
   262  	// Create a new database to run tests against.
   263  	dbPath := filepath.Join(os.TempDir(), "ffldb-interfacetest")
   264  	_ = os.RemoveAll(dbPath)
   265  	db, err := database.Create(dbType, dbPath, blockDataNet)
   266  	if err != nil {
   267  		t.Errorf("Failed to create test database (%s) %v", dbType, err)
   268  		return
   269  	}
   270  	defer os.RemoveAll(dbPath)
   271  	defer db.Close()
   272  
   273  	// Ensure the driver type is the expected value.
   274  	gotDbType := db.Type()
   275  	if gotDbType != dbType {
   276  		t.Errorf("Type: unepxected driver type - got %v, want %v",
   277  			gotDbType, dbType)
   278  		return
   279  	}
   280  
   281  	// Run all of the interface tests against the database.
   282  	runtime.GOMAXPROCS(runtime.NumCPU())
   283  
   284  	// Change the maximum file size to a small value to force multiple flat
   285  	// files with the test data set.
   286  	ffldb.TstRunWithMaxBlockFileSize(db, 2048, func() {
   287  		testInterface(t, db)
   288  	})
   289  }