From 17ab0e2ced40b865ed5afef77d88ab4438aae0c4 Mon Sep 17 00:00:00 2001 From: John Guo Date: Wed, 15 Jun 2022 19:36:53 +0800 Subject: [PATCH] remove returning error of Write* functions for ghttp.Server; add UT cases for gclient.Client.DoRequestObj --- net/gclient/gclient_z_example_test.go | 5 +- .../gclient_z_unit_feature_trace_test.go | 78 +++++++++++++++++++ .../gclient_z_unit_request_obj_test.go | 78 +++++++++++++++++++ net/gclient/gclient_z_unit_test.go | 62 +-------------- .../ghttp_middleware_handler_response.go | 7 +- net/ghttp/ghttp_response_write.go | 40 ++++------ net/ghttp/ghttp_server_openapi.go | 10 +-- 7 files changed, 176 insertions(+), 104 deletions(-) create mode 100644 net/gclient/gclient_z_unit_feature_trace_test.go create mode 100644 net/gclient/gclient_z_unit_request_obj_test.go diff --git a/net/gclient/gclient_z_example_test.go b/net/gclient/gclient_z_example_test.go index 24d4034d193..00bb657ccd4 100644 --- a/net/gclient/gclient_z_example_test.go +++ b/net/gclient/gclient_z_example_test.go @@ -11,13 +11,14 @@ import ( "crypto/tls" "encoding/hex" "fmt" + "net/http" + "time" + "github.com/gogf/gf/v2/debug/gdebug" "github.com/gogf/gf/v2/net/gclient" "github.com/gogf/gf/v2/net/gtcp" "github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/os/gfile" - "net/http" - "time" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" diff --git a/net/gclient/gclient_z_unit_feature_trace_test.go b/net/gclient/gclient_z_unit_feature_trace_test.go new file mode 100644 index 00000000000..e01ca4cd1b0 --- /dev/null +++ b/net/gclient/gclient_z_unit_feature_trace_test.go @@ -0,0 +1,78 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gclient_test + +import ( + "context" + "fmt" + "net/http" + "testing" + "time" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/internal/tracing" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/net/gtcp" + "github.com/gogf/gf/v2/test/gtest" + "go.opentelemetry.io/otel" + sdkTrace "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/trace" +) + +type CustomProvider struct { + *sdkTrace.TracerProvider +} + +func NewCustomProvider() *CustomProvider { + return &CustomProvider{ + TracerProvider: sdkTrace.NewTracerProvider( + sdkTrace.WithIDGenerator(NewCustomIDGenerator()), + ), + } +} + +type CustomIDGenerator struct{} + +func NewCustomIDGenerator() *CustomIDGenerator { + return &CustomIDGenerator{} +} + +func (id *CustomIDGenerator) NewIDs(ctx context.Context) (traceID trace.TraceID, spanID trace.SpanID) { + return tracing.NewIDs() +} + +func (id *CustomIDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) (spanID trace.SpanID) { + return tracing.NewSpanID() +} + +func TestClient_CustomProvider(t *testing.T) { + provider := otel.GetTracerProvider() + defer otel.SetTracerProvider(provider) + + otel.SetTracerProvider(NewCustomProvider()) + + p, _ := gtcp.GetFreePort() + s := g.Server(p) + s.BindHandler("/hello", func(r *ghttp.Request) { + r.Response.WriteHeader(200) + r.Response.WriteJson(g.Map{"field": "test_for_response_body"}) + }) + s.SetPort(p) + s.SetDumpRouterMap(false) + s.Start() + defer s.Shutdown() + + time.Sleep(100 * time.Millisecond) + gtest.C(t, func(t *gtest.T) { + c := g.Client() + url := fmt.Sprintf("127.0.0.1:%d/hello", p) + resp, err := c.DoRequest(ctx, http.MethodGet, url) + t.AssertNil(err) + t.AssertNE(resp, nil) + t.Assert(resp.ReadAllString(), "{\"field\":\"test_for_response_body\"}") + }) +} diff --git a/net/gclient/gclient_z_unit_request_obj_test.go b/net/gclient/gclient_z_unit_request_obj_test.go new file mode 100644 index 00000000000..7c9d2da0e64 --- /dev/null +++ b/net/gclient/gclient_z_unit_request_obj_test.go @@ -0,0 +1,78 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gclient_test + +import ( + "fmt" + "testing" + "time" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/net/gtcp" + "github.com/gogf/gf/v2/test/gtest" +) + +func Test_Client_DoRequestObj(t *testing.T) { + type UserCreateReq struct { + g.Meta `path:"/user" method:"post"` + Id int + Name string + } + type UserCreateRes struct { + Id int + } + type UserQueryReq struct { + g.Meta `path:"/user" method:"get"` + } + type UserQueryRes struct { + Id int + Name string + } + p, _ := gtcp.GetFreePort() + s := g.Server(p) + s.Group("/user", func(group *ghttp.RouterGroup) { + group.GET("/", func(r *ghttp.Request) { + r.Response.WriteJson(g.Map{"id": 1, "name": "john"}) + }) + group.POST("/", func(r *ghttp.Request) { + r.Response.WriteJson(g.Map{"id": r.Get("Id")}) + }) + }) + s.SetPort(p) + s.SetDumpRouterMap(false) + s.Start() + defer s.Shutdown() + + time.Sleep(100 * time.Millisecond) + gtest.C(t, func(t *gtest.T) { + url := fmt.Sprintf("http://127.0.0.1:%d", p) + client := g.Client().SetPrefix(url).ContentJson() + var ( + createRes *UserCreateRes + createReq = UserCreateReq{ + Id: 1, + Name: "john", + } + ) + err := client.DoRequestObj(ctx, createReq, &createRes) + t.AssertNil(err) + t.Assert(createRes.Id, 1) + }) + gtest.C(t, func(t *gtest.T) { + url := fmt.Sprintf("http://127.0.0.1:%d", p) + client := g.Client().SetPrefix(url).ContentJson() + var ( + queryRes *UserQueryRes + queryReq = UserQueryReq{} + ) + err := client.DoRequestObj(ctx, queryReq, &queryRes) + t.AssertNil(err) + t.Assert(queryRes.Id, 1) + t.Assert(queryRes.Name, "john") + }) +} diff --git a/net/gclient/gclient_z_unit_test.go b/net/gclient/gclient_z_unit_test.go index 806be5f6d6d..410645449d8 100644 --- a/net/gclient/gclient_z_unit_test.go +++ b/net/gclient/gclient_z_unit_test.go @@ -11,16 +11,13 @@ import ( "context" "crypto/tls" "fmt" - "github.com/gogf/gf/v2/debug/gdebug" - "github.com/gogf/gf/v2/internal/tracing" - "go.opentelemetry.io/otel" - sdkTrace "go.opentelemetry.io/otel/sdk/trace" - "go.opentelemetry.io/otel/trace" "io/ioutil" "net/http" "testing" "time" + "github.com/gogf/gf/v2/debug/gdebug" + "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/gclient" @@ -643,58 +640,3 @@ func TestClient_RequestVar(t *testing.T) { t.AssertNE(users, nil) }) } - -type CustomProvider struct { - *sdkTrace.TracerProvider -} - -func NewCustomProvider() *CustomProvider { - return &CustomProvider{ - TracerProvider: sdkTrace.NewTracerProvider( - sdkTrace.WithIDGenerator(NewCustomIDGenerator()), - ), - } -} - -type CustomIDGenerator struct{} - -func NewCustomIDGenerator() *CustomIDGenerator { - return &CustomIDGenerator{} -} - -func (id *CustomIDGenerator) NewIDs(ctx context.Context) (traceID trace.TraceID, spanID trace.SpanID) { - return tracing.NewIDs() -} - -func (id *CustomIDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) (spanID trace.SpanID) { - return tracing.NewSpanID() -} - -func TestClient_CustomProvider(t *testing.T) { - provider := otel.GetTracerProvider() - defer otel.SetTracerProvider(provider) - - otel.SetTracerProvider(NewCustomProvider()) - - p, _ := gtcp.GetFreePort() - s := g.Server(p) - s.BindHandler("/hello", func(r *ghttp.Request) { - r.Response.WriteHeader(200) - r.Response.WriteJson(g.Map{"field": "test_for_response_body"}) - }) - s.SetPort(p) - s.SetDumpRouterMap(false) - s.Start() - defer s.Shutdown() - - time.Sleep(100 * time.Millisecond) - gtest.C(t, func(t *gtest.T) { - c := g.Client() - url := fmt.Sprintf("127.0.0.1:%d/hello", p) - resp, err := c.DoRequest(ctx, http.MethodGet, url) - t.AssertNil(err) - t.AssertNE(resp, nil) - t.Assert(resp.ReadAllString(), "{\"field\":\"test_for_response_body\"}") - }) - -} diff --git a/net/ghttp/ghttp_middleware_handler_response.go b/net/ghttp/ghttp_middleware_handler_response.go index 8fbb9b70587..554996b7843 100644 --- a/net/ghttp/ghttp_middleware_handler_response.go +++ b/net/ghttp/ghttp_middleware_handler_response.go @@ -11,7 +11,6 @@ import ( "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/intlog" ) // DefaultHandlerResponse is the default implementation of HandlerResponse. @@ -32,7 +31,6 @@ func MiddlewareHandlerResponse(r *Request) { var ( msg string - ctx = r.Context() err = r.GetError() res = r.GetHandlerResponse() code = gerror.Code(err) @@ -55,12 +53,9 @@ func MiddlewareHandlerResponse(r *Request) { } else { code = gcode.CodeOK } - internalErr := r.Response.WriteJson(DefaultHandlerResponse{ + r.Response.WriteJson(DefaultHandlerResponse{ Code: code.Code(), Message: msg, Data: res, }) - if internalErr != nil { - intlog.Errorf(ctx, `%+v`, internalErr) - } } diff --git a/net/ghttp/ghttp_response_write.go b/net/ghttp/ghttp_response_write.go index 34878cd5db4..9d9565ec8e6 100644 --- a/net/ghttp/ghttp_response_write.go +++ b/net/ghttp/ghttp_response_write.go @@ -12,6 +12,7 @@ import ( "net/http" "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/util/gconv" ) @@ -102,48 +103,42 @@ func (r *Response) WriteflnExit(format string, params ...interface{}) { } // WriteJson writes `content` to the response with JSON format. -func (r *Response) WriteJson(content interface{}) error { +func (r *Response) WriteJson(content interface{}) { r.Header().Set("Content-Type", contentTypeJson) // If given string/[]byte, response it directly to the client. switch content.(type) { case string, []byte: r.Write(gconv.String(content)) - return nil } // Else use json.Marshal function to encode the parameter. if b, err := json.Marshal(content); err != nil { - return err + panic(gerror.Wrap(err, `WriteJson failed`)) } else { r.Write(b) } - return nil } // WriteJsonExit writes `content` to the response with JSON format and exits executing // of current handler if success. The "Exit" feature is commonly used to replace usage of // return statements in the handler, for convenience. -func (r *Response) WriteJsonExit(content interface{}) error { - if err := r.WriteJson(content); err != nil { - return err - } +func (r *Response) WriteJsonExit(content interface{}) { + r.WriteJson(content) r.Request.Exit() - return nil } // WriteJsonP writes `content` to the response with JSONP format. // // Note that there should be a "callback" parameter in the request for JSONP format. -func (r *Response) WriteJsonP(content interface{}) error { +func (r *Response) WriteJsonP(content interface{}) { r.Header().Set("Content-Type", contentTypeJson) // If given string/[]byte, response it directly to client. switch content.(type) { case string, []byte: r.Write(gconv.String(content)) - return nil } // Else use json.Marshal function to encode the parameter. if b, err := json.Marshal(content); err != nil { - return err + panic(gerror.Wrap(err, `WriteJsonP failed`)) } else { // r.Header().Set("Content-Type", "application/json") if callback := r.Request.Get("callback").String(); callback != "" { @@ -156,7 +151,6 @@ func (r *Response) WriteJsonP(content interface{}) error { r.Write(b) } } - return nil } // WriteJsonPExit writes `content` to the response with JSONP format and exits executing @@ -164,40 +158,32 @@ func (r *Response) WriteJsonP(content interface{}) error { // return statements in the handler, for convenience. // // Note that there should be a "callback" parameter in the request for JSONP format. -func (r *Response) WriteJsonPExit(content interface{}) error { - if err := r.WriteJsonP(content); err != nil { - return err - } +func (r *Response) WriteJsonPExit(content interface{}) { + r.WriteJsonP(content) r.Request.Exit() - return nil } // WriteXml writes `content` to the response with XML format. -func (r *Response) WriteXml(content interface{}, rootTag ...string) error { +func (r *Response) WriteXml(content interface{}, rootTag ...string) { r.Header().Set("Content-Type", contentTypeXml) // If given string/[]byte, response it directly to clients. switch content.(type) { case string, []byte: r.Write(gconv.String(content)) - return nil } if b, err := gjson.New(content).ToXml(rootTag...); err != nil { - return err + panic(gerror.Wrap(err, `WriteXml failed`)) } else { r.Write(b) } - return nil } // WriteXmlExit writes `content` to the response with XML format and exits executing // of current handler if success. The "Exit" feature is commonly used to replace usage // of return statements in the handler, for convenience. -func (r *Response) WriteXmlExit(content interface{}, rootTag ...string) error { - if err := r.WriteXml(content, rootTag...); err != nil { - return err - } +func (r *Response) WriteXmlExit(content interface{}, rootTag ...string) { + r.WriteXml(content, rootTag...) r.Request.Exit() - return nil } // WriteStatus writes HTTP `status` and `content` to the response. diff --git a/net/ghttp/ghttp_server_openapi.go b/net/ghttp/ghttp_server_openapi.go index 72fd1064425..0ca79a39040 100644 --- a/net/ghttp/ghttp_server_openapi.go +++ b/net/ghttp/ghttp_server_openapi.go @@ -9,7 +9,6 @@ package ghttp import ( "context" - "github.com/gogf/gf/v2/internal/intlog" "github.com/gogf/gf/v2/net/goai" "github.com/gogf/gf/v2/text/gstr" ) @@ -48,16 +47,9 @@ func (s *Server) initOpenApi() { // openapiSpec is a build-in handler automatic producing for openapi specification json file. func (s *Server) openapiSpec(r *Request) { - var ( - err error - ) if s.config.OpenApiPath == "" { r.Response.Write(`OpenApi specification file producing is disabled`) } else { - err = r.Response.WriteJson(s.openapi) - } - - if err != nil { - intlog.Errorf(r.Context(), `%+v`, err) + r.Response.WriteJson(s.openapi) } }