Skip to content

Commit 5d482fc

Browse files
authored
Merge pull request #140 from CosmWasm/real-contract-migrations-test
Add integration tests with updated wasm contracts
2 parents 46b2cad + 21df300 commit 5d482fc

File tree

1 file changed

+160
-27
lines changed

1 file changed

+160
-27
lines changed

x/wasm/internal/keeper/keeper_test.go

+160-27
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package keeper
22

33
import (
44
"bytes"
5+
"encoding/base64"
56
"encoding/binary"
67
"encoding/json"
78
"io/ioutil"
@@ -461,9 +462,8 @@ func TestMigrate(t *testing.T) {
461462
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
462463

463464
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
464-
topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
465465
creator := createFakeFundedAccount(ctx, accKeeper, deposit.Add(deposit...))
466-
fred := createFakeFundedAccount(ctx, accKeeper, topUp)
466+
fred := createFakeFundedAccount(ctx, accKeeper, sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)))
467467

468468
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
469469
require.NoError(t, err)
@@ -475,41 +475,56 @@ func TestMigrate(t *testing.T) {
475475
require.NotEqual(t, originalContractID, newContractID)
476476

477477
_, _, anyAddr := keyPubAddr()
478+
_, _, newVerifierAddr := keyPubAddr()
478479
initMsg := InitMsg{
479480
Verifier: fred,
480481
Beneficiary: anyAddr,
481482
}
482483
initMsgBz, err := json.Marshal(initMsg)
483484
require.NoError(t, err)
485+
486+
migMsg := struct {
487+
Verifier sdk.AccAddress `json:"verifier"`
488+
}{Verifier: newVerifierAddr}
489+
migMsgBz, err := json.Marshal(migMsg)
490+
require.NoError(t, err)
491+
484492
specs := map[string]struct {
485493
admin sdk.AccAddress
486494
overrideContractAddr sdk.AccAddress
487495
caller sdk.AccAddress
488496
codeID uint64
489497
migrateMsg []byte
490498
expErr *sdkerrors.Error
499+
expVerifier sdk.AccAddress
491500
}{
492501
"all good with same code id": {
493-
admin: creator,
494-
caller: creator,
495-
codeID: originalContractID,
502+
admin: creator,
503+
caller: creator,
504+
codeID: originalContractID,
505+
migrateMsg: migMsgBz,
506+
expVerifier: newVerifierAddr,
496507
},
497-
"all good with new code id": {
498-
admin: creator,
499-
caller: creator,
500-
codeID: newContractID,
508+
"all good with different code id": {
509+
admin: creator,
510+
caller: creator,
511+
codeID: newContractID,
512+
migrateMsg: migMsgBz,
513+
expVerifier: newVerifierAddr,
501514
},
502515
"all good with admin set": {
503-
admin: fred,
504-
caller: fred,
505-
codeID: newContractID,
516+
admin: fred,
517+
caller: fred,
518+
codeID: newContractID,
519+
migrateMsg: migMsgBz,
520+
expVerifier: newVerifierAddr,
506521
},
507522
"prevent migration when admin was not set on instantiate": {
508523
caller: creator,
509524
codeID: originalContractID,
510525
expErr: sdkerrors.ErrUnauthorized,
511526
},
512-
"prevent migration when not admin": {
527+
"prevent migration when not sent by admin": {
513528
caller: creator,
514529
admin: fred,
515530
codeID: originalContractID,
@@ -528,18 +543,21 @@ func TestMigrate(t *testing.T) {
528543
codeID: originalContractID,
529544
expErr: sdkerrors.ErrInvalidRequest,
530545
},
531-
"fail when migration caused error": {
546+
"fail in contract with invalid migrate msg": {
532547
admin: creator,
533548
caller: creator,
534549
codeID: originalContractID,
535-
migrateMsg: bytes.Repeat([]byte{0x1}, 7), // condition hard coded in stub: >6 = error
550+
migrateMsg: bytes.Repeat([]byte{0x1}, 7),
536551
expErr: types.ErrMigrationFailed,
537552
},
553+
"fail in contract without migrate msg": {
554+
admin: creator,
555+
caller: creator,
556+
codeID: originalContractID,
557+
expErr: types.ErrMigrationFailed,
558+
},
538559
}
539-
var (
540-
builtIntoGoCosmWasmStubGas = sdk.Gas(10000)
541-
builtIntoGoCosmWasmStubData = []byte(("my-migration-response-data"))
542-
)
560+
543561
for msg, spec := range specs {
544562
t.Run(msg, func(t *testing.T) {
545563
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
@@ -548,26 +566,141 @@ func TestMigrate(t *testing.T) {
548566
if spec.overrideContractAddr != nil {
549567
addr = spec.overrideContractAddr
550568
}
551-
gasBefore := ctx.GasMeter().GasConsumed()
552-
res, err := keeper.Migrate(ctx, addr, spec.caller, spec.codeID, spec.migrateMsg)
569+
_, err = keeper.Migrate(ctx, addr, spec.caller, spec.codeID, spec.migrateMsg)
553570
require.True(t, spec.expErr.Is(err), "expected %v but got %+v", spec.expErr, err)
554571
if spec.expErr != nil {
555572
return
556573
}
557-
gasAfter := ctx.GasMeter().GasConsumed()
558-
assert.Greater(t, gasAfter-gasBefore, builtIntoGoCosmWasmStubGas/GasMultiplier)
559-
assert.Equal(t, builtIntoGoCosmWasmStubData, res.Data)
560574
cInfo := keeper.GetContractInfo(ctx, addr)
561575
assert.Equal(t, spec.codeID, cInfo.CodeID)
562576
assert.Equal(t, originalContractID, cInfo.PreviousCodeID)
563577
assert.Equal(t, types.NewCreatedAt(ctx), cInfo.LastUpdated)
564-
// TODO: check contract store was updated by migration code (impl also in contract)
565-
// TODO: check any messages dispatched proper
566-
// TODO: check events?
578+
579+
m := keeper.QueryRaw(ctx, addr, []byte("config"))
580+
require.Len(t, m, 1)
581+
var stored map[string][]byte
582+
require.NoError(t, json.Unmarshal(m[0].Value, &stored))
583+
require.Contains(t, stored, "verifier")
584+
require.NoError(t, err)
585+
assert.Equal(t, spec.expVerifier, sdk.AccAddress(stored["verifier"]))
567586
})
568587
}
569588
}
570589

590+
func TestMigrateWithDispatchedMessage(t *testing.T) {
591+
tempDir, err := ioutil.TempDir("", "wasm")
592+
require.NoError(t, err)
593+
defer os.RemoveAll(tempDir)
594+
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
595+
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
596+
597+
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
598+
creator := createFakeFundedAccount(ctx, accKeeper, deposit.Add(deposit...))
599+
fred := createFakeFundedAccount(ctx, accKeeper, sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)))
600+
601+
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
602+
require.NoError(t, err)
603+
burnerCode, err := ioutil.ReadFile("./testdata/burner.wasm")
604+
require.NoError(t, err)
605+
606+
originalContractID, err := keeper.Create(ctx, creator, wasmCode, "", "")
607+
require.NoError(t, err)
608+
burnerContractID, err := keeper.Create(ctx, creator, burnerCode, "", "")
609+
require.NoError(t, err)
610+
require.NotEqual(t, originalContractID, burnerContractID)
611+
612+
_, _, myPayoutAddr := keyPubAddr()
613+
initMsg := InitMsg{
614+
Verifier: fred,
615+
Beneficiary: fred,
616+
}
617+
initMsgBz, err := json.Marshal(initMsg)
618+
require.NoError(t, err)
619+
620+
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
621+
contractAddr, err := keeper.Instantiate(ctx, originalContractID, creator, fred, initMsgBz, "demo contract", deposit)
622+
require.NoError(t, err)
623+
624+
migMsg := struct {
625+
Payout sdk.AccAddress `json:"payout"`
626+
}{Payout: myPayoutAddr}
627+
migMsgBz, err := json.Marshal(migMsg)
628+
require.NoError(t, err)
629+
ctx = ctx.WithEventManager(sdk.NewEventManager()).WithBlockHeight(ctx.BlockHeight() + 1)
630+
res, err := keeper.Migrate(ctx, contractAddr, fred, burnerContractID, migMsgBz)
631+
require.NoError(t, err)
632+
dataBz, err := base64.StdEncoding.DecodeString(string(res.Data))
633+
require.NoError(t, err)
634+
assert.Equal(t, "burnt", string(dataBz))
635+
assert.Equal(t, "", res.Log)
636+
type dict map[string]interface{}
637+
expEvents := []dict{
638+
{
639+
"Type": "wasm",
640+
"Attr": []dict{
641+
{"contract_address": contractAddr},
642+
{"action": "burn"},
643+
{"payout": myPayoutAddr},
644+
},
645+
},
646+
{
647+
"Type": "transfer",
648+
"Attr": []dict{
649+
{"recipient": myPayoutAddr},
650+
{"sender": contractAddr},
651+
{"amount": "100000denom"},
652+
},
653+
},
654+
{
655+
"Type": "message",
656+
"Attr": []dict{
657+
{"sender": contractAddr},
658+
},
659+
},
660+
{
661+
"Type": "message",
662+
"Attr": []dict{
663+
{"module": "bank"},
664+
},
665+
},
666+
}
667+
expJsonEvts := string(mustMarshal(t, expEvents))
668+
assert.JSONEq(t, expJsonEvts, prettyEvents(t, ctx.EventManager().Events()))
669+
670+
// all persistent data cleared
671+
m := keeper.QueryRaw(ctx, contractAddr, []byte("config"))
672+
require.Len(t, m, 0)
673+
674+
// and all deposit tokens sent to myPayoutAddr
675+
balance := accKeeper.GetAccount(ctx, myPayoutAddr).GetCoins()
676+
assert.Equal(t, deposit, balance)
677+
}
678+
679+
func prettyEvents(t *testing.T, events sdk.Events) string {
680+
t.Helper()
681+
type prettyEvent struct {
682+
Type string
683+
Attr []map[string]string
684+
}
685+
686+
r := make([]prettyEvent, len(events))
687+
for i, e := range events {
688+
attr := make([]map[string]string, len(e.Attributes))
689+
for j, a := range e.Attributes {
690+
attr[j] = map[string]string{string(a.Key): string(a.Value)}
691+
}
692+
r[i] = prettyEvent{Type: e.Type, Attr: attr}
693+
}
694+
return string(mustMarshal(t, r))
695+
}
696+
697+
func mustMarshal(t *testing.T, r interface{}) []byte {
698+
t.Helper()
699+
bz, err := json.Marshal(r)
700+
require.NoError(t, err)
701+
return bz
702+
}
703+
571704
func TestUpdateContractAdmin(t *testing.T) {
572705
tempDir, err := ioutil.TempDir("", "wasm")
573706
require.NoError(t, err)

0 commit comments

Comments
 (0)