Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 24 additions & 24 deletions wrap/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 }}
Expand Down Expand Up @@ -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})

Expand All @@ -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)

Expand All @@ -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)

Expand All @@ -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)
Expand All @@ -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(),
}

Expand All @@ -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,
Expand Down Expand Up @@ -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 }}
Expand Down
106 changes: 106 additions & 0 deletions wrap/template_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package wrap

import (
"testing"

"github.com/stretchr/testify/assert"
"gofr.dev/pkg/gofr"
"gofr.dev/pkg/gofr/cmd"
gofrConfig "gofr.dev/pkg/gofr/config"
"gofr.dev/pkg/gofr/container"
"gofr.dev/pkg/gofr/logging"
)

// createTestContext creates a test gofr.Context for CMD applications.
func createTestContext() *gofr.Context {
c := container.NewContainer(gofrConfig.NewEnvFile("", logging.NewMockLogger(logging.DEBUG)))
req := cmd.NewRequest([]string{})

return &gofr.Context{
Context: req.Context(),
Request: req,
Container: c,
}
}

// 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): Register<Svc>ServiceWithGofr / <Svc>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)
}
}