github.com/decred/dcrlnd@v0.7.6/kvdb/readwrite_bucket_test.go (about)

     1  package kvdb
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"testing"
     7  
     8  	"github.com/btcsuite/btcwallet/walletdb"
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func testBucketCreation(t *testing.T, db walletdb.DB) {
    13  	err := Update(db, func(tx walletdb.ReadWriteTx) error {
    14  		// empty bucket name
    15  		b, err := tx.CreateTopLevelBucket(nil)
    16  		require.Error(t, walletdb.ErrBucketNameRequired, err)
    17  		require.Nil(t, b)
    18  
    19  		// empty bucket name
    20  		b, err = tx.CreateTopLevelBucket([]byte(""))
    21  		require.Error(t, walletdb.ErrBucketNameRequired, err)
    22  		require.Nil(t, b)
    23  
    24  		// "apple"
    25  		apple, err := tx.CreateTopLevelBucket([]byte("apple"))
    26  		require.NoError(t, err)
    27  		require.NotNil(t, apple)
    28  
    29  		// Check bucket tx.
    30  		require.Equal(t, tx, apple.Tx())
    31  
    32  		// "apple" already created
    33  		b, err = tx.CreateTopLevelBucket([]byte("apple"))
    34  		require.NoError(t, err)
    35  		require.NotNil(t, b)
    36  
    37  		// "apple/banana"
    38  		banana, err := apple.CreateBucket([]byte("banana"))
    39  		require.NoError(t, err)
    40  		require.NotNil(t, banana)
    41  
    42  		banana, err = apple.CreateBucketIfNotExists([]byte("banana"))
    43  		require.NoError(t, err)
    44  		require.NotNil(t, banana)
    45  
    46  		// Try creating "apple/banana" again
    47  		b, err = apple.CreateBucket([]byte("banana"))
    48  		require.Error(t, walletdb.ErrBucketExists, err)
    49  		require.Nil(t, b)
    50  
    51  		// "apple/mango"
    52  		mango, err := apple.CreateBucket([]byte("mango"))
    53  		require.Nil(t, err)
    54  		require.NotNil(t, mango)
    55  
    56  		// "apple/banana/pear"
    57  		pear, err := banana.CreateBucket([]byte("pear"))
    58  		require.Nil(t, err)
    59  		require.NotNil(t, pear)
    60  
    61  		// empty bucket
    62  		require.Nil(t, apple.NestedReadWriteBucket(nil))
    63  		require.Nil(t, apple.NestedReadWriteBucket([]byte("")))
    64  
    65  		// "apple/pear" doesn't exist
    66  		require.Nil(t, apple.NestedReadWriteBucket([]byte("pear")))
    67  
    68  		// "apple/banana" exits
    69  		require.NotNil(t, apple.NestedReadWriteBucket([]byte("banana")))
    70  		require.NotNil(t, apple.NestedReadBucket([]byte("banana")))
    71  		return nil
    72  	}, func() {})
    73  
    74  	require.Nil(t, err)
    75  }
    76  
    77  func testBucketDeletion(t *testing.T, db walletdb.DB) {
    78  	err := Update(db, func(tx walletdb.ReadWriteTx) error {
    79  		// "apple"
    80  		apple, err := tx.CreateTopLevelBucket([]byte("apple"))
    81  		require.Nil(t, err)
    82  		require.NotNil(t, apple)
    83  
    84  		// "apple/banana"
    85  		banana, err := apple.CreateBucket([]byte("banana"))
    86  		require.Nil(t, err)
    87  		require.NotNil(t, banana)
    88  
    89  		kvs := []KV{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}}
    90  
    91  		for _, kv := range kvs {
    92  			require.NoError(t, banana.Put([]byte(kv.key), []byte(kv.val)))
    93  			require.Equal(t, []byte(kv.val), banana.Get([]byte(kv.key)))
    94  		}
    95  
    96  		// Delete a k/v from "apple/banana"
    97  		require.NoError(t, banana.Delete([]byte("key2")))
    98  		// Try getting/putting/deleting invalid k/v's.
    99  		require.Nil(t, banana.Get(nil))
   100  		require.Error(t, walletdb.ErrKeyRequired, banana.Put(nil, []byte("val")))
   101  		require.Error(t, walletdb.ErrKeyRequired, banana.Delete(nil))
   102  
   103  		// Try deleting a k/v that doesn't exist.
   104  		require.NoError(t, banana.Delete([]byte("nokey")))
   105  
   106  		// "apple/pear"
   107  		pear, err := apple.CreateBucket([]byte("pear"))
   108  		require.Nil(t, err)
   109  		require.NotNil(t, pear)
   110  
   111  		// Put some values into "apple/pear"
   112  		for _, kv := range kvs {
   113  			require.Nil(t, pear.Put([]byte(kv.key), []byte(kv.val)))
   114  			require.Equal(t, []byte(kv.val), pear.Get([]byte(kv.key)))
   115  		}
   116  
   117  		// Create nested bucket "apple/pear/cherry"
   118  		cherry, err := pear.CreateBucket([]byte("cherry"))
   119  		require.Nil(t, err)
   120  		require.NotNil(t, cherry)
   121  
   122  		// Put some values into "apple/pear/cherry"
   123  		for _, kv := range kvs {
   124  			require.NoError(t, cherry.Put([]byte(kv.key), []byte(kv.val)))
   125  		}
   126  
   127  		// Read back values in "apple/pear/cherry" trough a read bucket.
   128  		cherryReadBucket := pear.NestedReadBucket([]byte("cherry"))
   129  		for _, kv := range kvs {
   130  			require.Equal(
   131  				t, []byte(kv.val),
   132  				cherryReadBucket.Get([]byte(kv.key)),
   133  			)
   134  		}
   135  
   136  		// Try deleting some invalid buckets.
   137  		require.Error(t,
   138  			walletdb.ErrBucketNameRequired, apple.DeleteNestedBucket(nil),
   139  		)
   140  
   141  		// Try deleting a non existing bucket.
   142  		require.Error(
   143  			t,
   144  			walletdb.ErrBucketNotFound,
   145  			apple.DeleteNestedBucket([]byte("missing")),
   146  		)
   147  
   148  		// Delete "apple/pear"
   149  		require.Nil(t, apple.DeleteNestedBucket([]byte("pear")))
   150  
   151  		// "apple/pear" deleted
   152  		require.Nil(t, apple.NestedReadWriteBucket([]byte("pear")))
   153  
   154  		// "aple/banana" exists
   155  		require.NotNil(t, apple.NestedReadWriteBucket([]byte("banana")))
   156  		return nil
   157  	}, func() {})
   158  
   159  	require.Nil(t, err)
   160  }
   161  
   162  type bucketIterator = func(walletdb.ReadWriteBucket,
   163  	func(key, val []byte) error) error
   164  
   165  func testBucketForEach(t *testing.T, db walletdb.DB) {
   166  	testBucketIterator(t, db, func(bucket walletdb.ReadWriteBucket,
   167  		callback func(key, val []byte) error) error {
   168  
   169  		return bucket.ForEach(callback)
   170  	})
   171  }
   172  
   173  func testBucketIterator(t *testing.T, db walletdb.DB,
   174  	iterator bucketIterator) {
   175  
   176  	err := Update(db, func(tx walletdb.ReadWriteTx) error {
   177  		// "apple"
   178  		apple, err := tx.CreateTopLevelBucket([]byte("apple"))
   179  		require.Nil(t, err)
   180  		require.NotNil(t, apple)
   181  
   182  		// "apple/banana"
   183  		banana, err := apple.CreateBucket([]byte("banana"))
   184  		require.Nil(t, err)
   185  		require.NotNil(t, banana)
   186  
   187  		kvs := []KV{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}}
   188  
   189  		// put some values into "apple" and "apple/banana" too
   190  		for _, kv := range kvs {
   191  			require.Nil(t, apple.Put([]byte(kv.key), []byte(kv.val)))
   192  			require.Equal(t, []byte(kv.val), apple.Get([]byte(kv.key)))
   193  
   194  			require.Nil(t, banana.Put([]byte(kv.key), []byte(kv.val)))
   195  			require.Equal(t, []byte(kv.val), banana.Get([]byte(kv.key)))
   196  		}
   197  
   198  		got := make(map[string]string)
   199  		err = apple.ForEach(func(key, val []byte) error {
   200  			got[string(key)] = string(val)
   201  			return nil
   202  		})
   203  
   204  		expected := map[string]string{
   205  			"key1":   "val1",
   206  			"key2":   "val2",
   207  			"key3":   "val3",
   208  			"banana": "",
   209  		}
   210  
   211  		require.NoError(t, err)
   212  		require.Equal(t, expected, got)
   213  
   214  		got = make(map[string]string)
   215  		err = iterator(banana, func(key, val []byte) error {
   216  			got[string(key)] = string(val)
   217  			return nil
   218  		})
   219  
   220  		require.NoError(t, err)
   221  		// remove the sub-bucket key
   222  		delete(expected, "banana")
   223  		require.Equal(t, expected, got)
   224  
   225  		return nil
   226  	}, func() {})
   227  
   228  	require.Nil(t, err)
   229  }
   230  
   231  func testBucketForEachWithError(t *testing.T, db walletdb.DB) {
   232  	err := Update(db, func(tx walletdb.ReadWriteTx) error {
   233  		// "apple"
   234  		apple, err := tx.CreateTopLevelBucket([]byte("apple"))
   235  		require.Nil(t, err)
   236  		require.NotNil(t, apple)
   237  
   238  		// "apple/banana"
   239  		banana, err := apple.CreateBucket([]byte("banana"))
   240  		require.Nil(t, err)
   241  		require.NotNil(t, banana)
   242  
   243  		// "apple/pear"
   244  		pear, err := apple.CreateBucket([]byte("pear"))
   245  		require.Nil(t, err)
   246  		require.NotNil(t, pear)
   247  
   248  		kvs := []KV{{"key1", "val1"}, {"key2", "val2"}}
   249  
   250  		// Put some values into "apple" and "apple/banana" too.
   251  		for _, kv := range kvs {
   252  			require.Nil(t, apple.Put([]byte(kv.key), []byte(kv.val)))
   253  			require.Equal(t, []byte(kv.val), apple.Get([]byte(kv.key)))
   254  		}
   255  
   256  		got := make(map[string]string)
   257  		i := 0
   258  		// Error while iterating value keys.
   259  		err = apple.ForEach(func(key, val []byte) error {
   260  			if i == 2 {
   261  				return fmt.Errorf("error")
   262  			}
   263  
   264  			got[string(key)] = string(val)
   265  			i++
   266  			return nil
   267  		})
   268  
   269  		expected := map[string]string{
   270  			"banana": "",
   271  			"key1":   "val1",
   272  		}
   273  
   274  		require.Equal(t, expected, got)
   275  		require.Error(t, err)
   276  
   277  		got = make(map[string]string)
   278  		i = 0
   279  		// Erro while iterating buckets.
   280  		err = apple.ForEach(func(key, val []byte) error {
   281  			if i == 3 {
   282  				return fmt.Errorf("error")
   283  			}
   284  
   285  			got[string(key)] = string(val)
   286  			i++
   287  			return nil
   288  		})
   289  
   290  		expected = map[string]string{
   291  			"banana": "",
   292  			"key1":   "val1",
   293  			"key2":   "val2",
   294  		}
   295  
   296  		require.Equal(t, expected, got)
   297  		require.Error(t, err)
   298  		return nil
   299  	}, func() {})
   300  
   301  	require.Nil(t, err)
   302  }
   303  
   304  func testBucketSequence(t *testing.T, db walletdb.DB) {
   305  	err := Update(db, func(tx walletdb.ReadWriteTx) error {
   306  		apple, err := tx.CreateTopLevelBucket([]byte("apple"))
   307  		require.Nil(t, err)
   308  		require.NotNil(t, apple)
   309  
   310  		banana, err := apple.CreateBucket([]byte("banana"))
   311  		require.Nil(t, err)
   312  		require.NotNil(t, banana)
   313  
   314  		require.Equal(t, uint64(0), apple.Sequence())
   315  		require.Equal(t, uint64(0), banana.Sequence())
   316  
   317  		require.Nil(t, apple.SetSequence(math.MaxUint64))
   318  		require.Equal(t, uint64(math.MaxUint64), apple.Sequence())
   319  
   320  		for i := uint64(0); i < uint64(5); i++ {
   321  			s, err := apple.NextSequence()
   322  			require.Nil(t, err)
   323  			require.Equal(t, i, s)
   324  		}
   325  
   326  		return nil
   327  	}, func() {})
   328  
   329  	require.Nil(t, err)
   330  }
   331  
   332  // TestKeyClash tests that one cannot create a bucket if a value with the same
   333  // key exists and the same is true in reverse: that a value cannot be put if
   334  // a bucket with the same key exists.
   335  func testKeyClash(t *testing.T, db walletdb.DB) {
   336  	// First:
   337  	// put: /apple/key -> val
   338  	// create bucket: /apple/banana
   339  	err := Update(db, func(tx walletdb.ReadWriteTx) error {
   340  		apple, err := tx.CreateTopLevelBucket([]byte("apple"))
   341  		require.Nil(t, err)
   342  		require.NotNil(t, apple)
   343  
   344  		require.NoError(t, apple.Put([]byte("key"), []byte("val")))
   345  
   346  		banana, err := apple.CreateBucket([]byte("banana"))
   347  		require.Nil(t, err)
   348  		require.NotNil(t, banana)
   349  
   350  		return nil
   351  	}, func() {})
   352  
   353  	require.Nil(t, err)
   354  
   355  	// Next try to:
   356  	// put: /apple/banana -> val => will fail (as /apple/banana is a bucket)
   357  	// create bucket: /apple/key => will fail (as /apple/key is a value)
   358  	err = Update(db, func(tx walletdb.ReadWriteTx) error {
   359  		apple, err := tx.CreateTopLevelBucket([]byte("apple"))
   360  		require.Nil(t, err)
   361  		require.NotNil(t, apple)
   362  
   363  		require.Error(t,
   364  			walletdb.ErrIncompatibleValue,
   365  			apple.Put([]byte("banana"), []byte("val")),
   366  		)
   367  
   368  		b, err := apple.CreateBucket([]byte("key"))
   369  		require.Nil(t, b)
   370  		require.Error(t, walletdb.ErrIncompatibleValue, err)
   371  
   372  		b, err = apple.CreateBucketIfNotExists([]byte("key"))
   373  		require.Nil(t, b)
   374  		require.Error(t, walletdb.ErrIncompatibleValue, err)
   375  
   376  		return nil
   377  	}, func() {})
   378  
   379  	require.Nil(t, err)
   380  }
   381  
   382  // TestBucketCreateDelete tests that creating then deleting then creating a
   383  // bucket suceeds.
   384  func testBucketCreateDelete(t *testing.T, db walletdb.DB) {
   385  	err := Update(db, func(tx walletdb.ReadWriteTx) error {
   386  		apple, err := tx.CreateTopLevelBucket([]byte("apple"))
   387  		require.NoError(t, err)
   388  		require.NotNil(t, apple)
   389  
   390  		banana, err := apple.CreateBucket([]byte("banana"))
   391  		require.NoError(t, err)
   392  		require.NotNil(t, banana)
   393  
   394  		return nil
   395  	}, func() {})
   396  	require.NoError(t, err)
   397  
   398  	err = Update(db, func(tx walletdb.ReadWriteTx) error {
   399  		apple := tx.ReadWriteBucket([]byte("apple"))
   400  		require.NotNil(t, apple)
   401  		require.NoError(t, apple.DeleteNestedBucket([]byte("banana")))
   402  
   403  		return nil
   404  	}, func() {})
   405  	require.NoError(t, err)
   406  
   407  	err = Update(db, func(tx walletdb.ReadWriteTx) error {
   408  		apple := tx.ReadWriteBucket([]byte("apple"))
   409  		require.NotNil(t, apple)
   410  		require.NoError(t, apple.Put([]byte("banana"), []byte("value")))
   411  
   412  		return nil
   413  	}, func() {})
   414  	require.NoError(t, err)
   415  }
   416  
   417  //nolint:unused
   418  func testTopLevelBucketCreation(t *testing.T, db walletdb.DB) {
   419  	require.NoError(t, Update(db, func(tx walletdb.ReadWriteTx) error {
   420  		// Try to delete all data (there is none).
   421  		err := tx.DeleteTopLevelBucket([]byte("top"))
   422  		require.ErrorIs(t, walletdb.ErrBucketNotFound, err)
   423  
   424  		// Create top level bucket.
   425  		top, err := tx.CreateTopLevelBucket([]byte("top"))
   426  		require.NoError(t, err)
   427  		require.NotNil(t, top)
   428  
   429  		// Create second top level bucket with special characters.
   430  		top2, err := tx.CreateTopLevelBucket([]byte{1, 2, 3})
   431  		require.NoError(t, err)
   432  		require.NotNil(t, top2)
   433  
   434  		top2 = tx.ReadWriteBucket([]byte{1, 2, 3})
   435  		require.NotNil(t, top2)
   436  
   437  		// List top level buckets.
   438  		var tlKeys [][]byte
   439  		require.NoError(t, tx.ForEachBucket(func(k []byte) error {
   440  			tlKeys = append(tlKeys, k)
   441  			return nil
   442  		}))
   443  		require.Equal(t, [][]byte{{1, 2, 3}, []byte("top")}, tlKeys)
   444  
   445  		// Create third top level bucket with special uppercase.
   446  		top3, err := tx.CreateTopLevelBucket([]byte("UpperBucket"))
   447  		require.NoError(t, err)
   448  		require.NotNil(t, top3)
   449  
   450  		top3 = tx.ReadWriteBucket([]byte("UpperBucket"))
   451  		require.NotNil(t, top3)
   452  
   453  		require.NoError(t, tx.DeleteTopLevelBucket([]byte("top")))
   454  		require.NoError(t, tx.DeleteTopLevelBucket([]byte{1, 2, 3}))
   455  		require.NoError(t, tx.DeleteTopLevelBucket([]byte("UpperBucket")))
   456  
   457  		tx.ForEachBucket(func(k []byte) error {
   458  			require.Fail(t, "no top level buckets expected")
   459  			return nil
   460  		})
   461  
   462  		return nil
   463  	}, func() {}))
   464  }
   465  
   466  //nolint:unused
   467  func testBucketOperations(t *testing.T, db walletdb.DB) {
   468  	require.NoError(t, Update(db, func(tx walletdb.ReadWriteTx) error {
   469  		// Create top level bucket.
   470  		top, err := tx.CreateTopLevelBucket([]byte("top"))
   471  		require.NoError(t, err)
   472  		require.NotNil(t, top)
   473  
   474  		// Assert that key doesn't exist.
   475  		require.Nil(t, top.Get([]byte("key")))
   476  
   477  		require.NoError(t, top.ForEach(func(k, v []byte) error {
   478  			require.Fail(t, "unexpected data")
   479  			return nil
   480  		}))
   481  
   482  		// Put key.
   483  		require.NoError(t, top.Put([]byte("key"), []byte("val")))
   484  		require.Equal(t, []byte("val"), top.Get([]byte("key")))
   485  
   486  		// Overwrite key.
   487  		require.NoError(t, top.Put([]byte("key"), []byte("val2")))
   488  		require.Equal(t, []byte("val2"), top.Get([]byte("key")))
   489  
   490  		// Put nil value.
   491  		require.NoError(t, top.Put([]byte("nilkey"), nil))
   492  		require.Equal(t, []byte(""), top.Get([]byte("nilkey")))
   493  
   494  		// Put empty value.
   495  		require.NoError(t, top.Put([]byte("nilkey"), []byte{}))
   496  		require.Equal(t, []byte(""), top.Get([]byte("nilkey")))
   497  
   498  		// Try to create bucket with same name as previous key.
   499  		_, err = top.CreateBucket([]byte("key"))
   500  		require.ErrorIs(t, err, walletdb.ErrIncompatibleValue)
   501  
   502  		_, err = top.CreateBucketIfNotExists([]byte("key"))
   503  		require.ErrorIs(t, err, walletdb.ErrIncompatibleValue)
   504  
   505  		// Create sub-bucket.
   506  		sub2, err := top.CreateBucket([]byte("sub2"))
   507  		require.NoError(t, err)
   508  		require.NotNil(t, sub2)
   509  
   510  		// Assert that re-creating the bucket fails.
   511  		_, err = top.CreateBucket([]byte("sub2"))
   512  		require.ErrorIs(t, err, walletdb.ErrBucketExists)
   513  
   514  		// Assert that create-if-not-exists succeeds.
   515  		_, err = top.CreateBucketIfNotExists([]byte("sub2"))
   516  		require.NoError(t, err)
   517  
   518  		// Assert that fetching the bucket succeeds.
   519  		sub2 = top.NestedReadWriteBucket([]byte("sub2"))
   520  		require.NotNil(t, sub2)
   521  
   522  		// Try to put key with same name as bucket.
   523  		require.ErrorIs(t, top.Put([]byte("sub2"), []byte("val")), walletdb.ErrIncompatibleValue)
   524  
   525  		// Put key into sub bucket.
   526  		require.NoError(t, sub2.Put([]byte("subkey"), []byte("subval")))
   527  		require.Equal(t, []byte("subval"), sub2.Get([]byte("subkey")))
   528  
   529  		// Overwrite key in sub bucket.
   530  		require.NoError(t, sub2.Put([]byte("subkey"), []byte("subval2")))
   531  		require.Equal(t, []byte("subval2"), sub2.Get([]byte("subkey")))
   532  
   533  		// Check for each result.
   534  		kvs := make(map[string][]byte)
   535  		require.NoError(t, top.ForEach(func(k, v []byte) error {
   536  			kvs[string(k)] = v
   537  			return nil
   538  		}))
   539  		require.Equal(t, map[string][]byte{
   540  			"key":    []byte("val2"),
   541  			"nilkey": []byte(""),
   542  			"sub2":   nil,
   543  		}, kvs)
   544  
   545  		// Delete key.
   546  		require.NoError(t, top.Delete([]byte("key")))
   547  
   548  		// Delete non-existent key.
   549  		require.NoError(t, top.Delete([]byte("keynonexistent")))
   550  
   551  		// Test cursor.
   552  		cursor := top.ReadWriteCursor()
   553  		k, v := cursor.First()
   554  		require.Equal(t, []byte("nilkey"), k)
   555  		require.Equal(t, []byte(""), v)
   556  
   557  		k, v = cursor.Last()
   558  		require.Equal(t, []byte("sub2"), k)
   559  		require.Nil(t, v)
   560  
   561  		k, v = cursor.Prev()
   562  		require.Equal(t, []byte("nilkey"), k)
   563  		require.Equal(t, []byte(""), v)
   564  
   565  		k, v = cursor.Prev()
   566  		require.Nil(t, k)
   567  		require.Nil(t, v)
   568  
   569  		k, v = cursor.Next()
   570  		require.Equal(t, []byte("sub2"), k)
   571  		require.Nil(t, v)
   572  
   573  		k, v = cursor.Next()
   574  		require.Nil(t, k)
   575  		require.Nil(t, v)
   576  
   577  		k, v = cursor.Seek([]byte("nilkey"))
   578  		require.Equal(t, []byte("nilkey"), k)
   579  		require.Equal(t, []byte(""), v)
   580  
   581  		require.NoError(t, sub2.Put([]byte("k1"), []byte("v1")))
   582  		require.NoError(t, sub2.Put([]byte("k2"), []byte("v2")))
   583  		require.NoError(t, sub2.Put([]byte("k3"), []byte("v3")))
   584  
   585  		cursor = sub2.ReadWriteCursor()
   586  		cursor.First()
   587  		for i := 0; i < 4; i++ {
   588  			require.NoError(t, cursor.Delete())
   589  		}
   590  		require.NoError(t, sub2.ForEach(func(k, v []byte) error {
   591  			require.Fail(t, "unexpected data")
   592  			return nil
   593  		}))
   594  
   595  		_, err = sub2.CreateBucket([]byte("sub3"))
   596  		require.NoError(t, err)
   597  		require.ErrorIs(t, cursor.Delete(), walletdb.ErrIncompatibleValue)
   598  
   599  		//Try to delete all data.
   600  		require.NoError(t, tx.DeleteTopLevelBucket([]byte("top")))
   601  		require.Nil(t, tx.ReadBucket([]byte("top")))
   602  
   603  		return nil
   604  	}, func() {}))
   605  }
   606  
   607  //nolint:unused
   608  func testSubBucketSequence(t *testing.T, db walletdb.DB) {
   609  	require.NoError(t, Update(db, func(tx walletdb.ReadWriteTx) error {
   610  		// Create top level bucket.
   611  		top, err := tx.CreateTopLevelBucket([]byte("top"))
   612  		require.NoError(t, err)
   613  		require.NotNil(t, top)
   614  
   615  		// Create sub-bucket.
   616  		sub2, err := top.CreateBucket([]byte("sub2"))
   617  		require.NoError(t, err)
   618  		require.NotNil(t, sub2)
   619  
   620  		// Test sequence.
   621  		require.Equal(t, uint64(0), top.Sequence())
   622  
   623  		require.NoError(t, top.SetSequence(100))
   624  		require.Equal(t, uint64(100), top.Sequence())
   625  
   626  		require.NoError(t, top.SetSequence(101))
   627  		require.Equal(t, uint64(101), top.Sequence())
   628  
   629  		next, err := top.NextSequence()
   630  		require.NoError(t, err)
   631  		require.Equal(t, uint64(102), next)
   632  
   633  		next, err = sub2.NextSequence()
   634  		require.NoError(t, err)
   635  		require.Equal(t, uint64(1), next)
   636  
   637  		return nil
   638  	}, func() {}))
   639  }