remove returning error of Write* functions for ghttp.Server; add UT cases for gclient.Client.DoRequestObj

This commit is contained in:
John Guo
2022-06-15 19:36:53 +08:00
parent f4f73f2765
commit 17ab0e2ced
7 changed files with 176 additions and 104 deletions

View File

@ -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"

View File

@ -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\"}")
})
}

View File

@ -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")
})
}

View File

@ -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\"}")
})
}

View File

@ -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)
}
}

View File

@ -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.

View File

@ -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)
}
}