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
141 lines
4.2 KiB
Go
141 lines
4.2 KiB
Go
package contracts
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
// newBindTestGraph builds a minimal graph with one repo and the given
|
|
// method nodes. Receiver types and names drive the tier selection in
|
|
// bindGRPCProvider.
|
|
func newBindTestGraph(repoPrefix string, methods []struct {
|
|
id, name, recv string
|
|
}) graph.Store {
|
|
g := graph.New()
|
|
for _, m := range methods {
|
|
n := &graph.Node{
|
|
ID: m.id,
|
|
Kind: graph.KindMethod,
|
|
Name: m.name,
|
|
FilePath: "server.go",
|
|
RepoPrefix: repoPrefix,
|
|
Meta: map[string]any{},
|
|
}
|
|
if m.recv != "" {
|
|
n.Meta["receiver"] = m.recv
|
|
}
|
|
g.AddNode(n)
|
|
}
|
|
return g
|
|
}
|
|
|
|
func TestBindGRPCProvider_SingleCandidateExactReceiver(t *testing.T) {
|
|
g := newBindTestGraph("auth", []struct{ id, name, recv string }{
|
|
{"auth/server.go::UsersServer.GetUser", "GetUser", "UsersServer"},
|
|
})
|
|
reg := NewRegistry()
|
|
reg.Add(Contract{
|
|
ID: "grpc::Users::GetUser",
|
|
Type: ContractGRPC,
|
|
Role: RoleProvider,
|
|
RepoPrefix: "auth",
|
|
Meta: map[string]any{"service": "Users", "method": "GetUser"},
|
|
})
|
|
|
|
bound := BindProviderSymbols(reg, g)
|
|
if bound != 1 {
|
|
t.Fatalf("expected 1 binding, got %d", bound)
|
|
}
|
|
cs := reg.ByID("grpc::Users::GetUser")
|
|
if len(cs) == 0 {
|
|
t.Fatal("contract lost from registry after binding")
|
|
}
|
|
// Registry keeps appends; the bound copy is the most recent.
|
|
got := cs[len(cs)-1].SymbolID
|
|
if got != "auth/server.go::UsersServer.GetUser" {
|
|
t.Errorf("SymbolID: want auth/server.go::UsersServer.GetUser, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestBindGRPCProvider_AmbiguousReceiversNoBind(t *testing.T) {
|
|
// Two methods named GetUser in the same repo, neither on the
|
|
// canonical "{Service}Server" receiver. Binding must not guess —
|
|
// the provider stays unbound and no bridge forms (acceptable v1
|
|
// behavior documented in bind.go).
|
|
g := newBindTestGraph("auth", []struct{ id, name, recv string }{
|
|
{"auth/a.go::HandlerA.GetUser", "GetUser", "HandlerA"},
|
|
{"auth/b.go::HandlerB.GetUser", "GetUser", "HandlerB"},
|
|
})
|
|
reg := NewRegistry()
|
|
reg.Add(Contract{
|
|
ID: "grpc::Users::GetUser",
|
|
Type: ContractGRPC,
|
|
Role: RoleProvider,
|
|
RepoPrefix: "auth",
|
|
Meta: map[string]any{"service": "Users", "method": "GetUser"},
|
|
})
|
|
|
|
bound := BindProviderSymbols(reg, g)
|
|
if bound != 0 {
|
|
t.Errorf("expected 0 bindings when ambiguous, got %d", bound)
|
|
}
|
|
}
|
|
|
|
func TestBindGRPCProvider_NoCandidatesSkip(t *testing.T) {
|
|
g := graph.New()
|
|
reg := NewRegistry()
|
|
reg.Add(Contract{
|
|
ID: "grpc::Users::GetUser",
|
|
Type: ContractGRPC,
|
|
Role: RoleProvider,
|
|
RepoPrefix: "auth",
|
|
Meta: map[string]any{"service": "Users", "method": "GetUser"},
|
|
})
|
|
if got := BindProviderSymbols(reg, g); got != 0 {
|
|
t.Errorf("expected 0 bindings with no candidates, got %d", got)
|
|
}
|
|
}
|
|
|
|
func TestBindGRPCProvider_SkipsAlreadyBound(t *testing.T) {
|
|
g := newBindTestGraph("auth", []struct{ id, name, recv string }{
|
|
{"auth/server.go::UsersServer.GetUser", "GetUser", "UsersServer"},
|
|
})
|
|
reg := NewRegistry()
|
|
reg.Add(Contract{
|
|
ID: "grpc::Users::GetUser",
|
|
Type: ContractGRPC,
|
|
Role: RoleProvider,
|
|
RepoPrefix: "auth",
|
|
SymbolID: "manually/bound::Elsewhere",
|
|
Meta: map[string]any{"service": "Users", "method": "GetUser"},
|
|
})
|
|
// Contracts that already carry SymbolID must not be touched —
|
|
// the binding pass is a recovery step, not an override.
|
|
if got := BindProviderSymbols(reg, g); got != 0 {
|
|
t.Errorf("expected 0 bindings, got %d", got)
|
|
}
|
|
cs := reg.ByID("grpc::Users::GetUser")
|
|
if cs[0].SymbolID != "manually/bound::Elsewhere" {
|
|
t.Errorf("existing SymbolID was overwritten: %q", cs[0].SymbolID)
|
|
}
|
|
}
|
|
|
|
func TestBindGRPCProvider_CrossRepoCandidatesIgnored(t *testing.T) {
|
|
// A same-named method in a DIFFERENT repo must not be picked.
|
|
g := newBindTestGraph("other-repo", []struct{ id, name, recv string }{
|
|
{"other-repo/server.go::UsersServer.GetUser", "GetUser", "UsersServer"},
|
|
})
|
|
reg := NewRegistry()
|
|
reg.Add(Contract{
|
|
ID: "grpc::Users::GetUser",
|
|
Type: ContractGRPC,
|
|
Role: RoleProvider,
|
|
RepoPrefix: "auth",
|
|
Meta: map[string]any{"service": "Users", "method": "GetUser"},
|
|
})
|
|
if got := BindProviderSymbols(reg, g); got != 0 {
|
|
t.Errorf("expected 0 bindings (cross-repo candidate), got %d", got)
|
|
}
|
|
}
|