-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
28c29bb
commit df1f891
Showing
4 changed files
with
524 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package grpc | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/cosmos/gogoproto/proto" | ||
"github.com/stretchr/testify/require" | ||
protov2 "google.golang.org/protobuf/proto" | ||
"google.golang.org/protobuf/types/known/anypb" | ||
) | ||
|
||
type mockInterfaceRegistry struct{} | ||
|
||
func (m mockInterfaceRegistry) Resolve(typeUrl string) (interface { | ||
ProtoMessage() | ||
Reset() | ||
String() string | ||
}, error) { | ||
return nil, nil | ||
} | ||
|
||
func (m mockInterfaceRegistry) RegisterInterface(string, interface{}, ...interface{}) {} | ||
func (m mockInterfaceRegistry) RegisterImplementations(interface{}, ...interface{}) {} | ||
func (m mockInterfaceRegistry) ListAllInterfaces() []string { return nil } | ||
func (m mockInterfaceRegistry) ListImplementations(string) []string { return nil } | ||
func (m mockInterfaceRegistry) UnpackAny(*anypb.Any, interface{}) error { return nil } | ||
|
||
func TestProtoCodec_Marshal(t *testing.T) { | ||
registry := mockInterfaceRegistry{} | ||
codec := newProtoCodec(registry) | ||
|
||
tests := []struct { | ||
name string | ||
input proto.Message | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "nil message", | ||
input: nil, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "empty message", | ||
input: &anypb.Any{}, | ||
wantErr: false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
bz, err := codec.Marshal(tt.input) | ||
if tt.wantErr { | ||
require.Error(t, err) | ||
return | ||
} | ||
require.NoError(t, err) | ||
if tt.input == nil { | ||
require.Empty(t, bz) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestGRPCCodec_Marshal(t *testing.T) { | ||
registry := mockInterfaceRegistry{} | ||
pc := newProtoCodec(registry) | ||
codec := pc.GRPCCodec() | ||
|
||
tests := []struct { | ||
name string | ||
input interface{} | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "protov2 message", | ||
input: &anypb.Any{}, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "invalid type", | ||
input: "not a proto message", | ||
wantErr: true, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
bz, err := codec.Marshal(tt.input) | ||
if tt.wantErr { | ||
require.Error(t, err) | ||
require.ErrorIs(t, err, errUnknownProtoType) | ||
return | ||
} | ||
require.NoError(t, err) | ||
require.NotNil(t, bz) | ||
}) | ||
} | ||
} | ||
|
||
func TestGRPCCodec_Unmarshal(t *testing.T) { | ||
registry := mockInterfaceRegistry{} | ||
pc := newProtoCodec(registry) | ||
codec := pc.GRPCCodec() | ||
|
||
msg := &anypb.Any{} | ||
bz, err := protov2.Marshal(msg) | ||
require.NoError(t, err) | ||
|
||
tests := []struct { | ||
name string | ||
data []byte | ||
msg interface{} | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "protov2 message", | ||
data: bz, | ||
msg: &anypb.Any{}, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "invalid type", | ||
data: bz, | ||
msg: &struct{}{}, | ||
wantErr: true, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
err := codec.Unmarshal(tt.data, tt.msg) | ||
if tt.wantErr { | ||
require.Error(t, err) | ||
require.ErrorIs(t, err, errUnknownProtoType) | ||
return | ||
} | ||
require.NoError(t, err) | ||
}) | ||
} | ||
} | ||
|
||
func TestCodecName(t *testing.T) { | ||
registry := mockInterfaceRegistry{} | ||
pc := newProtoCodec(registry) | ||
require.Equal(t, "cosmos-sdk-grpc-codec", pc.Name()) | ||
|
||
grpcCodec := pc.GRPCCodec() | ||
require.Equal(t, "cosmos-sdk-grpc-codec", grpcCodec.Name()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package grpc | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
appmodulev2 "cosmossdk.io/core/appmodule/v2" | ||
"cosmossdk.io/core/transaction" | ||
"cosmossdk.io/log" | ||
"github.com/stretchr/testify/assert" | ||
"google.golang.org/grpc/metadata" | ||
) | ||
|
||
func TestGetHeightFromCtx(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
ctx context.Context | ||
wantHeight uint64 | ||
wantErr bool | ||
errContains string | ||
}{ | ||
{ | ||
name: "no metadata returns zero height", | ||
ctx: context.Background(), | ||
wantHeight: 0, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "valid height", | ||
ctx: metadata.NewIncomingContext( | ||
context.Background(), | ||
metadata.Pairs(BlockHeightHeader, "100"), | ||
), | ||
wantHeight: 100, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "invalid height format", | ||
ctx: metadata.NewIncomingContext( | ||
context.Background(), | ||
metadata.Pairs(BlockHeightHeader, "invalid"), | ||
), | ||
wantHeight: 0, | ||
wantErr: true, | ||
errContains: "unable to parse height", | ||
}, | ||
{ | ||
name: "multiple height values", | ||
ctx: metadata.NewIncomingContext( | ||
context.Background(), | ||
metadata.Pairs(BlockHeightHeader, "100", BlockHeightHeader, "200"), | ||
), | ||
wantHeight: 0, | ||
wantErr: true, | ||
errContains: "must be of length 1", | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
height, err := getHeightFromCtx(tt.ctx) | ||
if tt.wantErr { | ||
assert.ErrorContains(t, err, tt.errContains) | ||
return | ||
} | ||
if err != nil { | ||
t.Fatalf("unexpected error: %v", err) | ||
} | ||
if height != tt.wantHeight { | ||
t.Errorf("height = %v, want %v", height, tt.wantHeight) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestServerConfig(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
cfgOptions []CfgOption | ||
wantAddress string | ||
}{ | ||
{ | ||
name: "default config", | ||
cfgOptions: nil, | ||
wantAddress: "localhost:9090", | ||
}, | ||
{ | ||
name: "custom address", | ||
cfgOptions: []CfgOption{ | ||
func(cfg *Config) { | ||
cfg.Address = "localhost:8080" | ||
}, | ||
}, | ||
wantAddress: "localhost:8080", | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
srv := NewWithConfigOptions[transaction.Tx](tt.cfgOptions...) | ||
cfg := srv.Config().(*Config) | ||
if cfg.Address != tt.wantAddress { | ||
t.Errorf("address = %v, want %v", cfg.Address, tt.wantAddress) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestNewServer(t *testing.T) { | ||
logger := log.NewNopLogger() | ||
handlers := make(map[string]appmodulev2.Handler) | ||
queryable := func(ctx context.Context, version uint64, msg transaction.Msg) (transaction.Msg, error) { | ||
return msg, nil | ||
} | ||
|
||
srv, err := New[transaction.Tx]( | ||
logger, | ||
nil, | ||
handlers, | ||
queryable, | ||
nil, | ||
) | ||
|
||
if err != nil { | ||
t.Fatalf("failed to create server: %v", err) | ||
} | ||
|
||
if srv.Name() != ServerName { | ||
t.Errorf("server name = %v, want %v", srv.Name(), ServerName) | ||
} | ||
} |
Oops, something went wrong.