driver_test.go raw

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