From 42a9ddd972786b75a826a36636b437d60f278149 Mon Sep 17 00:00:00 2001 From: Taichi Sasaki Date: Mon, 6 Nov 2023 14:21:33 +0900 Subject: [PATCH] Fix generated validation code for gRPC (#3409) * Add test cases of struct:field:name for gRPC * Fix generated validation code for gRPC --- grpc/codegen/client_types_test.go | 1 + grpc/codegen/server_types_test.go | 1 + grpc/codegen/service_data.go | 1 + grpc/codegen/testdata/client_type_code.go | 43 +++++++++++++++++++++++ grpc/codegen/testdata/dsls.go | 28 +++++++++++++++ grpc/codegen/testdata/server_type_code.go | 43 +++++++++++++++++++++++ 6 files changed, 117 insertions(+) diff --git a/grpc/codegen/client_types_test.go b/grpc/codegen/client_types_test.go index cb4ca2d772..d6ed0d5466 100644 --- a/grpc/codegen/client_types_test.go +++ b/grpc/codegen/client_types_test.go @@ -23,6 +23,7 @@ func TestClientTypeFiles(t *testing.T) { {"client-with-errors", testdata.UnaryRPCWithErrorsDSL, testdata.WithErrorsClientTypeCode}, {"client-bidirectional-streaming-same-type", testdata.BidirectionalStreamingRPCSameTypeDSL, testdata.BidirectionalStreamingRPCSameTypeClientTypeCode}, {"client-struct-meta-type", testdata.StructMetaTypeDSL, testdata.StructMetaTypeTypeCode}, + {"client-struct-field-name-meta-type", testdata.StructFieldNameMetaTypeDSL, testdata.StructFieldNameMetaTypeClientTypesCode}, {"client-default-fields", testdata.DefaultFieldsDSL, testdata.DefaultFieldsTypeCode}, } for _, c := range cases { diff --git a/grpc/codegen/server_types_test.go b/grpc/codegen/server_types_test.go index 15a401fd63..ea5e87c30e 100644 --- a/grpc/codegen/server_types_test.go +++ b/grpc/codegen/server_types_test.go @@ -24,6 +24,7 @@ func TestServerTypeFiles(t *testing.T) { {"server-elem-validation", testdata.ElemValidationDSL, testdata.ElemValidationServerTypesFile}, {"server-alias-validation", testdata.AliasValidationDSL, testdata.AliasValidationServerTypesFile}, {"server-struct-meta-type", testdata.StructMetaTypeDSL, testdata.StructMetaTypeServerTypeCode}, + {"server-struct-field-name-meta-type", testdata.StructFieldNameMetaTypeDSL, testdata.StructFieldNameMetaTypeServerTypesCode}, {"server-default-fields", testdata.DefaultFieldsDSL, testdata.DefaultFieldsServerTypeCode}, } for _, c := range cases { diff --git a/grpc/codegen/service_data.go b/grpc/codegen/service_data.go index ced49fb447..f356d441b7 100644 --- a/grpc/codegen/service_data.go +++ b/grpc/codegen/service_data.go @@ -744,6 +744,7 @@ func addValidation(att *expr.AttributeExpr, attName string, sd *ServiceData, req } } vtx := protoBufTypeContext(sd.PkgName, sd.Scope, false) + removeMeta(att) if def := codegen.ValidationCode(att, ut, vtx, true, expr.IsAlias(att.Type), attName); def != "" { v := &ValidationData{ Name: "Validate" + name, diff --git a/grpc/codegen/testdata/client_type_code.go b/grpc/codegen/testdata/client_type_code.go index 61a68a097a..fdf747269d 100644 --- a/grpc/codegen/testdata/client_type_code.go +++ b/grpc/codegen/testdata/client_type_code.go @@ -371,6 +371,49 @@ func NewMethodResult(message *using_meta_typespb.MethodResponse) *usingmetatypes } ` +const StructFieldNameMetaTypeClientTypesCode = `// NewProtoMethodRequest builds the gRPC request type from the payload of the +// "Method" endpoint of the "UsingMetaTypes" service. +func NewProtoMethodRequest(payload *usingmetatypes.MethodPayload) *using_meta_typespb.MethodRequest { + message := &using_meta_typespb.MethodRequest{ + A: &payload.Foo, + } + if payload.Bar != nil { + message.B = make([]int64, len(payload.Bar)) + for i, val := range payload.Bar { + message.B[i] = val + } + } + return message +} + +// NewMethodResult builds the result type of the "Method" endpoint of the +// "UsingMetaTypes" service from the gRPC response type. +func NewMethodResult(message *using_meta_typespb.MethodResponse) *usingmetatypes.MethodResult { + result := &usingmetatypes.MethodResult{} + if message.A != nil { + result.Foo = *message.A + } + if message.A == nil { + result.Foo = 1 + } + if message.B != nil { + result.Bar = make([]int64, len(message.B)) + for i, val := range message.B { + result.Bar[i] = val + } + } + return result +} + +// ValidateMethodResponse runs the validations defined on MethodResponse. +func ValidateMethodResponse(message *using_meta_typespb.MethodResponse) (err error) { + if message.B == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("b", "message")) + } + return +} +` + const DefaultFieldsTypeCode = `// NewProtoMethodRequest builds the gRPC request type from the payload of the // "Method" endpoint of the "DefaultFields" service. func NewProtoMethodRequest(payload *defaultfields.MethodPayload) *default_fieldspb.MethodRequest { diff --git a/grpc/codegen/testdata/dsls.go b/grpc/codegen/testdata/dsls.go index ffa3b0f85d..a54d1b13fb 100644 --- a/grpc/codegen/testdata/dsls.go +++ b/grpc/codegen/testdata/dsls.go @@ -924,6 +924,34 @@ var StructMetaTypeDSL = func() { }) } +var StructFieldNameMetaTypeDSL = func() { + Service("UsingMetaTypes", func() { + Method("Method", func() { + Payload(func() { + Field(1, "a", Int64, func() { + Meta("struct:field:name", "Foo") + Default(1) + }) + Field(2, "b", ArrayOf(Int64), func() { + Meta("struct:field:name", "Bar") + }) + Required("b") + }) + Result(func() { + Field(1, "a", Int64, func() { + Meta("struct:field:name", "Foo") + Default(1) + }) + Field(2, "b", ArrayOf(Int64), func() { + Meta("struct:field:name", "Bar") + }) + Required("b") + }) + GRPC(func() {}) + }) + }) +} + var DefaultFieldsDSL = func() { Service("DefaultFields", func() { Method("Method", func() { diff --git a/grpc/codegen/testdata/server_type_code.go b/grpc/codegen/testdata/server_type_code.go index 923f1e747f..c6acec6854 100644 --- a/grpc/codegen/testdata/server_type_code.go +++ b/grpc/codegen/testdata/server_type_code.go @@ -491,6 +491,49 @@ func NewProtoMethodResponse(result *usingmetatypes.MethodResult) *using_meta_typ } ` +const StructFieldNameMetaTypeServerTypesCode = `// NewMethodPayload builds the payload of the "Method" endpoint of the +// "UsingMetaTypes" service from the gRPC request type. +func NewMethodPayload(message *using_meta_typespb.MethodRequest) *usingmetatypes.MethodPayload { + v := &usingmetatypes.MethodPayload{} + if message.A != nil { + v.Foo = *message.A + } + if message.A == nil { + v.Foo = 1 + } + if message.B != nil { + v.Bar = make([]int64, len(message.B)) + for i, val := range message.B { + v.Bar[i] = val + } + } + return v +} + +// NewProtoMethodResponse builds the gRPC response type from the result of the +// "Method" endpoint of the "UsingMetaTypes" service. +func NewProtoMethodResponse(result *usingmetatypes.MethodResult) *using_meta_typespb.MethodResponse { + message := &using_meta_typespb.MethodResponse{ + A: &result.Foo, + } + if result.Bar != nil { + message.B = make([]int64, len(result.Bar)) + for i, val := range result.Bar { + message.B[i] = val + } + } + return message +} + +// ValidateMethodRequest runs the validations defined on MethodRequest. +func ValidateMethodRequest(message *using_meta_typespb.MethodRequest) (err error) { + if message.B == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("b", "message")) + } + return +} +` + const DefaultFieldsServerTypeCode = `// NewMethodPayload builds the payload of the "Method" endpoint of the // "DefaultFields" service from the gRPC request type. func NewMethodPayload(message *default_fieldspb.MethodRequest) *defaultfields.MethodPayload {