a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
183 lines
5.2 KiB
Go
183 lines
5.2 KiB
Go
package languages
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
// grpcStubEdge returns the single EdgeCalls edge tagged as a gRPC stub
|
|
// call, failing the test when zero or more than one is present.
|
|
func grpcStubEdge(t *testing.T, fix *extractedFixture) *graph.Edge {
|
|
t.Helper()
|
|
var found []*graph.Edge
|
|
for _, e := range fix.edgesByKind[graph.EdgeCalls] {
|
|
if e.Meta != nil && e.Meta["via"] == "grpc.stub" {
|
|
found = append(found, e)
|
|
}
|
|
}
|
|
require.Len(t, found, 1, "expected exactly one grpc.stub call edge")
|
|
return found[0]
|
|
}
|
|
|
|
func TestGoGRPC_InlineChainedStubCall(t *testing.T) {
|
|
fix := runGoExtract(t, `package client
|
|
|
|
import pb "example.com/proto"
|
|
|
|
func run(conn *grpc.ClientConn) {
|
|
pb.NewUserServiceClient(conn).GetUser(ctx, req)
|
|
}
|
|
`)
|
|
e := grpcStubEdge(t, fix)
|
|
assert.Equal(t, "pkg/foo.go::run", e.From)
|
|
assert.Equal(t, "unresolved::grpc::UserService::GetUser", e.To)
|
|
assert.Equal(t, "UserService", e.Meta["grpc_service"])
|
|
assert.Equal(t, "GetUser", e.Meta["grpc_method"])
|
|
}
|
|
|
|
func TestGoGRPC_VariableStubCall(t *testing.T) {
|
|
fix := runGoExtract(t, `package client
|
|
|
|
import pb "example.com/proto"
|
|
|
|
func run(conn *grpc.ClientConn) {
|
|
c := pb.NewUserServiceClient(conn)
|
|
c.ListUsers(ctx, req)
|
|
}
|
|
`)
|
|
e := grpcStubEdge(t, fix)
|
|
assert.Equal(t, "pkg/foo.go::run", e.From)
|
|
assert.Equal(t, "unresolved::grpc::UserService::ListUsers", e.To)
|
|
assert.Equal(t, "UserService", e.Meta["grpc_service"])
|
|
assert.Equal(t, "ListUsers", e.Meta["grpc_method"])
|
|
}
|
|
|
|
func TestGoGRPC_UnqualifiedConstructor(t *testing.T) {
|
|
// Same-package generated stub: the constructor has no package
|
|
// qualifier.
|
|
fix := runGoExtract(t, `package proto
|
|
|
|
func run(conn *grpc.ClientConn) {
|
|
NewOrderServiceClient(conn).PlaceOrder(ctx, req)
|
|
}
|
|
`)
|
|
e := grpcStubEdge(t, fix)
|
|
assert.Equal(t, "unresolved::grpc::OrderService::PlaceOrder", e.To)
|
|
}
|
|
|
|
func TestGoGRPC_LongerChainNotMistakenForStub(t *testing.T) {
|
|
// In `New<Service>Client(c).WithTimeout().GetUser()`, GetUser is
|
|
// invoked on WithTimeout's return value, not on the stub itself —
|
|
// its receiver is a longer chain than a single balanced call, so it
|
|
// must not be tagged as a grpc.stub call. (WithTimeout, called
|
|
// directly on the stub, is tagged by the heuristic and harmlessly
|
|
// left unresolved by the resolver — that is expected.)
|
|
fix := runGoExtract(t, `package client
|
|
|
|
import pb "example.com/proto"
|
|
|
|
func run(conn *grpc.ClientConn) {
|
|
pb.NewUserServiceClient(conn).WithTimeout().GetUser(ctx, req)
|
|
}
|
|
`)
|
|
for _, e := range fix.edgesByKind[graph.EdgeCalls] {
|
|
if e.Meta != nil && e.Meta["via"] == "grpc.stub" && e.Meta["grpc_method"] == "GetUser" {
|
|
t.Fatalf("GetUser on a chained receiver was wrongly tagged as a grpc.stub call: %s", e.To)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGoGRPC_PlainMethodCallNotStub(t *testing.T) {
|
|
fix := runGoExtract(t, `package client
|
|
|
|
func run(s *Server) {
|
|
s.DoWork(ctx)
|
|
}
|
|
`)
|
|
for _, e := range fix.edgesByKind[graph.EdgeCalls] {
|
|
if e.Meta != nil && e.Meta["via"] == "grpc.stub" {
|
|
t.Fatalf("plain method call wrongly tagged as grpc.stub: %s", e.To)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGoGRPC_ServerRegistration_CompositeLiteral(t *testing.T) {
|
|
fix := runGoExtract(t, `package main
|
|
|
|
import pb "example.com/proto"
|
|
|
|
func main() {
|
|
s := grpc.NewServer()
|
|
pb.RegisterUserServiceServer(s, &userServer{})
|
|
}
|
|
`)
|
|
var reg *graph.Edge
|
|
for _, e := range fix.edgesByKind[graph.EdgeCalls] {
|
|
if e.Meta != nil && e.Meta["grpc_register_service"] != nil {
|
|
require.Nil(t, reg, "expected exactly one registration edge")
|
|
reg = e
|
|
}
|
|
}
|
|
require.NotNil(t, reg, "registration call edge must carry grpc_register_* meta")
|
|
assert.Equal(t, "UserService", reg.Meta["grpc_register_service"])
|
|
assert.Equal(t, "userServer", reg.Meta["grpc_register_impl"])
|
|
}
|
|
|
|
func TestGoGRPC_ServerRegistration_IdentifierViaTypeEnv(t *testing.T) {
|
|
fix := runGoExtract(t, `package main
|
|
|
|
import pb "example.com/proto"
|
|
|
|
func main() {
|
|
s := grpc.NewServer()
|
|
srv := &userServer{}
|
|
pb.RegisterUserServiceServer(s, srv)
|
|
}
|
|
`)
|
|
var reg *graph.Edge
|
|
for _, e := range fix.edgesByKind[graph.EdgeCalls] {
|
|
if e.Meta != nil && e.Meta["grpc_register_service"] != nil {
|
|
reg = e
|
|
}
|
|
}
|
|
require.NotNil(t, reg, "registration via identifier must resolve through the type env")
|
|
assert.Equal(t, "UserService", reg.Meta["grpc_register_service"])
|
|
assert.Equal(t, "userServer", reg.Meta["grpc_register_impl"])
|
|
}
|
|
|
|
func TestGoGRPC_ServerRegistration_Unqualified(t *testing.T) {
|
|
fix := runGoExtract(t, `package proto
|
|
|
|
func wire(s *grpc.Server) {
|
|
RegisterPaymentServiceServer(s, NewPaymentServer())
|
|
}
|
|
`)
|
|
var reg *graph.Edge
|
|
for _, e := range fix.edgesByKind[graph.EdgeCalls] {
|
|
if e.Meta != nil && e.Meta["grpc_register_service"] != nil {
|
|
reg = e
|
|
}
|
|
}
|
|
require.NotNil(t, reg, "unqualified registration call must carry grpc_register_* meta")
|
|
assert.Equal(t, "PaymentService", reg.Meta["grpc_register_service"])
|
|
assert.Equal(t, "PaymentServer", reg.Meta["grpc_register_impl"])
|
|
}
|
|
|
|
func TestGoGRPC_NonRegisterCallNoMeta(t *testing.T) {
|
|
fix := runGoExtract(t, `package main
|
|
|
|
func main() {
|
|
doSomething(a, b)
|
|
}
|
|
`)
|
|
for _, e := range fix.edgesByKind[graph.EdgeCalls] {
|
|
if e.Meta != nil && e.Meta["grpc_register_service"] != nil {
|
|
t.Fatalf("non-registration call wrongly carries grpc_register_* meta")
|
|
}
|
|
}
|
|
}
|