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 }