test(sims): fix sim-import-export and improve sims (#15835)
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
|
||||
@@ -133,56 +134,103 @@ func GetSimulationLog(storeName string, sdr simtypes.StoreDecoderRegistry, kvAs,
|
||||
|
||||
// DiffKVStores compares two KVstores and returns all the key/value pairs
|
||||
// that differ from one another. It also skips value comparison for a set of provided prefixes.
|
||||
func DiffKVStores(a, b storetypes.KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []kv.Pair) {
|
||||
func DiffKVStores(a, b storetypes.KVStore, prefixesToSkip [][]byte) (diffA, diffB []kv.Pair) {
|
||||
iterA := a.Iterator(nil, nil)
|
||||
|
||||
defer iterA.Close()
|
||||
|
||||
iterB := b.Iterator(nil, nil)
|
||||
|
||||
defer iterB.Close()
|
||||
|
||||
for {
|
||||
if !iterA.Valid() && !iterB.Valid() {
|
||||
return kvAs, kvBs
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(1)
|
||||
kvAs := make([]kv.Pair, 0)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
kvAs = getKVPairs(iterA, prefixesToSkip)
|
||||
}()
|
||||
|
||||
wg.Add(1)
|
||||
kvBs := make([]kv.Pair, 0)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
kvBs = getKVPairs(iterB, prefixesToSkip)
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if len(kvAs) != len(kvBs) {
|
||||
fmt.Printf("KV stores are different: %d key/value pairs in store A and %d key/value pairs in store B\n", len(kvAs), len(kvBs))
|
||||
}
|
||||
|
||||
return getDiffFromKVPair(kvAs, kvBs)
|
||||
}
|
||||
|
||||
// getDiffFromKVPair compares two KVstores and returns all the key/value pairs
|
||||
func getDiffFromKVPair(kvAs, kvBs []kv.Pair) (diffA, diffB []kv.Pair) {
|
||||
// we assume that kvBs is equal or larger than kvAs
|
||||
// if not, we swap the two
|
||||
if len(kvAs) > len(kvBs) {
|
||||
kvAs, kvBs = kvBs, kvAs
|
||||
// we need to swap the diffA and diffB as well
|
||||
defer func() {
|
||||
diffA, diffB = diffB, diffA
|
||||
}()
|
||||
}
|
||||
|
||||
// in case kvAs is empty we can return early
|
||||
// since there is nothing to compare
|
||||
// if kvAs == kvBs, then diffA and diffB will be empty
|
||||
if len(kvAs) == 0 {
|
||||
return []kv.Pair{}, kvBs
|
||||
}
|
||||
|
||||
index := make(map[string][]byte, len(kvBs))
|
||||
for _, kv := range kvBs {
|
||||
index[string(kv.Key)] = kv.Value
|
||||
}
|
||||
|
||||
for _, kvA := range kvAs {
|
||||
if kvBValue, ok := index[string(kvA.Key)]; !ok {
|
||||
diffA = append(diffA, kvA)
|
||||
diffB = append(diffB, kv.Pair{Key: kvA.Key}) // the key is missing from kvB so we append a pair with an empty value
|
||||
} else if !bytes.Equal(kvA.Value, kvBValue) {
|
||||
diffA = append(diffA, kvA)
|
||||
diffB = append(diffB, kv.Pair{Key: kvA.Key, Value: kvBValue})
|
||||
} else {
|
||||
// values are equal, so we remove the key from the index
|
||||
delete(index, string(kvA.Key))
|
||||
}
|
||||
}
|
||||
|
||||
var kvA, kvB kv.Pair
|
||||
if iterA.Valid() {
|
||||
kvA = kv.Pair{Key: iterA.Key(), Value: iterA.Value()}
|
||||
// add the remaining keys from kvBs
|
||||
for key, value := range index {
|
||||
diffA = append(diffA, kv.Pair{Key: []byte(key)}) // the key is missing from kvA so we append a pair with an empty value
|
||||
diffB = append(diffB, kv.Pair{Key: []byte(key), Value: value})
|
||||
}
|
||||
|
||||
iterA.Next()
|
||||
}
|
||||
return diffA, diffB
|
||||
}
|
||||
|
||||
if iterB.Valid() {
|
||||
kvB = kv.Pair{Key: iterB.Key(), Value: iterB.Value()}
|
||||
}
|
||||
|
||||
compareValue := true
|
||||
func getKVPairs(iter dbm.Iterator, prefixesToSkip [][]byte) (kvs []kv.Pair) {
|
||||
for iter.Valid() {
|
||||
key, value := iter.Key(), iter.Value()
|
||||
|
||||
// do not add the KV pair if the key is prefixed to be skipped.
|
||||
skip := false
|
||||
for _, prefix := range prefixesToSkip {
|
||||
// Skip value comparison if we matched a prefix
|
||||
if bytes.HasPrefix(kvA.Key, prefix) {
|
||||
compareValue = false
|
||||
if bytes.HasPrefix(key, prefix) {
|
||||
skip = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !compareValue {
|
||||
// We're skipping this key due to an exclusion prefix. If it's present in B, iterate past it. If it's
|
||||
// absent don't iterate.
|
||||
if bytes.Equal(kvA.Key, kvB.Key) {
|
||||
iterB.Next()
|
||||
}
|
||||
continue
|
||||
if !skip {
|
||||
kvs = append(kvs, kv.Pair{Key: key, Value: value})
|
||||
}
|
||||
|
||||
// always iterate B when comparing
|
||||
iterB.Next()
|
||||
|
||||
if !bytes.Equal(kvA.Key, kvB.Key) || !bytes.Equal(kvA.Value, kvB.Value) {
|
||||
kvAs = append(kvAs, kvA)
|
||||
kvBs = append(kvBs, kvB)
|
||||
}
|
||||
iter.Next()
|
||||
}
|
||||
|
||||
return kvs
|
||||
}
|
||||
|
||||
@@ -4,17 +4,16 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/store/metrics"
|
||||
"cosmossdk.io/store/rootmulti"
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/store/metrics"
|
||||
"cosmossdk.io/store/rootmulti"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/types/kv"
|
||||
"github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
@@ -62,24 +61,30 @@ func TestDiffKVStores(t *testing.T) {
|
||||
store1.Set(k1, v1)
|
||||
store2.Set(k1, v1)
|
||||
|
||||
checkDiffResults(t, store1, store2)
|
||||
checkDiffResults(t, store1, store2, true, nil)
|
||||
|
||||
// delete k1 from store2, which is now empty
|
||||
store2.Delete(k1)
|
||||
checkDiffResults(t, store1, store2)
|
||||
checkDiffResults(t, store1, store2, false, nil)
|
||||
|
||||
// set k1 in store2, different value than what store1 holds for k1
|
||||
v2 := []byte("v2")
|
||||
store2.Set(k1, v2)
|
||||
checkDiffResults(t, store1, store2)
|
||||
checkDiffResults(t, store1, store2, false, nil)
|
||||
|
||||
// add k2 to store2
|
||||
k2 := []byte("k2")
|
||||
store2.Set(k2, v2)
|
||||
checkDiffResults(t, store1, store2)
|
||||
checkDiffResults(t, store1, store2, false, nil)
|
||||
|
||||
// add k3 to store1
|
||||
k3 := []byte("k3")
|
||||
store1.Set(k3, v2)
|
||||
checkDiffResults(t, store1, store2, false, nil)
|
||||
|
||||
// Reset stores
|
||||
store1.Delete(k1)
|
||||
store1.Delete(k3)
|
||||
store2.Delete(k1)
|
||||
store2.Delete(k2)
|
||||
|
||||
@@ -88,14 +93,20 @@ func TestDiffKVStores(t *testing.T) {
|
||||
k1Prefixed := append(prefix, k1...)
|
||||
store1.Set(k1Prefixed, v1)
|
||||
store2.Set(k1Prefixed, v2)
|
||||
checkDiffResults(t, store1, store2)
|
||||
checkDiffResults(t, store1, store2, true, [][]byte{prefix})
|
||||
}
|
||||
|
||||
func checkDiffResults(t *testing.T, store1, store2 storetypes.KVStore) {
|
||||
kvAs1, kvBs1 := DiffKVStores(store1, store2, nil)
|
||||
kvAs2, kvBs2 := DiffKVStores(store1, store2, nil)
|
||||
assert.DeepEqual(t, kvAs1, kvAs2)
|
||||
assert.DeepEqual(t, kvBs1, kvBs2)
|
||||
func checkDiffResults(t *testing.T, store1, store2 storetypes.KVStore, noDiff bool, skipPrefixes [][]byte) {
|
||||
t.Helper()
|
||||
|
||||
kvAs1, kvBs1 := DiffKVStores(store1, store2, skipPrefixes)
|
||||
|
||||
if noDiff {
|
||||
assert.Assert(t, len(kvAs1) == 0)
|
||||
assert.Assert(t, len(kvBs1) == 0)
|
||||
} else {
|
||||
assert.Assert(t, len(kvAs1) > 0 || len(kvBs1) > 0)
|
||||
}
|
||||
}
|
||||
|
||||
func initTestStores(t *testing.T) (storetypes.KVStore, storetypes.KVStore) {
|
||||
|
||||
Reference in New Issue
Block a user