diff --git a/wrap/template.go b/wrap/template.go index 7b18670..59bdc48 100644 --- a/wrap/template.go +++ b/wrap/template.go @@ -33,15 +33,15 @@ import ( healthpb "google.golang.org/grpc/health/grpc_health_v1" ) -// New{{ .Service }}GoFrServer creates a new instance of {{ .Service }}GoFrServer -func New{{ .Service }}GoFrServer() *{{ .Service }}GoFrServer { - return &{{ .Service }}GoFrServer{ +// New{{ .Service }}GoFrService creates a new instance of {{ .Service }}GoFrService +func New{{ .Service }}GoFrService() *{{ .Service }}GoFrService { + return &{{ .Service }}GoFrService{ health: getOrCreateHealthServer(), // Initialize the health server } } -// {{ .Service }}ServerWithGofr is the interface for the server implementation -type {{ .Service }}ServerWithGofr interface { +// {{ .Service }}ServiceWithGofr is the interface for the server implementation +type {{ .Service }}ServiceWithGofr interface { {{- range .Methods }} {{- if or .StreamsRequest .StreamsResponse }} {{ .Name }}(*gofr.Context, {{ $.Service }}_{{ .Name }}Server) error @@ -51,12 +51,12 @@ type {{ .Service }}ServerWithGofr interface { {{- end }} } -// {{ .Service }}ServerWrapper wraps the server and handles request and response logic -type {{ .Service }}ServerWrapper struct { +// {{ .Service }}ServiceWrapper wraps the server and handles request and response logic +type {{ .Service }}ServiceWrapper struct { {{ .Service }}Server *healthServer Container *container.Container - server {{ .Service }}ServerWithGofr + server {{ .Service }}ServiceWithGofr } {{- $hasStream := false }} @@ -220,7 +220,7 @@ func (w *bidiStreamWrapper{{ .Name }}) CloseSend() error { {{- if .StreamsResponse }} {{- if not .StreamsRequest }} // Server-side streaming handler for {{ .Name }} -func (h *{{ $.Service }}ServerWrapper) {{ .Name }}(req *{{ .Request }}, stream {{ $.Service }}_{{ .Name }}Server) error { +func (h *{{ $.Service }}ServiceWrapper) {{ .Name }}(req *{{ .Request }}, stream {{ $.Service }}_{{ .Name }}Server) error { ctx := stream.Context() gctx := h.getGofrContext(ctx, &{{ .Request }}Wrapper{ctx: ctx, {{ .Request }}: req}) @@ -235,7 +235,7 @@ func (h *{{ $.Service }}ServerWrapper) {{ .Name }}(req *{{ .Request }}, stream { } {{- else }} // Bidirectional streaming handler for {{ .Name }} -func (h *{{ $.Service }}ServerWrapper) {{ .Name }}(stream {{ $.Service }}_{{ .Name }}Server) error { +func (h *{{ $.Service }}ServiceWrapper) {{ .Name }}(stream {{ $.Service }}_{{ .Name }}Server) error { ctx := stream.Context() gctx := h.getGofrContext(ctx, nil) @@ -251,7 +251,7 @@ func (h *{{ $.Service }}ServerWrapper) {{ .Name }}(stream {{ $.Service }}_{{ .Na {{- end }} {{- else if .StreamsRequest }} // Client-side streaming handler for {{ .Name }} -func (h *{{ $.Service }}ServerWrapper) {{ .Name }}(stream {{ $.Service }}_{{ .Name }}Server) error { +func (h *{{ $.Service }}ServiceWrapper) {{ .Name }}(stream {{ $.Service }}_{{ .Name }}Server) error { ctx := stream.Context() gctx := h.getGofrContext(ctx, nil) @@ -266,7 +266,7 @@ func (h *{{ $.Service }}ServerWrapper) {{ .Name }}(stream {{ $.Service }}_{{ .Na } {{- else }} // Unary method handler for {{ .Name }} -func (h *{{ $.Service }}ServerWrapper) {{ .Name }}(ctx context.Context, req *{{ .Request }}) (*{{ .Response }}, error) { +func (h *{{ $.Service }}ServiceWrapper) {{ .Name }}(ctx context.Context, req *{{ .Request }}) (*{{ .Response }}, error) { gctx := h.getGofrContext(ctx, &{{ .Request }}Wrapper{ctx: ctx, {{ .Request }}: req}) res, err := h.server.{{ .Name }}(gctx) @@ -285,13 +285,13 @@ func (h *{{ $.Service }}ServerWrapper) {{ .Name }}(ctx context.Context, req *{{ {{- end }} // mustEmbedUnimplemented{{ .Service }}Server ensures implementation -func (h *{{ .Service }}ServerWrapper) mustEmbedUnimplemented{{ .Service }}Server() {} +func (h *{{ .Service }}ServiceWrapper) mustEmbedUnimplemented{{ .Service }}Server() {} -// Register{{ .Service }}ServerWithGofr registers the server -func Register{{ .Service }}ServerWithGofr(app *gofr.App, srv {{ .Service }}ServerWithGofr) { +// Register{{ .Service }}ServiceWithGofr registers the server +func Register{{ .Service }}ServiceWithGofr(app *gofr.App, srv {{ .Service }}ServiceWithGofr) { registerServerWithGofr(app, srv, func(s grpc.ServiceRegistrar, srv any) { - wrapper := &{{ .Service }}ServerWrapper{ - server: srv.({{ .Service }}ServerWithGofr), + wrapper := &{{ .Service }}ServiceWrapper{ + server: srv.({{ .Service }}ServiceWithGofr), healthServer: getOrCreateHealthServer(), } @@ -302,7 +302,7 @@ func Register{{ .Service }}ServerWithGofr(app *gofr.App, srv {{ .Service }}Serve } // getGofrContext creates GoFr context -func (h *{{ .Service }}ServerWrapper) getGofrContext(ctx context.Context, req gofr.Request) *gofr.Context { +func (h *{{ .Service }}ServiceWrapper) getGofrContext(ctx context.Context, req gofr.Request) *gofr.Context { return &gofr.Context{ Context: ctx, Container: h.Container, @@ -388,28 +388,28 @@ import "gofr.dev/pkg/gofr" // Register the gRPC service in your app using the following code in your main.go: // -// {{ .Package }}.Register{{ $.Service }}ServerWithGofr(app, &{{ .Package }}.New{{ $.Service }}GoFrServer()) +// {{ .Package }}.Register{{ $.Service }}ServiceWithGofr(app, &{{ .Package }}.New{{ $.Service }}GoFrService()) // -// {{ $.Service }}GoFrServer defines the gRPC server implementation. +// {{ $.Service }}GoFrService defines the gRPC server implementation. // Customize the struct with required dependencies and fields as needed. -type {{ $.Service }}GoFrServer struct { +type {{ $.Service }}GoFrService struct { health *healthServer } {{- range .Methods }} {{- if .StreamsRequest }} -func (s *{{ $.Service }}GoFrServer) {{ .Name }}(ctx *gofr.Context, stream {{ $.Service }}_{{ .Name }}Server) error { +func (s *{{ $.Service }}GoFrService) {{ .Name }}(ctx *gofr.Context, stream {{ $.Service }}_{{ .Name }}Server) error { // Implementation here return nil } {{- else if .StreamsResponse }} -func (s *{{ $.Service }}GoFrServer) {{ .Name }}(ctx *gofr.Context, stream {{ $.Service }}_{{ .Name }}Server) error { +func (s *{{ $.Service }}GoFrService) {{ .Name }}(ctx *gofr.Context, stream {{ $.Service }}_{{ .Name }}Server) error { // Implementation here return nil } {{- else }} -func (s *{{ $.Service }}GoFrServer) {{ .Name }}(ctx *gofr.Context) (any, error) { +func (s *{{ $.Service }}GoFrService) {{ .Name }}(ctx *gofr.Context) (any, error) { return &{{ .Response }}{}, nil } {{- end }} diff --git a/wrap/template_test.go b/wrap/template_test.go index bc40bf9..192cc8f 100644 --- a/wrap/template_test.go +++ b/wrap/template_test.go @@ -4,6 +4,7 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" "gofr.dev/pkg/gofr" "gofr.dev/pkg/gofr/cmd" gofrConfig "gofr.dev/pkg/gofr/config" @@ -23,6 +24,88 @@ func createTestContext() *gofr.Context { } } +// testWrapperData returns a service with one unary and one server-streaming +// method, enough to exercise every naming path in the templates. +func testWrapperData() *WrapperData { + return &WrapperData{ + Package: "hello", + Service: "Hello", + Source: "hello.proto", + Methods: []ServiceMethod{ + {Name: "SayHello", Request: "HelloRequest", Response: "HelloResponse"}, + {Name: "LotsOfReplies", Request: "HelloRequest", Response: "HelloResponse", StreamsResponse: true}, + }, + Requests: []ServiceRequest{{Request: "HelloRequest"}}, + } +} + +// The generated GoFr wrapper must name the CLI's own types after the service +// (issue #40): RegisterServiceWithGofr / GoFrService, not ...Server... +// The protoc-gen-go-grpc contract symbols the wrapper references must stay +// exactly as protoc emits them, otherwise the generated code won't compile. +func TestGenerateGoFrServerWrapper_Naming(t *testing.T) { + out := generateGoFrServerWrapper(createTestContext(), testWrapperData()) + + wantService := []string{ + "func NewHelloGoFrService() *HelloGoFrService {", + "type HelloServiceWithGofr interface {", + "type HelloServiceWrapper struct {", + "func RegisterHelloServiceWithGofr(app *gofr.App, srv HelloServiceWithGofr) {", + "func (h *HelloServiceWrapper) SayHello(", + } + for _, s := range wantService { + assert.Contains(t, out, s, "CLI-owned type must be renamed to Service") + } + + wantProtoc := []string{ + "mustEmbedUnimplementedHelloServer()", // required method of protoc HelloServer + "RegisterHelloServer(s, wrapper)", // protoc registration func + "Hello_LotsOfRepliesServer", // protoc stream interface + "registerServerWithGofr(app, srv,", // generic CLI helper, not service-scoped + } + for _, s := range wantProtoc { + assert.Contains(t, out, s, "protoc/contract symbol must be left unchanged") + } + + // The old CLI names must be gone entirely. + for _, s := range []string{"NewHelloGoFrServer", "HelloServerWithGofr", "HelloServerWrapper", "RegisterHelloServerWithGofr"} { + assert.NotContains(t, out, s, "old Server-suffixed CLI name must not remain") + } +} + +// The server scaffold users edit must expose the renamed struct + usage hint. +func TestGenerateGoFrServer_Naming(t *testing.T) { + out := generateGoFrServer(createTestContext(), testWrapperData()) + + for _, s := range []string{ + "type HelloGoFrService struct {", + "func (s *HelloGoFrService) SayHello(", + "RegisterHelloServiceWithGofr(app,", + "NewHelloGoFrService()", + } { + assert.Contains(t, out, s) + } + + // Streaming handler still references the protoc stream type. + assert.Contains(t, out, "Hello_LotsOfRepliesServer") + assert.NotContains(t, out, "HelloGoFrServer") +} + +// The client template is unrelated to the Server->Service rename and must keep +// its GoFrClient / protoc client naming intact. +func TestGenerateGoFrClient_NamingUnaffected(t *testing.T) { + out := generateGoFrClient(createTestContext(), testWrapperData()) + + for _, s := range []string{ + "type HelloGoFrClient interface {", + "type HelloClientWrapper struct {", + "func NewHelloGoFrClient(", + "NewHelloClient(conn)", // protoc client constructor + } { + assert.Contains(t, out, s) + } +} + // The request-wrapper template ranges over []ServiceRequest, so it must render // the request type's Name, not the whole struct. Regression test for #75: // `{{ $request }}` printed the struct as `{GetThingRequest GetThingRequest}`,