package listenkv_test import ( "bytes" "fmt" "io" "testing" "github.com/cosmos/cosmos-sdk/codec" codecTypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/store/types" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" ) func bz(s string) []byte { return []byte(s) } func keyFmt(i int) []byte { return bz(fmt.Sprintf("key%0.8d", i)) } func valFmt(i int) []byte { return bz(fmt.Sprintf("value%0.8d", i)) } var kvPairs = []types.KVPair{ {Key: keyFmt(1), Value: valFmt(1)}, {Key: keyFmt(2), Value: valFmt(2)}, {Key: keyFmt(3), Value: valFmt(3)}, } var testStoreKey = types.NewKVStoreKey("listen_test") var interfaceRegistry = codecTypes.NewInterfaceRegistry() var testMarshaller = codec.NewProtoCodec(interfaceRegistry) func newListenKVStore(w io.Writer) *listenkv.Store { store := newEmptyListenKVStore(w) for _, kvPair := range kvPairs { store.Set(kvPair.Key, kvPair.Value) } return store } func newEmptyListenKVStore(w io.Writer) *listenkv.Store { listener := types.NewStoreKVPairWriteListener(w, testMarshaller) memDB := dbadapter.Store{DB: dbm.NewMemDB()} return listenkv.NewStore(memDB, testStoreKey, []types.WriteListener{listener}) } func TestListenKVStoreGet(t *testing.T) { testCases := []struct { key []byte expectedValue []byte }{ { key: kvPairs[0].Key, expectedValue: kvPairs[0].Value, }, { key: []byte("does-not-exist"), expectedValue: nil, }, } for _, tc := range testCases { var buf bytes.Buffer store := newListenKVStore(&buf) buf.Reset() value := store.Get(tc.key) require.Equal(t, tc.expectedValue, value) } } func TestListenKVStoreSet(t *testing.T) { testCases := []struct { key []byte value []byte expectedOut *types.StoreKVPair }{ { key: kvPairs[0].Key, value: kvPairs[0].Value, expectedOut: &types.StoreKVPair{ Key: kvPairs[0].Key, Value: kvPairs[0].Value, StoreKey: testStoreKey.Name(), Delete: false, }, }, { key: kvPairs[1].Key, value: kvPairs[1].Value, expectedOut: &types.StoreKVPair{ Key: kvPairs[1].Key, Value: kvPairs[1].Value, StoreKey: testStoreKey.Name(), Delete: false, }, }, { key: kvPairs[2].Key, value: kvPairs[2].Value, expectedOut: &types.StoreKVPair{ Key: kvPairs[2].Key, Value: kvPairs[2].Value, StoreKey: testStoreKey.Name(), Delete: false, }, }, } for _, tc := range testCases { var buf bytes.Buffer store := newEmptyListenKVStore(&buf) buf.Reset() store.Set(tc.key, tc.value) storeKVPair := new(types.StoreKVPair) testMarshaller.UnmarshalLengthPrefixed(buf.Bytes(), storeKVPair) require.Equal(t, tc.expectedOut, storeKVPair) } var buf bytes.Buffer store := newEmptyListenKVStore(&buf) require.Panics(t, func() { store.Set([]byte(""), []byte("value")) }, "setting an empty key should panic") require.Panics(t, func() { store.Set(nil, []byte("value")) }, "setting a nil key should panic") } func TestListenKVStoreDelete(t *testing.T) { testCases := []struct { key []byte expectedOut *types.StoreKVPair }{ { key: kvPairs[0].Key, expectedOut: &types.StoreKVPair{ Key: kvPairs[0].Key, Value: nil, StoreKey: testStoreKey.Name(), Delete: true, }, }, } for _, tc := range testCases { var buf bytes.Buffer store := newListenKVStore(&buf) buf.Reset() store.Delete(tc.key) storeKVPair := new(types.StoreKVPair) testMarshaller.UnmarshalLengthPrefixed(buf.Bytes(), storeKVPair) require.Equal(t, tc.expectedOut, storeKVPair) } } func TestListenKVStoreHas(t *testing.T) { testCases := []struct { key []byte expected bool }{ { key: kvPairs[0].Key, expected: true, }, } for _, tc := range testCases { var buf bytes.Buffer store := newListenKVStore(&buf) buf.Reset() ok := store.Has(tc.key) require.Equal(t, tc.expected, ok) } } func TestTestListenKVStoreIterator(t *testing.T) { var buf bytes.Buffer store := newListenKVStore(&buf) iterator := store.Iterator(nil, nil) s, e := iterator.Domain() require.Equal(t, []byte(nil), s) require.Equal(t, []byte(nil), e) testCases := []struct { expectedKey []byte expectedValue []byte }{ { expectedKey: kvPairs[0].Key, expectedValue: kvPairs[0].Value, }, { expectedKey: kvPairs[1].Key, expectedValue: kvPairs[1].Value, }, { expectedKey: kvPairs[2].Key, expectedValue: kvPairs[2].Value, }, } for _, tc := range testCases { ka := iterator.Key() require.Equal(t, tc.expectedKey, ka) va := iterator.Value() require.Equal(t, tc.expectedValue, va) iterator.Next() } require.False(t, iterator.Valid()) require.Panics(t, iterator.Next) require.NoError(t, iterator.Close()) } func TestTestListenKVStoreReverseIterator(t *testing.T) { var buf bytes.Buffer store := newListenKVStore(&buf) iterator := store.ReverseIterator(nil, nil) s, e := iterator.Domain() require.Equal(t, []byte(nil), s) require.Equal(t, []byte(nil), e) testCases := []struct { expectedKey []byte expectedValue []byte }{ { expectedKey: kvPairs[2].Key, expectedValue: kvPairs[2].Value, }, { expectedKey: kvPairs[1].Key, expectedValue: kvPairs[1].Value, }, { expectedKey: kvPairs[0].Key, expectedValue: kvPairs[0].Value, }, } for _, tc := range testCases { ka := iterator.Key() require.Equal(t, tc.expectedKey, ka) va := iterator.Value() require.Equal(t, tc.expectedValue, va) iterator.Next() } require.False(t, iterator.Valid()) require.Panics(t, iterator.Next) require.NoError(t, iterator.Close()) } func TestListenKVStorePrefix(t *testing.T) { store := newEmptyListenKVStore(nil) pStore := prefix.NewStore(store, []byte("listen_prefix")) require.IsType(t, prefix.Store{}, pStore) } func TestListenKVStoreGetStoreType(t *testing.T) { memDB := dbadapter.Store{DB: dbm.NewMemDB()} store := newEmptyListenKVStore(nil) require.Equal(t, memDB.GetStoreType(), store.GetStoreType()) } func TestListenKVStoreCacheWrap(t *testing.T) { store := newEmptyListenKVStore(nil) require.Panics(t, func() { store.CacheWrap() }) } func TestListenKVStoreCacheWrapWithTrace(t *testing.T) { store := newEmptyListenKVStore(nil) require.Panics(t, func() { store.CacheWrapWithTrace(nil, nil) }) } func TestListenKVStoreCacheWrapWithListeners(t *testing.T) { store := newEmptyListenKVStore(nil) require.Panics(t, func() { store.CacheWrapWithListeners(nil, nil) }) }