// testPutValues stores all of the provided key/value pairs in the provided // bucket while checking for errors. func testPutValues(tc *testContext, bucket walletdb.ReadWriteBucket, values map[string]string) bool { for k, v := range values { var vBytes []byte if v != "" { vBytes = []byte(v) } if err := bucket.Put([]byte(k), vBytes); err != nil { tc.t.Errorf("Put: unexpected error: %v", err) return false } } return true }
// testBucketInterface ensures the bucket interface is working properly by // exercising all of its functions. func testBucketInterface(tc *testContext, bucket walletdb.ReadWriteBucket) bool { if bucket.Writable() != tc.isWritable { tc.t.Errorf("Bucket writable state does not match.") return false } if tc.isWritable { // keyValues holds the keys and values to use when putting // values into the bucket. var keyValues = map[string]string{ "bucketkey1": "foo1", "bucketkey2": "foo2", "bucketkey3": "foo3", } if !testPutValues(tc, bucket, keyValues) { return false } if !testGetValues(tc, bucket, keyValues) { return false } // Iterate all of the keys using ForEach while making sure the // stored values are the expected values. keysFound := make(map[string]struct{}, len(keyValues)) err := bucket.ForEach(func(k, v []byte) error { kString := string(k) wantV, ok := keyValues[kString] if !ok { return fmt.Errorf("ForEach: key '%s' should "+ "exist", kString) } if !reflect.DeepEqual(v, []byte(wantV)) { return fmt.Errorf("ForEach: value for key '%s' "+ "does not match - got %s, want %s", kString, v, wantV) } keysFound[kString] = struct{}{} return nil }) if err != nil { tc.t.Errorf("%v", err) return false } // Ensure all keys were iterated. for k := range keyValues { if _, ok := keysFound[k]; !ok { tc.t.Errorf("ForEach: key '%s' was not iterated "+ "when it should have been", k) return false } } // Delete the keys and ensure they were deleted. if !testDeleteValues(tc, bucket, keyValues) { return false } if !testGetValues(tc, bucket, rollbackValues(keyValues)) { return false } // Ensure creating a new bucket works as expected. testBucketName := []byte("testbucket") testBucket, err := bucket.CreateBucket(testBucketName) if err != nil { tc.t.Errorf("CreateBucket: unexpected error: %v", err) return false } if !testNestedBucket(tc, testBucket) { return false } // Ensure creating a bucket that already exists fails with the // expected error. wantErr := walletdb.ErrBucketExists if _, err := bucket.CreateBucket(testBucketName); err != wantErr { tc.t.Errorf("CreateBucket: unexpected error - got %v, "+ "want %v", err, wantErr) return false } // Ensure CreateBucketIfNotExists returns an existing bucket. testBucket, err = bucket.CreateBucketIfNotExists(testBucketName) if err != nil { tc.t.Errorf("CreateBucketIfNotExists: unexpected "+ "error: %v", err) return false } if !testNestedBucket(tc, testBucket) { return false } // Ensure retrieving and existing bucket works as expected. testBucket = bucket.ReadWriteBucket(testBucketName) if !testNestedBucket(tc, testBucket) { return false } // Ensure deleting a bucket works as intended. if err := bucket.DeleteBucket(testBucketName); err != nil { tc.t.Errorf("DeleteBucket: unexpected error: %v", err) return false } if b := bucket.ReadWriteBucket(testBucketName); b != nil { tc.t.Errorf("DeleteBucket: bucket '%s' still exists", testBucketName) return false } // Ensure deleting a bucket that doesn't exist returns the // expected error. wantErr = walletdb.ErrBucketNotFound if err := bucket.DeleteBucket(testBucketName); err != wantErr { tc.t.Errorf("DeleteBucket: unexpected error - got %v, "+ "want %v", err, wantErr) return false } // Ensure CreateBucketIfNotExists creates a new bucket when // it doesn't already exist. testBucket, err = bucket.CreateBucketIfNotExists(testBucketName) if err != nil { tc.t.Errorf("CreateBucketIfNotExists: unexpected "+ "error: %v", err) return false } if !testNestedBucket(tc, testBucket) { return false } // Delete the test bucket to avoid leaving it around for future // calls. if err := bucket.DeleteBucket(testBucketName); err != nil { tc.t.Errorf("DeleteBucket: unexpected error: %v", err) return false } if b := bucket.ReadWriteBucket(testBucketName); b != nil { tc.t.Errorf("DeleteBucket: bucket '%s' still exists", testBucketName) return false } } else { // Put should fail with bucket that is not writable. wantErr := walletdb.ErrTxNotWritable failBytes := []byte("fail") if err := bucket.Put(failBytes, failBytes); err != wantErr { tc.t.Errorf("Put did not fail with unwritable bucket") return false } // Delete should fail with bucket that is not writable. if err := bucket.Delete(failBytes); err != wantErr { tc.t.Errorf("Put did not fail with unwritable bucket") return false } // CreateBucket should fail with bucket that is not writable. if _, err := bucket.CreateBucket(failBytes); err != wantErr { tc.t.Errorf("CreateBucket did not fail with unwritable " + "bucket") return false } // CreateBucketIfNotExists should fail with bucket that is not // writable. if _, err := bucket.CreateBucketIfNotExists(failBytes); err != wantErr { tc.t.Errorf("CreateBucketIfNotExists did not fail with " + "unwritable bucket") return false } // DeleteBucket should fail with bucket that is not writable. if err := bucket.DeleteBucket(failBytes); err != wantErr { tc.t.Errorf("DeleteBucket did not fail with unwritable " + "bucket") return false } } return true }