cosmos-sdk/simsx/registry_test.go
Alexander Peters cf721a6540
feat(sims): Integration with app v2 (#23013)
Co-authored-by: Alex | Interchain Labs <alex@skip.money>
2025-01-09 08:19:35 +00:00

212 lines
7.6 KiB
Go

package simsx
import (
"context"
"errors"
"math/rand"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"cosmossdk.io/log"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
)
func TestSimsMsgRegistryAdapter(t *testing.T) {
senderAcc := SimAccountFixture()
accs := []simtypes.Account{senderAcc.Account}
ak := MockAccountSourceX{GetAccountFn: MemoryAccountSource(senderAcc).GetAccount}
myMsg := testdata.NewTestMsg(senderAcc.Address)
ctx := sdk.Context{}.WithContext(context.Background())
futureTime := time.Now().Add(time.Second)
specs := map[string]struct {
factory SimMsgFactoryX
expFactoryMsg sdk.Msg
expFactoryErr error
expDeliveryErr error
expFutureOpsCount int
}{
"successful execution": {
factory: SimMsgFactoryFn[*testdata.TestMsg](func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg *testdata.TestMsg) {
return []SimAccount{senderAcc}, myMsg
}),
expFactoryMsg: myMsg,
},
"skip execution": {
factory: SimMsgFactoryFn[*testdata.TestMsg](func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg *testdata.TestMsg) {
reporter.Skip("testing")
return nil, nil
}),
},
"future ops registration": {
factory: NewSimMsgFactoryWithFutureOps[*testdata.TestMsg](func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter, fOpsReg FutureOpsRegistry) (signer []SimAccount, msg *testdata.TestMsg) {
fOpsReg.Add(futureTime, SimMsgFactoryFn[*testdata.TestMsg](func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg *testdata.TestMsg) {
return []SimAccount{senderAcc}, myMsg
}))
return []SimAccount{senderAcc}, myMsg
}),
expFactoryMsg: myMsg,
expFutureOpsCount: 1,
},
"error in factory execution": {
factory: NewSimMsgFactoryWithFutureOps[*testdata.TestMsg](func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter, fOpsReg FutureOpsRegistry) (signer []SimAccount, msg *testdata.TestMsg) {
reporter.Fail(errors.New("testing"))
return nil, nil
}),
expFactoryErr: errors.New("testing"),
},
"missing senders": {
factory: SimMsgFactoryFn[*testdata.TestMsg](func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg *testdata.TestMsg) {
return nil, myMsg
}),
expDeliveryErr: errors.New("no senders"),
},
"error in delivery execution": {
factory: SimMsgFactoryFn[*testdata.TestMsg](func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg *testdata.TestMsg) {
return []SimAccount{senderAcc}, myMsg
}),
expDeliveryErr: errors.New("testing"),
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
r := NewBasicSimulationReporter()
reg := NewSimsMsgRegistryAdapter(r, ak, nil, txConfig(), log.NewNopLogger())
// when
reg.Add(100, spec.factory)
// then
gotOps := reg.ToLegacyObjects()
require.Len(t, gotOps, 1)
assert.Equal(t, 100, gotOps[0].Weight())
// and when ops executed
var capturedTXs []sdk.Tx
captureTXApp := AppEntrypointFn(func(_txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) {
capturedTXs = append(capturedTXs, tx)
return sdk.GasInfo{}, &sdk.Result{}, spec.expDeliveryErr
})
fn := gotOps[0].Op()
gotOpsResult, gotFOps, gotErr := fn(rand.New(rand.NewSource(1)), captureTXApp, ctx, accs, "testchain")
// then
if spec.expFactoryErr != nil {
require.Equal(t, spec.expFactoryErr, gotErr)
assert.Empty(t, gotFOps)
assert.Equal(t, gotOpsResult.OK, spec.expFactoryErr == nil)
assert.Empty(t, gotOpsResult.Comment)
require.Empty(t, capturedTXs)
}
if spec.expDeliveryErr != nil {
require.Equal(t, spec.expDeliveryErr, gotErr)
}
// and verify TX delivery
if spec.expFactoryMsg != nil {
require.Len(t, capturedTXs, 1)
require.Len(t, capturedTXs[0].GetMsgs(), 1)
assert.Equal(t, spec.expFactoryMsg, capturedTXs[0].GetMsgs()[0])
}
assert.Len(t, gotFOps, spec.expFutureOpsCount)
})
}
}
func TestUniqueTypeRegistry(t *testing.T) {
exampleFactory := SimMsgFactoryFn[*testdata.TestMsg](func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg *testdata.TestMsg) {
return []SimAccount{}, nil
})
exampleFactory2 := SimMsgFactoryFn[*testdata.MsgCreateDog](func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg *testdata.MsgCreateDog) {
return []SimAccount{}, nil
})
specs := map[string]struct {
src []WeightedFactory
exp []WeightedFactoryMethod
expErr bool
}{
"unique": {
src: []WeightedFactory{{Weight: 1, Factory: exampleFactory}},
exp: []WeightedFactoryMethod{{Weight: 1, Factory: exampleFactory.Create()}},
},
"sorted": {
src: []WeightedFactory{{Weight: 2, Factory: exampleFactory2}, {Weight: 1, Factory: exampleFactory}},
exp: []WeightedFactoryMethod{{Weight: 1, Factory: exampleFactory.Create()}, {Weight: 2, Factory: exampleFactory2.Create()}},
},
"duplicate": {
src: []WeightedFactory{{Weight: 1, Factory: exampleFactory}, {Weight: 2, Factory: exampleFactory}},
expErr: true,
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
reg := NewUniqueTypeRegistry()
if spec.expErr {
require.Panics(t, func() {
for _, v := range spec.src {
reg.Add(v.Weight, v.Factory)
}
})
return
}
for _, v := range spec.src {
reg.Add(v.Weight, v.Factory)
}
// then
got := readAll(reg.Iterator())
require.Len(t, got, len(spec.exp))
})
}
}
func TestWeightedFactories(t *testing.T) {
r := NewWeightedFactoryMethods()
f1 := func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg sdk.Msg) {
panic("not implemented")
}
f2 := func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg sdk.Msg) {
panic("not implemented")
}
r.Add(1, f1)
r.Add(2, f2)
got := readAll(r.Iterator())
require.Len(t, got, 2)
assert.Equal(t, uint32(1), r[0].Weight)
assert.Equal(t, uint32(2), r[1].Weight)
}
func TestAppendIterators(t *testing.T) {
r1 := NewWeightedFactoryMethods()
r1.Add(2, func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg sdk.Msg) {
panic("not implemented")
})
r1.Add(2, func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg sdk.Msg) {
panic("not implemented")
})
r1.Add(3, func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg sdk.Msg) {
panic("not implemented")
})
r2 := NewUniqueTypeRegistry()
r2.Add(1, SimMsgFactoryFn[*testdata.TestMsg](func(ctx context.Context, testData *ChainDataSource, reporter SimulationReporter) (signer []SimAccount, msg *testdata.TestMsg) {
panic("not implemented")
}))
// when
all := readAll(AppendIterators(r1.Iterator(), r2.Iterator()))
// then
require.Len(t, all, 4)
gotWeights := Collect(all, func(a WeightedFactoryMethod) uint32 { return a.Weight })
assert.Equal(t, []uint32{2, 2, 3, 1}, gotWeights)
}
func readAll(iterator WeightedProposalMsgIter) []WeightedFactoryMethod {
var ret []WeightedFactoryMethod
for w, f := range iterator {
ret = append(ret, WeightedFactoryMethod{Weight: w, Factory: f})
}
return ret
}