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