github.com/cosmos/cosmos-sdk@v0.50.10/server/mock/app.go (about) 1 package mock 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "path/filepath" 9 10 abci "github.com/cometbft/cometbft/abci/types" 11 db "github.com/cosmos/cosmos-db" 12 "google.golang.org/grpc" 13 "google.golang.org/protobuf/proto" 14 "google.golang.org/protobuf/reflect/protodesc" 15 "google.golang.org/protobuf/reflect/protoregistry" 16 "google.golang.org/protobuf/types/descriptorpb" 17 18 "cosmossdk.io/log" 19 storetypes "cosmossdk.io/store/types" 20 21 bam "github.com/cosmos/cosmos-sdk/baseapp" 22 "github.com/cosmos/cosmos-sdk/codec" 23 "github.com/cosmos/cosmos-sdk/codec/testutil" 24 servertypes "github.com/cosmos/cosmos-sdk/server/types" 25 sdk "github.com/cosmos/cosmos-sdk/types" 26 genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" 27 ) 28 29 // NewApp creates a simple mock kvstore app for testing. It should work 30 // similar to a real app. Make sure rootDir is empty before running the test, 31 // in order to guarantee consistent results. 32 func NewApp(rootDir string, logger log.Logger) (servertypes.ABCI, error) { 33 db, err := db.NewGoLevelDB("mock", filepath.Join(rootDir, "data"), nil) 34 if err != nil { 35 return nil, err 36 } 37 38 capKeyMainStore := storetypes.NewKVStoreKey("main") 39 40 baseApp := bam.NewBaseApp("kvstore", logger, db, decodeTx) 41 baseApp.MountStores(capKeyMainStore) 42 baseApp.SetInitChainer(InitChainer(capKeyMainStore)) 43 44 interfaceRegistry := testutil.CodecOptions{}.NewInterfaceRegistry() 45 interfaceRegistry.RegisterImplementations((*sdk.Msg)(nil), &KVStoreTx{}) 46 baseApp.SetInterfaceRegistry(interfaceRegistry) 47 48 router := bam.NewMsgServiceRouter() 49 router.SetInterfaceRegistry(interfaceRegistry) 50 51 newDesc := &grpc.ServiceDesc{ 52 ServiceName: "Test", 53 Methods: []grpc.MethodDesc{ 54 { 55 MethodName: "Test", 56 Handler: MsgTestHandler, 57 }, 58 }, 59 } 60 61 router.RegisterService(newDesc, &MsgServerImpl{capKeyMainStore}) 62 baseApp.SetMsgServiceRouter(router) 63 64 if err := baseApp.LoadLatestVersion(); err != nil { 65 return nil, err 66 } 67 68 return baseApp, nil 69 } 70 71 // KVStoreHandler is a simple handler that takes KVStoreTx and writes 72 // them to the db. 73 func KVStoreHandler(storeKey storetypes.StoreKey) bam.MsgServiceHandler { 74 return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 75 dTx, ok := msg.(*KVStoreTx) 76 if !ok { 77 return nil, errors.New("KVStoreHandler should only receive KVStoreTx") 78 } 79 80 key := dTx.key 81 value := dTx.value 82 83 store := ctx.KVStore(storeKey) 84 store.Set(key, value) 85 86 return &sdk.Result{ 87 Log: fmt.Sprintf("set %s=%s", key, value), 88 }, nil 89 } 90 } 91 92 // basic KV structure 93 type KV struct { 94 Key string `json:"key"` 95 Value string `json:"value"` 96 } 97 98 // What Genesis JSON is formatted as 99 type GenesisJSON struct { 100 Values []KV `json:"values"` 101 } 102 103 // InitChainer returns a function that can initialize the chain 104 // with key/value pairs 105 func InitChainer(key storetypes.StoreKey) func(sdk.Context, *abci.RequestInitChain) (*abci.ResponseInitChain, error) { 106 return func(ctx sdk.Context, req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { 107 stateJSON := req.AppStateBytes 108 109 genesisState := new(GenesisJSON) 110 err := json.Unmarshal(stateJSON, genesisState) 111 if err != nil { 112 return &abci.ResponseInitChain{}, err 113 } 114 115 for _, val := range genesisState.Values { 116 store := ctx.KVStore(key) 117 store.Set([]byte(val.Key), []byte(val.Value)) 118 } 119 return &abci.ResponseInitChain{}, nil 120 } 121 } 122 123 // AppGenState can be passed into InitCmd, returns a static string of a few 124 // key-values that can be parsed by InitChainer 125 func AppGenState(_ *codec.LegacyAmino, _ genutiltypes.AppGenesis, _ []json.RawMessage) (appState json.RawMessage, err error) { 126 appState = json.RawMessage(`{ 127 "values": [ 128 { 129 "key": "hello", 130 "value": "goodbye" 131 }, 132 { 133 "key": "foo", 134 "value": "bar" 135 } 136 ] 137 }`) 138 return 139 } 140 141 // AppGenStateEmpty returns an empty transaction state for mocking. 142 func AppGenStateEmpty(_ *codec.LegacyAmino, _ genutiltypes.AppGenesis, _ []json.RawMessage) (appState json.RawMessage, err error) { 143 appState = json.RawMessage(``) 144 return 145 } 146 147 // Manually write the handlers for this custom message 148 type MsgServer interface { 149 Test(ctx context.Context, msg *KVStoreTx) (*sdk.Result, error) 150 } 151 152 type MsgServerImpl struct { 153 capKeyMainStore *storetypes.KVStoreKey 154 } 155 156 func MsgTestHandler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { // nolint: revive // refactor this in a followup pr 157 in := new(KVStoreTx) 158 if err := dec(in); err != nil { 159 return nil, err 160 } 161 if interceptor == nil { 162 return srv.(MsgServer).Test(ctx, in) 163 } 164 info := &grpc.UnaryServerInfo{ 165 Server: srv, 166 FullMethod: "/KVStoreTx", 167 } 168 handler := func(ctx context.Context, req interface{}) (interface{}, error) { 169 return srv.(MsgServer).Test(ctx, req.(*KVStoreTx)) 170 } 171 return interceptor(ctx, in, info, handler) 172 } 173 174 func (m MsgServerImpl) Test(ctx context.Context, msg *KVStoreTx) (*sdk.Result, error) { 175 return KVStoreHandler(m.capKeyMainStore)(sdk.UnwrapSDKContext(ctx), msg) 176 } 177 178 func init() { 179 err := registerFauxDescriptor() 180 if err != nil { 181 panic(err) 182 } 183 } 184 185 func registerFauxDescriptor() error { 186 fauxDescriptor, err := protodesc.NewFile(&descriptorpb.FileDescriptorProto{ 187 Name: proto.String("faux_proto/test.proto"), 188 Dependency: nil, 189 PublicDependency: nil, 190 WeakDependency: nil, 191 MessageType: []*descriptorpb.DescriptorProto{ 192 { 193 Name: proto.String("KVStoreTx"), 194 }, 195 }, 196 EnumType: nil, 197 Service: []*descriptorpb.ServiceDescriptorProto{ 198 { 199 Name: proto.String("Test"), 200 Method: []*descriptorpb.MethodDescriptorProto{ 201 { 202 Name: proto.String("Test"), 203 InputType: proto.String("KVStoreTx"), 204 OutputType: proto.String("KVStoreTx"), 205 }, 206 }, 207 }, 208 }, 209 Extension: nil, 210 Options: nil, 211 SourceCodeInfo: nil, 212 Syntax: nil, 213 Edition: nil, 214 }, nil) 215 if err != nil { 216 return err 217 } 218 219 return protoregistry.GlobalFiles.RegisterFile(fauxDescriptor) 220 }