From 8ebab066032334c94b9eed6c0b20df3d467f91a4 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Mon, 12 Oct 2020 23:06:43 +0200 Subject: [PATCH 1/2] Add simple iterator test - all asc/desc --- go.mod | 1 + x/wasm/internal/types/iavl_range_test.go | 59 ++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 x/wasm/internal/types/iavl_range_test.go diff --git a/go.mod b/go.mod index e19ef51d..db3f22d3 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/spf13/viper v1.6.3 github.com/stretchr/testify v1.6.1 github.com/tendermint/go-amino v0.15.1 + github.com/tendermint/iavl v0.14.0 github.com/tendermint/tendermint v0.33.6 github.com/tendermint/tm-db v0.5.1 go.etcd.io/bbolt v1.3.4 // indirect diff --git a/x/wasm/internal/types/iavl_range_test.go b/x/wasm/internal/types/iavl_range_test.go new file mode 100644 index 00000000..3f7a054c --- /dev/null +++ b/x/wasm/internal/types/iavl_range_test.go @@ -0,0 +1,59 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/store" + "github.com/cosmos/cosmos-sdk/store/iavl" + "github.com/magiconair/properties/assert" + "github.com/stretchr/testify/require" + iavl2 "github.com/tendermint/iavl" + dbm "github.com/tendermint/tm-db" + "testing" +) + +// This is modeled close to +// https://github.com/CosmWasm/cosmwasm-plus/blob/f97a7de44b6a930fd1d5179ee6f95b786a532f32/packages/storage-plus/src/prefix.rs#L183 +// and designed to ensure the IAVL store handles bounds the same way as the mock storage we use in Rust contract tests +func TestIavlRangeBounds(t *testing.T) { + db := dbm.NewMemDB() + tree, err := iavl2.NewMutableTree(db, 50) + require.NoError(t, err) + store := iavl.UnsafeNewStore(tree) + + expected := []KV{ + {[]byte("bar"), []byte("1")}, + {[]byte("ra"), []byte("2")}, + {[]byte("zi"), []byte("3")}, + } + reversed := []KV{ + {[]byte("zi"), []byte("3")}, + {[]byte("ra"), []byte("2")}, + {[]byte("bar"), []byte("1")}, + } + + // set up test cases, like `ensure_proper_range_bounds` in `cw-storage-plus` + for _, kv := range expected { + store.Set(kv.Key, kv.Value) + } + + ascAll := store.Iterator(nil, nil) + assert.Equal(t, expected, consume(ascAll)) + + descAll := store.ReverseIterator(nil, nil) + assert.Equal(t, reversed, consume(descAll)) +} + +type KV struct { + Key []byte + Value []byte +} + +func consume(itr store.Iterator) []KV { + defer itr.Close() + + var res []KV + for ; itr.Valid(); itr.Next() { + k, v := itr.Key(), itr.Value() + res = append(res, KV{k, v}) + } + return res +} \ No newline at end of file From e3c37da8c48cb6b0416717131e0725ffae64bdec Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Mon, 12 Oct 2020 23:16:58 +0200 Subject: [PATCH 2/2] Full test cases over all bounds --- x/wasm/internal/types/iavl_range_test.go | 46 ++++++++++++++++++------ 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/x/wasm/internal/types/iavl_range_test.go b/x/wasm/internal/types/iavl_range_test.go index 3f7a054c..4af41474 100644 --- a/x/wasm/internal/types/iavl_range_test.go +++ b/x/wasm/internal/types/iavl_range_test.go @@ -3,7 +3,6 @@ package types import ( "github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/store/iavl" - "github.com/magiconair/properties/assert" "github.com/stretchr/testify/require" iavl2 "github.com/tendermint/iavl" dbm "github.com/tendermint/tm-db" @@ -14,11 +13,12 @@ import ( // https://github.com/CosmWasm/cosmwasm-plus/blob/f97a7de44b6a930fd1d5179ee6f95b786a532f32/packages/storage-plus/src/prefix.rs#L183 // and designed to ensure the IAVL store handles bounds the same way as the mock storage we use in Rust contract tests func TestIavlRangeBounds(t *testing.T) { - db := dbm.NewMemDB() - tree, err := iavl2.NewMutableTree(db, 50) + memdb := dbm.NewMemDB() + tree, err := iavl2.NewMutableTree(memdb, 50) require.NoError(t, err) - store := iavl.UnsafeNewStore(tree) + kvstore := iavl.UnsafeNewStore(tree) + // values to compare with expected := []KV{ {[]byte("bar"), []byte("1")}, {[]byte("ra"), []byte("2")}, @@ -32,18 +32,42 @@ func TestIavlRangeBounds(t *testing.T) { // set up test cases, like `ensure_proper_range_bounds` in `cw-storage-plus` for _, kv := range expected { - store.Set(kv.Key, kv.Value) + kvstore.Set(kv.Key, kv.Value) } - ascAll := store.Iterator(nil, nil) - assert.Equal(t, expected, consume(ascAll)) + cases := map[string]struct { + start []byte + end []byte + reverse bool + expected []KV + }{ + "all ascending": {nil, nil, false, expected}, + "ascending start inclusive": {[]byte("ra"), nil, false, expected[1:]}, + "ascending end exclusive": {nil, []byte("ra"), false, expected[:1]}, + "ascending both points": {[]byte("bar"), []byte("zi"), false, expected[:2]}, - descAll := store.ReverseIterator(nil, nil) - assert.Equal(t, reversed, consume(descAll)) + "all descending": {nil, nil, true, reversed}, + "descending start inclusive": {[]byte("ra"), nil, true, reversed[:2]}, // "zi", "ra" + "descending end inclusive": {nil, []byte("ra"), true, reversed[2:]}, // "bar" + "descending both points": {[]byte("bar"), []byte("zi"), true, reversed[1:]}, // "ra", "bar" + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + var iter store.Iterator + if tc.reverse { + iter = kvstore.ReverseIterator(tc.start, tc.end) + } else { + iter = kvstore.Iterator(tc.start, tc.end) + } + items := consume(iter) + require.Equal(t, tc.expected, items) + }) + } } type KV struct { - Key []byte + Key []byte Value []byte } @@ -56,4 +80,4 @@ func consume(itr store.Iterator) []KV { res = append(res, KV{k, v}) } return res -} \ No newline at end of file +}