package tracekv_test import ( "bytes" "fmt" "io" "testing" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" ) 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)}, } func newTraceKVStore(w io.Writer) *tracekv.Store { store := newEmptyTraceKVStore(w) for _, kvPair := range kvPairs { store.Set(kvPair.Key, kvPair.Value) } return store } func newEmptyTraceKVStore(w io.Writer) *tracekv.Store { memDB := dbadapter.Store{DB: dbm.NewMemDB()} tc := types.TraceContext(map[string]interface{}{"blockHeight": 64}) return tracekv.NewStore(memDB, w, tc) } func TestTraceKVStoreGet(t *testing.T) { testCases := []struct { key []byte expectedValue []byte expectedOut string }{ { key: kvPairs[0].Key, expectedValue: kvPairs[0].Value, expectedOut: "{\"operation\":\"read\",\"key\":\"a2V5MDAwMDAwMDE=\",\"value\":\"dmFsdWUwMDAwMDAwMQ==\",\"metadata\":{\"blockHeight\":64}}\n", }, { key: []byte("does-not-exist"), expectedValue: nil, expectedOut: "{\"operation\":\"read\",\"key\":\"ZG9lcy1ub3QtZXhpc3Q=\",\"value\":\"\",\"metadata\":{\"blockHeight\":64}}\n", }, } for _, tc := range testCases { var buf bytes.Buffer store := newTraceKVStore(&buf) buf.Reset() value := store.Get(tc.key) require.Equal(t, tc.expectedValue, value) require.Equal(t, tc.expectedOut, buf.String()) } } func TestTraceKVStoreSet(t *testing.T) { testCases := []struct { key []byte value []byte expectedOut string }{ { key: kvPairs[0].Key, value: kvPairs[0].Value, expectedOut: "{\"operation\":\"write\",\"key\":\"a2V5MDAwMDAwMDE=\",\"value\":\"dmFsdWUwMDAwMDAwMQ==\",\"metadata\":{\"blockHeight\":64}}\n", }, { key: kvPairs[1].Key, value: kvPairs[1].Value, expectedOut: "{\"operation\":\"write\",\"key\":\"a2V5MDAwMDAwMDI=\",\"value\":\"dmFsdWUwMDAwMDAwMg==\",\"metadata\":{\"blockHeight\":64}}\n", }, { key: kvPairs[2].Key, value: kvPairs[2].Value, expectedOut: "{\"operation\":\"write\",\"key\":\"a2V5MDAwMDAwMDM=\",\"value\":\"dmFsdWUwMDAwMDAwMw==\",\"metadata\":{\"blockHeight\":64}}\n", }, } for _, tc := range testCases { var buf bytes.Buffer store := newEmptyTraceKVStore(&buf) buf.Reset() store.Set(tc.key, tc.value) require.Equal(t, tc.expectedOut, buf.String()) } var buf bytes.Buffer store := newEmptyTraceKVStore(&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 TestTraceKVStoreDelete(t *testing.T) { testCases := []struct { key []byte expectedOut string }{ { key: kvPairs[0].Key, expectedOut: "{\"operation\":\"delete\",\"key\":\"a2V5MDAwMDAwMDE=\",\"value\":\"\",\"metadata\":{\"blockHeight\":64}}\n", }, } for _, tc := range testCases { var buf bytes.Buffer store := newTraceKVStore(&buf) buf.Reset() store.Delete(tc.key) require.Equal(t, tc.expectedOut, buf.String()) } } func TestTraceKVStoreHas(t *testing.T) { testCases := []struct { key []byte expected bool }{ { key: kvPairs[0].Key, expected: true, }, } for _, tc := range testCases { var buf bytes.Buffer store := newTraceKVStore(&buf) buf.Reset() ok := store.Has(tc.key) require.Equal(t, tc.expected, ok) } } func TestTestTraceKVStoreIterator(t *testing.T) { var buf bytes.Buffer store := newTraceKVStore(&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 expectedKeyOut string expectedvalueOut string }{ { expectedKey: kvPairs[0].Key, expectedValue: kvPairs[0].Value, expectedKeyOut: "{\"operation\":\"iterKey\",\"key\":\"a2V5MDAwMDAwMDE=\",\"value\":\"\",\"metadata\":{\"blockHeight\":64}}\n", expectedvalueOut: "{\"operation\":\"iterValue\",\"key\":\"\",\"value\":\"dmFsdWUwMDAwMDAwMQ==\",\"metadata\":{\"blockHeight\":64}}\n", }, { expectedKey: kvPairs[1].Key, expectedValue: kvPairs[1].Value, expectedKeyOut: "{\"operation\":\"iterKey\",\"key\":\"a2V5MDAwMDAwMDI=\",\"value\":\"\",\"metadata\":{\"blockHeight\":64}}\n", expectedvalueOut: "{\"operation\":\"iterValue\",\"key\":\"\",\"value\":\"dmFsdWUwMDAwMDAwMg==\",\"metadata\":{\"blockHeight\":64}}\n", }, { expectedKey: kvPairs[2].Key, expectedValue: kvPairs[2].Value, expectedKeyOut: "{\"operation\":\"iterKey\",\"key\":\"a2V5MDAwMDAwMDM=\",\"value\":\"\",\"metadata\":{\"blockHeight\":64}}\n", expectedvalueOut: "{\"operation\":\"iterValue\",\"key\":\"\",\"value\":\"dmFsdWUwMDAwMDAwMw==\",\"metadata\":{\"blockHeight\":64}}\n", }, } for _, tc := range testCases { buf.Reset() ka := iterator.Key() require.Equal(t, tc.expectedKeyOut, buf.String()) buf.Reset() va := iterator.Value() require.Equal(t, tc.expectedvalueOut, buf.String()) require.Equal(t, tc.expectedKey, ka) require.Equal(t, tc.expectedValue, va) iterator.Next() } require.False(t, iterator.Valid()) require.Panics(t, iterator.Next) require.NoError(t, iterator.Close()) } func TestTestTraceKVStoreReverseIterator(t *testing.T) { var buf bytes.Buffer store := newTraceKVStore(&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 expectedKeyOut string expectedvalueOut string }{ { expectedKey: kvPairs[2].Key, expectedValue: kvPairs[2].Value, expectedKeyOut: "{\"operation\":\"iterKey\",\"key\":\"a2V5MDAwMDAwMDM=\",\"value\":\"\",\"metadata\":{\"blockHeight\":64}}\n", expectedvalueOut: "{\"operation\":\"iterValue\",\"key\":\"\",\"value\":\"dmFsdWUwMDAwMDAwMw==\",\"metadata\":{\"blockHeight\":64}}\n", }, { expectedKey: kvPairs[1].Key, expectedValue: kvPairs[1].Value, expectedKeyOut: "{\"operation\":\"iterKey\",\"key\":\"a2V5MDAwMDAwMDI=\",\"value\":\"\",\"metadata\":{\"blockHeight\":64}}\n", expectedvalueOut: "{\"operation\":\"iterValue\",\"key\":\"\",\"value\":\"dmFsdWUwMDAwMDAwMg==\",\"metadata\":{\"blockHeight\":64}}\n", }, { expectedKey: kvPairs[0].Key, expectedValue: kvPairs[0].Value, expectedKeyOut: "{\"operation\":\"iterKey\",\"key\":\"a2V5MDAwMDAwMDE=\",\"value\":\"\",\"metadata\":{\"blockHeight\":64}}\n", expectedvalueOut: "{\"operation\":\"iterValue\",\"key\":\"\",\"value\":\"dmFsdWUwMDAwMDAwMQ==\",\"metadata\":{\"blockHeight\":64}}\n", }, } for _, tc := range testCases { buf.Reset() ka := iterator.Key() require.Equal(t, tc.expectedKeyOut, buf.String()) buf.Reset() va := iterator.Value() require.Equal(t, tc.expectedvalueOut, buf.String()) require.Equal(t, tc.expectedKey, ka) require.Equal(t, tc.expectedValue, va) iterator.Next() } require.False(t, iterator.Valid()) require.Panics(t, iterator.Next) require.NoError(t, iterator.Close()) } func TestTraceKVStorePrefix(t *testing.T) { store := newEmptyTraceKVStore(nil) pStore := prefix.NewStore(store, []byte("trace_prefix")) require.IsType(t, prefix.Store{}, pStore) } func TestTraceKVStoreGetStoreType(t *testing.T) { memDB := dbadapter.Store{DB: dbm.NewMemDB()} store := newEmptyTraceKVStore(nil) require.Equal(t, memDB.GetStoreType(), store.GetStoreType()) } func TestTraceKVStoreCacheWrap(t *testing.T) { store := newEmptyTraceKVStore(nil) require.Panics(t, func() { store.CacheWrap() }) } func TestTraceKVStoreCacheWrapWithTrace(t *testing.T) { store := newEmptyTraceKVStore(nil) require.Panics(t, func() { store.CacheWrapWithTrace(nil, nil) }) } func TestTraceKVStoreCacheWrapWithListeners(t *testing.T) { store := newEmptyTraceKVStore(nil) require.Panics(t, func() { store.CacheWrapWithListeners(nil, nil) }) }