From 3c6d35ec4182d4a2fc569264446f03c5591c0452 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Tue, 6 Jul 2021 16:31:24 +0200 Subject: [PATCH 1/4] kvdb/test: generalize etcd tests --- kvdb/etcd/bucket.go | 39 ++++++ kvdb/etcd/bucket_test.go | 42 ------ kvdb/etcd/db_test.go | 4 +- kvdb/etcd/{fixture_test.go => fixture.go} | 9 ++ kvdb/etcd/readwrite_tx_test.go | 78 +---------- kvdb/etcd_test.go | 154 ++++++++++++++++++++++ kvdb/{etcd => }/readwrite_bucket_test.go | 149 +++------------------ kvdb/{etcd => }/readwrite_cursor_test.go | 82 +++--------- kvdb/readwrite_tx_test.go | 49 +++++++ kvdb/test.go | 14 ++ 10 files changed, 307 insertions(+), 313 deletions(-) delete mode 100644 kvdb/etcd/bucket_test.go rename kvdb/etcd/{fixture_test.go => fixture.go} (93%) create mode 100644 kvdb/etcd_test.go rename kvdb/{etcd => }/readwrite_bucket_test.go (72%) rename kvdb/{etcd => }/readwrite_cursor_test.go (77%) create mode 100644 kvdb/readwrite_tx_test.go create mode 100644 kvdb/test.go diff --git a/kvdb/etcd/bucket.go b/kvdb/etcd/bucket.go index 8a1ff071..514eab63 100644 --- a/kvdb/etcd/bucket.go +++ b/kvdb/etcd/bucket.go @@ -90,3 +90,42 @@ func getKeyVal(kv *KV) ([]byte, []byte) { return getKey(kv.key), val } + +// BucketKey is a helper functon used in tests to create a bucket key from +// passed bucket list. +func BucketKey(buckets ...string) string { + var bucketKey []byte + + rootID := makeBucketID([]byte(etcdDefaultRootBucketId)) + parent := rootID[:] + + for _, bucketName := range buckets { + bucketKey = makeBucketKey(parent, []byte(bucketName)) + id := makeBucketID(bucketKey) + parent = id[:] + } + + return string(bucketKey) +} + +// BucketVal is a helper function used in tests to create a bucket value (the +// value for a bucket key) from the passed bucket list. +func BucketVal(buckets ...string) string { + id := makeBucketID([]byte(BucketKey(buckets...))) + return string(id[:]) +} + +// ValueKey is a helper function used in tests to create a value key from the +// passed key and bucket list. +func ValueKey(key string, buckets ...string) string { + rootID := makeBucketID([]byte(etcdDefaultRootBucketId)) + bucket := rootID[:] + + for _, bucketName := range buckets { + bucketKey := makeBucketKey(bucket, []byte(bucketName)) + id := makeBucketID(bucketKey) + bucket = id[:] + } + + return string(makeValueKey(bucket, []byte(key))) +} diff --git a/kvdb/etcd/bucket_test.go b/kvdb/etcd/bucket_test.go deleted file mode 100644 index 6a97a9b8..00000000 --- a/kvdb/etcd/bucket_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// +build kvdb_etcd - -package etcd - -// bkey is a helper functon used in tests to create a bucket key from passed -// bucket list. -func bkey(buckets ...string) string { - var bucketKey []byte - - rootID := makeBucketID([]byte(etcdDefaultRootBucketId)) - parent := rootID[:] - - for _, bucketName := range buckets { - bucketKey = makeBucketKey(parent, []byte(bucketName)) - id := makeBucketID(bucketKey) - parent = id[:] - } - - return string(bucketKey) -} - -// bval is a helper function used in tests to create a bucket value (the value -// for a bucket key) from the passed bucket list. -func bval(buckets ...string) string { - id := makeBucketID([]byte(bkey(buckets...))) - return string(id[:]) -} - -// vkey is a helper function used in tests to create a value key from the -// passed key and bucket list. -func vkey(key string, buckets ...string) string { - rootID := makeBucketID([]byte(etcdDefaultRootBucketId)) - bucket := rootID[:] - - for _, bucketName := range buckets { - bucketKey := makeBucketKey(bucket, []byte(bucketName)) - id := makeBucketID(bucketKey) - bucket = id[:] - } - - return string(makeValueKey(bucket, []byte(key))) -} diff --git a/kvdb/etcd/db_test.go b/kvdb/etcd/db_test.go index 7d0c10be..357c4ed5 100644 --- a/kvdb/etcd/db_test.go +++ b/kvdb/etcd/db_test.go @@ -38,8 +38,8 @@ func TestCopy(t *testing.T) { require.Nil(t, err) expected := map[string]string{ - bkey("apple"): bval("apple"), - vkey("key", "apple"): "val", + BucketKey("apple"): BucketVal("apple"), + ValueKey("key", "apple"): "val", } require.Equal(t, expected, f.Dump()) } diff --git a/kvdb/etcd/fixture_test.go b/kvdb/etcd/fixture.go similarity index 93% rename from kvdb/etcd/fixture_test.go rename to kvdb/etcd/fixture.go index 377e8473..01781b7b 100644 --- a/kvdb/etcd/fixture_test.go +++ b/kvdb/etcd/fixture.go @@ -9,6 +9,8 @@ import ( "testing" "time" + "github.com/btcsuite/btcwallet/walletdb" + "github.com/stretchr/testify/require" "go.etcd.io/etcd/clientv3" "go.etcd.io/etcd/clientv3/namespace" ) @@ -76,6 +78,13 @@ func NewEtcdTestFixture(t *testing.T) *EtcdTestFixture { } } +func (f *EtcdTestFixture) NewBackend() walletdb.DB { + db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) + require.NoError(f.t, err) + + return db +} + // Put puts a string key/value into the test etcd database. func (f *EtcdTestFixture) Put(key, value string) { ctx, cancel := context.WithTimeout(context.TODO(), testEtcdTimeout) diff --git a/kvdb/etcd/readwrite_tx_test.go b/kvdb/etcd/readwrite_tx_test.go index 7e8c92c6..c640493e 100644 --- a/kvdb/etcd/readwrite_tx_test.go +++ b/kvdb/etcd/readwrite_tx_test.go @@ -10,70 +10,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestTxManualCommit(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) - - tx, err := db.BeginReadWriteTx() - require.NoError(t, err) - require.NotNil(t, tx) - - committed := false - - tx.OnCommit(func() { - committed = true - }) - - apple, err := tx.CreateTopLevelBucket([]byte("apple")) - require.NoError(t, err) - require.NotNil(t, apple) - require.NoError(t, apple.Put([]byte("testKey"), []byte("testVal"))) - - banana, err := tx.CreateTopLevelBucket([]byte("banana")) - require.NoError(t, err) - require.NotNil(t, banana) - require.NoError(t, banana.Put([]byte("testKey"), []byte("testVal"))) - require.NoError(t, tx.DeleteTopLevelBucket([]byte("banana"))) - - require.NoError(t, tx.Commit()) - require.True(t, committed) - - expected := map[string]string{ - bkey("apple"): bval("apple"), - vkey("testKey", "apple"): "testVal", - } - require.Equal(t, expected, f.Dump()) -} - -func TestTxRollback(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) - - tx, err := db.BeginReadWriteTx() - require.Nil(t, err) - require.NotNil(t, tx) - - apple, err := tx.CreateTopLevelBucket([]byte("apple")) - require.Nil(t, err) - require.NotNil(t, apple) - - require.NoError(t, apple.Put([]byte("testKey"), []byte("testVal"))) - - require.NoError(t, tx.Rollback()) - require.Error(t, walletdb.ErrTxClosed, tx.Commit()) - require.Equal(t, map[string]string{}, f.Dump()) -} - func TestChangeDuringManualTx(t *testing.T) { t.Parallel() @@ -94,12 +30,12 @@ func TestChangeDuringManualTx(t *testing.T) { require.NoError(t, apple.Put([]byte("testKey"), []byte("testVal"))) // Try overwriting the bucket key. - f.Put(bkey("apple"), "banana") + f.Put(BucketKey("apple"), "banana") // TODO: translate error require.NotNil(t, tx.Commit()) require.Equal(t, map[string]string{ - bkey("apple"): "banana", + BucketKey("apple"): "banana", }, f.Dump()) } @@ -122,8 +58,8 @@ func TestChangeDuringUpdate(t *testing.T) { require.NoError(t, apple.Put([]byte("key"), []byte("value"))) if count == 0 { - f.Put(vkey("key", "apple"), "new_value") - f.Put(vkey("key2", "apple"), "value2") + f.Put(ValueKey("key", "apple"), "new_value") + f.Put(ValueKey("key2", "apple"), "value2") } cursor := apple.ReadCursor() @@ -149,9 +85,9 @@ func TestChangeDuringUpdate(t *testing.T) { require.Equal(t, count, 2) expected := map[string]string{ - bkey("apple"): bval("apple"), - vkey("key", "apple"): "value", - vkey("key2", "apple"): "value2", + BucketKey("apple"): BucketVal("apple"), + ValueKey("key", "apple"): "value", + ValueKey("key2", "apple"): "value2", } require.Equal(t, expected, f.Dump()) } diff --git a/kvdb/etcd_test.go b/kvdb/etcd_test.go new file mode 100644 index 00000000..fc81bb93 --- /dev/null +++ b/kvdb/etcd_test.go @@ -0,0 +1,154 @@ +// +build kvdb_etcd + +package kvdb + +import ( + "testing" + + "github.com/btcsuite/btcwallet/walletdb" + "github.com/lightningnetwork/lnd/kvdb/etcd" + "github.com/stretchr/testify/require" +) + +var ( + bkey = etcd.BucketKey + bval = etcd.BucketVal + vkey = etcd.ValueKey +) + +func TestEtcd(t *testing.T) { + tests := []struct { + name string + test func(*testing.T, walletdb.DB) + expectedDb map[string]string + }{ + { + name: "read cursor empty interval", + test: testReadCursorEmptyInterval, + }, + { + name: "read cursor non empty interval", + test: testReadCursorNonEmptyInterval, + }, + { + name: "read write cursor", + test: testReadWriteCursor, + expectedDb: map[string]string{ + bkey("apple"): bval("apple"), + vkey("a", "apple"): "0", + vkey("c", "apple"): "3", + vkey("cx", "apple"): "x", + vkey("cy", "apple"): "y", + vkey("da", "apple"): "3", + vkey("f", "apple"): "5", + }, + }, + { + name: "read write cursor with bucket and value", + test: testReadWriteCursorWithBucketAndValue, + expectedDb: map[string]string{ + bkey("apple"): bval("apple"), + bkey("apple", "banana"): bval("apple", "banana"), + bkey("apple", "pear"): bval("apple", "pear"), + vkey("key", "apple"): "val", + }, + }, + { + name: "bucket creation", + test: testBucketCreation, + expectedDb: map[string]string{ + bkey("apple"): bval("apple"), + bkey("apple", "banana"): bval("apple", "banana"), + bkey("apple", "mango"): bval("apple", "mango"), + bkey("apple", "banana", "pear"): bval("apple", "banana", "pear"), + }, + }, + { + name: "bucket deletion", + test: testBucketDeletion, + expectedDb: map[string]string{ + bkey("apple"): bval("apple"), + bkey("apple", "banana"): bval("apple", "banana"), + vkey("key1", "apple", "banana"): "val1", + vkey("key3", "apple", "banana"): "val3", + }, + }, + { + name: "bucket for each", + test: testBucketForEach, + expectedDb: map[string]string{ + bkey("apple"): bval("apple"), + bkey("apple", "banana"): bval("apple", "banana"), + vkey("key1", "apple"): "val1", + vkey("key2", "apple"): "val2", + vkey("key3", "apple"): "val3", + vkey("key1", "apple", "banana"): "val1", + vkey("key2", "apple", "banana"): "val2", + vkey("key3", "apple", "banana"): "val3", + }, + }, + { + name: "bucket for each with error", + test: testBucketForEachWithError, + expectedDb: map[string]string{ + bkey("apple"): bval("apple"), + bkey("apple", "banana"): bval("apple", "banana"), + bkey("apple", "pear"): bval("apple", "pear"), + vkey("key1", "apple"): "val1", + vkey("key2", "apple"): "val2", + }, + }, + { + name: "bucket sequence", + test: testBucketSequence, + }, + { + name: "key clash", + test: testKeyClash, + expectedDb: map[string]string{ + bkey("apple"): bval("apple"), + bkey("apple", "banana"): bval("apple", "banana"), + vkey("key", "apple"): "val", + }, + }, + { + name: "bucket create delete", + test: testBucketCreateDelete, + expectedDb: map[string]string{ + vkey("banana", "apple"): "value", + bkey("apple"): bval("apple"), + }, + }, + { + name: "tx manual commit", + test: testTxManualCommit, + expectedDb: map[string]string{ + bkey("apple"): bval("apple"), + vkey("testKey", "apple"): "testVal", + }, + }, + { + name: "tx rollback", + test: testTxRollback, + expectedDb: map[string]string{}, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + f := etcd.NewEtcdTestFixture(t) + defer f.Cleanup() + + test.test(t, f.NewBackend()) + + if test.expectedDb != nil { + dump := f.Dump() + require.Equal(t, test.expectedDb, dump) + } + }) + } +} diff --git a/kvdb/etcd/readwrite_bucket_test.go b/kvdb/readwrite_bucket_test.go similarity index 72% rename from kvdb/etcd/readwrite_bucket_test.go rename to kvdb/readwrite_bucket_test.go index b630e5ee..1927f8dc 100644 --- a/kvdb/etcd/readwrite_bucket_test.go +++ b/kvdb/readwrite_bucket_test.go @@ -1,9 +1,6 @@ -// +build kvdb_etcd - -package etcd +package kvdb import ( - "context" "fmt" "math" "testing" @@ -12,16 +9,8 @@ import ( "github.com/stretchr/testify/require" ) -func TestBucketCreation(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) - - err = db.Update(func(tx walletdb.ReadWriteTx) error { +func testBucketCreation(t *testing.T, db walletdb.DB) { + err := Update(db, func(tx walletdb.ReadWriteTx) error { // empty bucket name b, err := tx.CreateTopLevelBucket(nil) require.Error(t, walletdb.ErrBucketNameRequired, err) @@ -83,26 +72,10 @@ func TestBucketCreation(t *testing.T) { }, func() {}) require.Nil(t, err) - - expected := map[string]string{ - bkey("apple"): bval("apple"), - bkey("apple", "banana"): bval("apple", "banana"), - bkey("apple", "mango"): bval("apple", "mango"), - bkey("apple", "banana", "pear"): bval("apple", "banana", "pear"), - } - require.Equal(t, expected, f.Dump()) } -func TestBucketDeletion(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) - - err = db.Update(func(tx walletdb.ReadWriteTx) error { +func testBucketDeletion(t *testing.T, db walletdb.DB) { + err := Update(db, func(tx walletdb.ReadWriteTx) error { // "apple" apple, err := tx.CreateTopLevelBucket([]byte("apple")) require.Nil(t, err) @@ -193,26 +166,10 @@ func TestBucketDeletion(t *testing.T) { }, func() {}) require.Nil(t, err) - - expected := map[string]string{ - bkey("apple"): bval("apple"), - bkey("apple", "banana"): bval("apple", "banana"), - vkey("key1", "apple", "banana"): "val1", - vkey("key3", "apple", "banana"): "val3", - } - require.Equal(t, expected, f.Dump()) } -func TestBucketForEach(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) - - err = db.Update(func(tx walletdb.ReadWriteTx) error { +func testBucketForEach(t *testing.T, db walletdb.DB) { + err := Update(db, func(tx walletdb.ReadWriteTx) error { // "apple" apple, err := tx.CreateTopLevelBucket([]byte("apple")) require.Nil(t, err) @@ -265,30 +222,10 @@ func TestBucketForEach(t *testing.T) { }, func() {}) require.Nil(t, err) - - expected := map[string]string{ - bkey("apple"): bval("apple"), - bkey("apple", "banana"): bval("apple", "banana"), - vkey("key1", "apple"): "val1", - vkey("key2", "apple"): "val2", - vkey("key3", "apple"): "val3", - vkey("key1", "apple", "banana"): "val1", - vkey("key2", "apple", "banana"): "val2", - vkey("key3", "apple", "banana"): "val3", - } - require.Equal(t, expected, f.Dump()) } -func TestBucketForEachWithError(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) - - err = db.Update(func(tx walletdb.ReadWriteTx) error { +func testBucketForEachWithError(t *testing.T, db walletdb.DB) { + err := Update(db, func(tx walletdb.ReadWriteTx) error { // "apple" apple, err := tx.CreateTopLevelBucket([]byte("apple")) require.Nil(t, err) @@ -358,27 +295,10 @@ func TestBucketForEachWithError(t *testing.T) { }, func() {}) require.Nil(t, err) - - expected := map[string]string{ - bkey("apple"): bval("apple"), - bkey("apple", "banana"): bval("apple", "banana"), - bkey("apple", "pear"): bval("apple", "pear"), - vkey("key1", "apple"): "val1", - vkey("key2", "apple"): "val2", - } - require.Equal(t, expected, f.Dump()) } -func TestBucketSequence(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) - - err = db.Update(func(tx walletdb.ReadWriteTx) error { +func testBucketSequence(t *testing.T, db walletdb.DB) { + err := Update(db, func(tx walletdb.ReadWriteTx) error { apple, err := tx.CreateTopLevelBucket([]byte("apple")) require.Nil(t, err) require.NotNil(t, apple) @@ -408,19 +328,11 @@ func TestBucketSequence(t *testing.T) { // TestKeyClash tests that one cannot create a bucket if a value with the same // key exists and the same is true in reverse: that a value cannot be put if // a bucket with the same key exists. -func TestKeyClash(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) - +func testKeyClash(t *testing.T, db walletdb.DB) { // First: // put: /apple/key -> val // create bucket: /apple/banana - err = db.Update(func(tx walletdb.ReadWriteTx) error { + err := Update(db, func(tx walletdb.ReadWriteTx) error { apple, err := tx.CreateTopLevelBucket([]byte("apple")) require.Nil(t, err) require.NotNil(t, apple) @@ -439,7 +351,7 @@ func TestKeyClash(t *testing.T) { // Next try to: // put: /apple/banana -> val => will fail (as /apple/banana is a bucket) // create bucket: /apple/key => will fail (as /apple/key is a value) - err = db.Update(func(tx walletdb.ReadWriteTx) error { + err = Update(db, func(tx walletdb.ReadWriteTx) error { apple, err := tx.CreateTopLevelBucket([]byte("apple")) require.Nil(t, err) require.NotNil(t, apple) @@ -461,31 +373,12 @@ func TestKeyClash(t *testing.T) { }, func() {}) require.Nil(t, err) - - // Except that the only existing items in the db are: - // bucket: /apple - // bucket: /apple/banana - // value: /apple/key -> val - expected := map[string]string{ - bkey("apple"): bval("apple"), - bkey("apple", "banana"): bval("apple", "banana"), - vkey("key", "apple"): "val", - } - require.Equal(t, expected, f.Dump()) - } // TestBucketCreateDelete tests that creating then deleting then creating a // bucket suceeds. -func TestBucketCreateDelete(t *testing.T) { - t.Parallel() - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) - - err = db.Update(func(tx walletdb.ReadWriteTx) error { +func testBucketCreateDelete(t *testing.T, db walletdb.DB) { + err := Update(db, func(tx walletdb.ReadWriteTx) error { apple, err := tx.CreateTopLevelBucket([]byte("apple")) require.NoError(t, err) require.NotNil(t, apple) @@ -498,7 +391,7 @@ func TestBucketCreateDelete(t *testing.T) { }, func() {}) require.NoError(t, err) - err = db.Update(func(tx walletdb.ReadWriteTx) error { + err = Update(db, func(tx walletdb.ReadWriteTx) error { apple := tx.ReadWriteBucket([]byte("apple")) require.NotNil(t, apple) require.NoError(t, apple.DeleteNestedBucket([]byte("banana"))) @@ -507,7 +400,7 @@ func TestBucketCreateDelete(t *testing.T) { }, func() {}) require.NoError(t, err) - err = db.Update(func(tx walletdb.ReadWriteTx) error { + err = Update(db, func(tx walletdb.ReadWriteTx) error { apple := tx.ReadWriteBucket([]byte("apple")) require.NotNil(t, apple) require.NoError(t, apple.Put([]byte("banana"), []byte("value"))) @@ -515,10 +408,4 @@ func TestBucketCreateDelete(t *testing.T) { return nil }, func() {}) require.NoError(t, err) - - expected := map[string]string{ - vkey("banana", "apple"): "value", - bkey("apple"): bval("apple"), - } - require.Equal(t, expected, f.Dump()) } diff --git a/kvdb/etcd/readwrite_cursor_test.go b/kvdb/readwrite_cursor_test.go similarity index 77% rename from kvdb/etcd/readwrite_cursor_test.go rename to kvdb/readwrite_cursor_test.go index ce524f80..3ac83ba3 100644 --- a/kvdb/etcd/readwrite_cursor_test.go +++ b/kvdb/readwrite_cursor_test.go @@ -1,25 +1,14 @@ -// +build kvdb_etcd - -package etcd +package kvdb import ( - "context" "testing" "github.com/btcsuite/btcwallet/walletdb" "github.com/stretchr/testify/require" ) -func TestReadCursorEmptyInterval(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) - - err = db.Update(func(tx walletdb.ReadWriteTx) error { +func testReadCursorEmptyInterval(t *testing.T, db walletdb.DB) { + err := Update(db, func(tx walletdb.ReadWriteTx) error { b, err := tx.CreateTopLevelBucket([]byte("apple")) require.NoError(t, err) require.NotNil(t, b) @@ -28,7 +17,7 @@ func TestReadCursorEmptyInterval(t *testing.T) { }, func() {}) require.NoError(t, err) - err = db.View(func(tx walletdb.ReadTx) error { + err = View(db, func(tx walletdb.ReadTx) error { b := tx.ReadBucket([]byte("apple")) require.NotNil(t, b) @@ -54,15 +43,7 @@ func TestReadCursorEmptyInterval(t *testing.T) { require.NoError(t, err) } -func TestReadCursorNonEmptyInterval(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) - +func testReadCursorNonEmptyInterval(t *testing.T, db walletdb.DB) { testKeyValues := []KV{ {"b", "1"}, {"c", "2"}, @@ -70,7 +51,7 @@ func TestReadCursorNonEmptyInterval(t *testing.T) { {"e", "4"}, } - err = db.Update(func(tx walletdb.ReadWriteTx) error { + err := Update(db, func(tx walletdb.ReadWriteTx) error { b, err := tx.CreateTopLevelBucket([]byte("apple")) require.NoError(t, err) require.NotNil(t, b) @@ -83,7 +64,7 @@ func TestReadCursorNonEmptyInterval(t *testing.T) { require.NoError(t, err) - err = db.View(func(tx walletdb.ReadTx) error { + err = View(db, func(tx walletdb.ReadTx) error { b := tx.ReadBucket([]byte("apple")) require.NotNil(t, b) @@ -131,14 +112,7 @@ func TestReadCursorNonEmptyInterval(t *testing.T) { require.NoError(t, err) } -func TestReadWriteCursor(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) +func testReadWriteCursor(t *testing.T, db walletdb.DB) { testKeyValues := []KV{ {"b", "1"}, @@ -150,7 +124,7 @@ func TestReadWriteCursor(t *testing.T) { count := len(testKeyValues) // Pre-store the first half of the interval. - require.NoError(t, db.Update(func(tx walletdb.ReadWriteTx) error { + require.NoError(t, Update(db, func(tx walletdb.ReadWriteTx) error { b, err := tx.CreateTopLevelBucket([]byte("apple")) require.NoError(t, err) require.NotNil(t, b) @@ -165,13 +139,13 @@ func TestReadWriteCursor(t *testing.T) { return nil }, func() {})) - err = db.Update(func(tx walletdb.ReadWriteTx) error { + err := Update(db, func(tx walletdb.ReadWriteTx) error { b := tx.ReadWriteBucket([]byte("apple")) require.NotNil(t, b) // Store the second half of the interval. for i := count / 2; i < count; i++ { - err = b.Put( + err := b.Put( []byte(testKeyValues[i].key), []byte(testKeyValues[i].val), ) @@ -280,32 +254,14 @@ func TestReadWriteCursor(t *testing.T) { }, func() {}) require.NoError(t, err) - - expected := map[string]string{ - bkey("apple"): bval("apple"), - vkey("a", "apple"): "0", - vkey("c", "apple"): "3", - vkey("cx", "apple"): "x", - vkey("cy", "apple"): "y", - vkey("da", "apple"): "3", - vkey("f", "apple"): "5", - } - require.Equal(t, expected, f.Dump()) } -// TestReadWriteCursorWithBucketAndValue tests that cursors are able to iterate +// testReadWriteCursorWithBucketAndValue tests that cursors are able to iterate // over both bucket and value keys if both are present in the iterated bucket. -func TestReadWriteCursorWithBucketAndValue(t *testing.T) { - t.Parallel() - - f := NewEtcdTestFixture(t) - defer f.Cleanup() - - db, err := newEtcdBackend(context.TODO(), f.BackendConfig()) - require.NoError(t, err) +func testReadWriteCursorWithBucketAndValue(t *testing.T, db walletdb.DB) { // Pre-store the first half of the interval. - require.NoError(t, db.Update(func(tx walletdb.ReadWriteTx) error { + require.NoError(t, Update(db, func(tx walletdb.ReadWriteTx) error { b, err := tx.CreateTopLevelBucket([]byte("apple")) require.NoError(t, err) require.NotNil(t, b) @@ -323,7 +279,7 @@ func TestReadWriteCursorWithBucketAndValue(t *testing.T) { return nil }, func() {})) - err = db.View(func(tx walletdb.ReadTx) error { + err := View(db, func(tx walletdb.ReadTx) error { b := tx.ReadBucket([]byte("apple")) require.NotNil(t, b) @@ -358,12 +314,4 @@ func TestReadWriteCursorWithBucketAndValue(t *testing.T) { }, func() {}) require.NoError(t, err) - - expected := map[string]string{ - bkey("apple"): bval("apple"), - bkey("apple", "banana"): bval("apple", "banana"), - bkey("apple", "pear"): bval("apple", "pear"), - vkey("key", "apple"): "val", - } - require.Equal(t, expected, f.Dump()) } diff --git a/kvdb/readwrite_tx_test.go b/kvdb/readwrite_tx_test.go new file mode 100644 index 00000000..b07e2efb --- /dev/null +++ b/kvdb/readwrite_tx_test.go @@ -0,0 +1,49 @@ +package kvdb + +import ( + "testing" + + "github.com/btcsuite/btcwallet/walletdb" + "github.com/stretchr/testify/require" +) + +func testTxManualCommit(t *testing.T, db walletdb.DB) { + tx, err := db.BeginReadWriteTx() + require.NoError(t, err) + require.NotNil(t, tx) + + committed := false + + tx.OnCommit(func() { + committed = true + }) + + apple, err := tx.CreateTopLevelBucket([]byte("apple")) + require.NoError(t, err) + require.NotNil(t, apple) + require.NoError(t, apple.Put([]byte("testKey"), []byte("testVal"))) + + banana, err := tx.CreateTopLevelBucket([]byte("banana")) + require.NoError(t, err) + require.NotNil(t, banana) + require.NoError(t, banana.Put([]byte("testKey"), []byte("testVal"))) + require.NoError(t, tx.DeleteTopLevelBucket([]byte("banana"))) + + require.NoError(t, tx.Commit()) + require.True(t, committed) +} + +func testTxRollback(t *testing.T, db walletdb.DB) { + tx, err := db.BeginReadWriteTx() + require.Nil(t, err) + require.NotNil(t, tx) + + apple, err := tx.CreateTopLevelBucket([]byte("apple")) + require.Nil(t, err) + require.NotNil(t, apple) + + require.NoError(t, apple.Put([]byte("testKey"), []byte("testVal"))) + + require.NoError(t, tx.Rollback()) + require.Error(t, walletdb.ErrTxClosed, tx.Commit()) +} diff --git a/kvdb/test.go b/kvdb/test.go new file mode 100644 index 00000000..483862e9 --- /dev/null +++ b/kvdb/test.go @@ -0,0 +1,14 @@ +package kvdb + +type KV struct { + key string + val string +} + +func reverseKVs(a []KV) []KV { + for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 { + a[i], a[j] = a[j], a[i] + } + + return a +} From 84490466be847f41a77f1fb11d7d6233bac510dd Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Thu, 8 Jul 2021 09:40:17 +0200 Subject: [PATCH 2/4] kvdb/test: remove invalid operations Accessing buckets that have been removed is not an allowed operation. --- kvdb/readwrite_bucket_test.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/kvdb/readwrite_bucket_test.go b/kvdb/readwrite_bucket_test.go index 1927f8dc..6d3dd705 100644 --- a/kvdb/readwrite_bucket_test.go +++ b/kvdb/readwrite_bucket_test.go @@ -151,15 +151,6 @@ func testBucketDeletion(t *testing.T, db walletdb.DB) { // "apple/pear" deleted require.Nil(t, apple.NestedReadWriteBucket([]byte("pear"))) - // "apple/pear/cherry" deleted - require.Nil(t, pear.NestedReadWriteBucket([]byte("cherry"))) - - // Values deleted too. - for _, kv := range kvs { - require.Nil(t, pear.Get([]byte(kv.key))) - require.Nil(t, cherry.Get([]byte(kv.key))) - } - // "aple/banana" exists require.NotNil(t, apple.NestedReadWriteBucket([]byte("banana"))) return nil From f592375d1b0fe24978a2f80ff879f9cbdd4d855b Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Thu, 8 Jul 2021 09:44:41 +0200 Subject: [PATCH 3/4] kvdb/test: fix cursor tests to match bbolt semantics From bbolt docs: // Seek positions the cursor at the passed seek key. If the key does not exist, // the cursor is moved to the next key after seek. Returns the new pair. --- kvdb/etcd/readwrite_cursor.go | 5 ----- kvdb/readwrite_cursor_test.go | 5 ++--- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/kvdb/etcd/readwrite_cursor.go b/kvdb/etcd/readwrite_cursor.go index 75c0456d..fb408b8f 100644 --- a/kvdb/etcd/readwrite_cursor.go +++ b/kvdb/etcd/readwrite_cursor.go @@ -96,11 +96,6 @@ func (c *readWriteCursor) Prev() (key, value []byte) { // not exist, the cursor is moved to the next key after seek. Returns // the new pair. func (c *readWriteCursor) Seek(seek []byte) (key, value []byte) { - // Return nil if trying to seek to an empty key. - if seek == nil { - return nil, nil - } - // Seek to the first key with prefix + seek. If that key is not present // STM will seek to the next matching key with prefix. kv, err := c.bucket.tx.stm.Seek(c.prefix, c.prefix+string(seek)) diff --git a/kvdb/readwrite_cursor_test.go b/kvdb/readwrite_cursor_test.go index 3ac83ba3..de70196b 100644 --- a/kvdb/readwrite_cursor_test.go +++ b/kvdb/readwrite_cursor_test.go @@ -99,8 +99,8 @@ func testReadCursorNonEmptyInterval(t *testing.T, db walletdb.DB) { // Seek to nonexisting key. k, v = cursor.Seek(nil) - require.Nil(t, k) - require.Nil(t, v) + require.Equal(t, "b", string(k)) + require.Equal(t, "1", string(v)) k, v = cursor.Seek([]byte("x")) require.Nil(t, k) @@ -113,7 +113,6 @@ func testReadCursorNonEmptyInterval(t *testing.T, db walletdb.DB) { } func testReadWriteCursor(t *testing.T, db walletdb.DB) { - testKeyValues := []KV{ {"b", "1"}, {"c", "2"}, From e9cba1a526a77f757e85017f6ceecd8d9e9a475e Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Wed, 7 Jul 2021 09:27:43 +0200 Subject: [PATCH 4/4] kvdb/test: add bolt test --- kvdb/bolt_fixture.go | 44 ++++++++++++++++++++++++ kvdb/bolt_test.go | 80 ++++++++++++++++++++++++++++++++++++++++++++ kvdb/go.sum | 12 +++---- 3 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 kvdb/bolt_fixture.go create mode 100644 kvdb/bolt_test.go diff --git a/kvdb/bolt_fixture.go b/kvdb/bolt_fixture.go new file mode 100644 index 00000000..d78e1ece --- /dev/null +++ b/kvdb/bolt_fixture.go @@ -0,0 +1,44 @@ +package kvdb + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/btcsuite/btcwallet/walletdb" + "github.com/stretchr/testify/require" +) + +type boltFixture struct { + t *testing.T + tempDir string +} + +func NewBoltFixture(t *testing.T) *boltFixture { + tempDir, err := ioutil.TempDir("", "test") + require.NoError(t, err) + + return &boltFixture{ + t: t, + tempDir: tempDir, + } +} + +func (b *boltFixture) Cleanup() { + os.RemoveAll(b.tempDir) +} + +func (b *boltFixture) NewBackend() walletdb.DB { + dbPath := filepath.Join(b.tempDir) + + db, err := GetBoltBackend(&BoltBackendConfig{ + DBPath: dbPath, + DBFileName: "test.db", + NoFreelistSync: true, + DBTimeout: DefaultDBTimeout, + }) + require.NoError(b.t, err) + + return db +} diff --git a/kvdb/bolt_test.go b/kvdb/bolt_test.go new file mode 100644 index 00000000..08221b90 --- /dev/null +++ b/kvdb/bolt_test.go @@ -0,0 +1,80 @@ +package kvdb + +import ( + "testing" + + "github.com/btcsuite/btcwallet/walletdb" +) + +func TestBolt(t *testing.T) { + tests := []struct { + name string + test func(*testing.T, walletdb.DB) + }{ + { + name: "read cursor empty interval", + test: testReadCursorEmptyInterval, + }, + { + name: "read cursor non empty interval", + test: testReadCursorNonEmptyInterval, + }, + { + name: "read write cursor", + test: testReadWriteCursor, + }, + { + name: "read write cursor with bucket and value", + test: testReadWriteCursorWithBucketAndValue, + }, + { + name: "bucket creation", + test: testBucketCreation, + }, + { + name: "bucket deletion", + test: testBucketDeletion, + }, + { + name: "bucket for each", + test: testBucketForEach, + }, + { + name: "bucket for each with error", + test: testBucketForEachWithError, + }, + { + name: "bucket sequence", + test: testBucketSequence, + }, + { + name: "key clash", + test: testKeyClash, + }, + { + name: "bucket create delete", + test: testBucketCreateDelete, + }, + { + name: "tx manual commit", + test: testTxManualCommit, + }, + { + name: "tx rollback", + test: testTxRollback, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + f := NewBoltFixture(t) + defer f.Cleanup() + + test.test(t, f.NewBackend()) + }) + } +} diff --git a/kvdb/go.sum b/kvdb/go.sum index bdc02b4e..b3c5cfa9 100644 --- a/kvdb/go.sum +++ b/kvdb/go.sum @@ -7,12 +7,17 @@ github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQY github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcwallet/walletdb v1.3.5-0.20210513043850-3a2f12e3a954 h1:CB6chiHPhZWmbCL7kFCADDf15V6I3EUNDgGC25jbptc= github.com/btcsuite/btcwallet/walletdb v1.3.5-0.20210513043850-3a2f12e3a954/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -109,7 +114,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -137,6 +141,7 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -160,7 +165,6 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= @@ -174,7 +178,6 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -217,7 +220,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -233,7 +235,6 @@ google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= @@ -247,7 +248,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=