cosmos-sdk/client/v2/autocli/common_test.go
2024-12-03 12:34:43 +00:00

240 lines
6.9 KiB
Go

package autocli
import (
"bytes"
"context"
"net"
"testing"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/protobuf/reflect/protoregistry"
"gotest.tools/v3/assert"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
reflectionv2alpha1 "cosmossdk.io/api/cosmos/base/reflection/v2alpha1"
"cosmossdk.io/client/v2/autocli/flag"
"cosmossdk.io/client/v2/internal/testpb"
"cosmossdk.io/x/bank"
banktypes "cosmossdk.io/x/bank/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/codec/testutil"
sdkkeyring "github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
)
type fixture struct {
conn *testClientConn
b *Builder
clientCtx client.Context
home string
chainID string
kBackend string
}
func initFixture(t *testing.T) *fixture {
t.Helper()
home := t.TempDir()
server := grpc.NewServer()
testpb.RegisterQueryServer(server, &testEchoServer{})
reflectionv2alpha1.RegisterReflectionServiceServer(server, &testReflectionServer{})
listener, err := net.Listen("tcp", "127.0.0.1:0")
assert.NilError(t, err)
go func() {
err := server.Serve(listener)
if err != nil {
panic(err)
}
}()
clientConn, err := grpc.NewClient(listener.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()))
assert.NilError(t, err)
encodingConfig := moduletestutil.MakeTestEncodingConfig(testutil.CodecOptions{}, bank.AppModule{})
kr, err := sdkkeyring.New(sdk.KeyringServiceName(), sdkkeyring.BackendMemory, home, nil, encodingConfig.Codec)
assert.NilError(t, err)
interfaceRegistry := encodingConfig.Codec.InterfaceRegistry()
banktypes.RegisterInterfaces(interfaceRegistry)
clientCtx := client.Context{}.
WithAddressCodec(interfaceRegistry.SigningContext().AddressCodec()).
WithValidatorAddressCodec(interfaceRegistry.SigningContext().ValidatorAddressCodec()).
WithConsensusAddressCodec(addresscodec.NewBech32Codec("cosmosvalcons")).
WithKeyring(kr).
WithKeyringDir(home).
WithHomeDir(home).
WithViper("").
WithInterfaceRegistry(interfaceRegistry).
WithTxConfig(encodingConfig.TxConfig).
WithAccountRetriever(client.MockAccountRetriever{}).
WithChainID("autocli-test")
conn := &testClientConn{ClientConn: clientConn}
b := &Builder{
Builder: flag.Builder{
TypeResolver: protoregistry.GlobalTypes,
FileResolver: protoregistry.GlobalFiles,
AddressCodec: clientCtx.AddressCodec,
ValidatorAddressCodec: clientCtx.ValidatorAddressCodec,
ConsensusAddressCodec: clientCtx.ConsensusAddressCodec,
},
GetClientConn: func(*cobra.Command) (grpc.ClientConnInterface, error) {
return conn, nil
},
AddQueryConnFlags: flags.AddQueryFlagsToCmd,
AddTxConnFlags: addTxAndGlobalFlagsToCmd,
Cdc: encodingConfig.Codec,
}
assert.NilError(t, b.ValidateAndComplete())
return &fixture{
conn: conn,
b: b,
clientCtx: clientCtx,
home: home,
chainID: "autocli-test",
kBackend: sdkkeyring.BackendMemory,
}
}
func addTxAndGlobalFlagsToCmd(cmd *cobra.Command) {
f := cmd.Flags()
f.String("home", "", "home directory")
flags.AddTxFlagsToCmd(cmd)
}
func runCmd(fixture *fixture, command func(moduleName string, f *fixture) (*cobra.Command, error), args ...string) (*bytes.Buffer, error) {
out := &bytes.Buffer{}
cmd, err := command("test", fixture)
if err != nil {
return out, err
}
cmd.SetArgs(args)
cmd.SetOut(out)
return out, cmd.Execute()
}
type testReflectionServer struct {
reflectionv2alpha1.UnimplementedReflectionServiceServer
}
func (t testReflectionServer) GetConfigurationDescriptor(_ context.Context, client *reflectionv2alpha1.GetConfigurationDescriptorRequest) (*reflectionv2alpha1.GetConfigurationDescriptorResponse, error) {
return &reflectionv2alpha1.GetConfigurationDescriptorResponse{
Config: &reflectionv2alpha1.ConfigurationDescriptor{
Bech32AccountAddressPrefix: "cosmos",
},
}, nil
}
var _ reflectionv2alpha1.ReflectionServiceServer = testReflectionServer{}
type testClientConn struct {
*grpc.ClientConn
lastRequest interface{}
lastResponse interface{}
}
func (t *testClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...grpc.CallOption) error {
err := t.ClientConn.Invoke(ctx, method, args, reply, opts...)
t.lastRequest = args
t.lastResponse = reply
return err
}
type testEchoServer struct {
testpb.UnimplementedQueryServer
}
func (t testEchoServer) Echo(_ context.Context, request *testpb.EchoRequest) (*testpb.EchoResponse, error) {
return &testpb.EchoResponse{Request: request}, nil
}
var _ testpb.QueryServer = testEchoServer{}
func TestEnhanceCommand(t *testing.T) {
b := &Builder{}
// Test that the command has a subcommand
cmd := &cobra.Command{Use: "test"}
cmd.AddCommand(&cobra.Command{Use: "test"})
for i := 0; i < 2; i++ {
cmdTp := cmdType(i)
appOptions := AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{
"test": {},
},
}
err := b.enhanceCommandCommon(cmd, cmdTp, appOptions, map[string]*cobra.Command{})
assert.NilError(t, err)
cmd = &cobra.Command{Use: "test"}
appOptions = AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{},
}
customCommands := map[string]*cobra.Command{
"test2": {Use: "test"},
}
err = b.enhanceCommandCommon(cmd, cmdTp, appOptions, customCommands)
assert.NilError(t, err)
cmd = &cobra.Command{Use: "test"}
appOptions = AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{
"test": {Tx: nil},
},
}
err = b.enhanceCommandCommon(cmd, cmdTp, appOptions, map[string]*cobra.Command{})
assert.NilError(t, err)
}
}
func TestErrorBuildCommand(t *testing.T) {
fixture := initFixture(t)
b := fixture.b
b.AddQueryConnFlags = nil
b.AddTxConnFlags = nil
commandDescriptor := &autocliv1.ServiceCommandDescriptor{
Service: testpb.Msg_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "Send",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{
ProtoField: "un-existent-proto-field",
},
},
},
},
}
appOptions := AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{
"test": {
Query: commandDescriptor,
Tx: commandDescriptor,
},
},
}
_, err := b.BuildMsgCommand(context.Background(), appOptions, nil)
assert.ErrorContains(t, err, "can't find field un-existent-proto-field")
appOptions.ModuleOptions["test"].Tx = &autocliv1.ServiceCommandDescriptor{Service: "un-existent-service"}
appOptions.ModuleOptions["test"].Query = &autocliv1.ServiceCommandDescriptor{Service: "un-existent-service"}
_, err = b.BuildMsgCommand(context.Background(), appOptions, nil)
assert.ErrorContains(t, err, "can't find service un-existent-service")
}