Example #1
0
// testBucketInterface ensures the bucket interface is working properly by
// exercising all of its functions.
func testBucketInterface(tc *testContext, bucket walletdb.Bucket) 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.Bucket(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.Bucket(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.Bucket(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
}