Skip to content

Commit

Permalink
test http (#1045)
Browse files Browse the repository at this point in the history
* test http
* fix response codec
* benchmark
  • Loading branch information
Windfarer committed Jun 14, 2021
1 parent dc80d08 commit 0ff1c6f
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 1 deletion.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/google/uuid v1.2.0
github.com/gorilla/mux v1.8.0
github.com/imdario/mergo v0.3.12
github.com/stretchr/testify v1.7.0
go.opentelemetry.io/otel v0.20.0
go.opentelemetry.io/otel/trace v0.20.0
golang.org/x/net v0.0.0-20210525063256-abc453219eb5 // indirect
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
Expand Down
2 changes: 1 addition & 1 deletion transport/http/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ func DefaultErrorDecoder(ctx context.Context, res *http.Response) error {

// CodecForResponse get encoding.Codec via http.Response
func CodecForResponse(r *http.Response) encoding.Codec {
codec := encoding.GetCodec(httputil.ContentSubtype("Content-Type"))
codec := encoding.GetCodec(httputil.ContentSubtype(r.Header.Get("Content-Type")))
if codec != nil {
return codec
}
Expand Down
174 changes: 174 additions & 0 deletions transport/http/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package http

import (
"bytes"
"context"
"encoding/json"
"github.com/go-kratos/kratos/v2/errors"
"io/ioutil"
nethttp "net/http"
"testing"
"time"

"github.com/stretchr/testify/assert"

"github.com/go-kratos/kratos/v2/registry"
)

type mockRoundTripper struct {
}

func (rt *mockRoundTripper) RoundTrip(req *nethttp.Request) (resp *nethttp.Response, err error) {
return
}

func TestWithTransport(t *testing.T) {
ov := &mockRoundTripper{}
o := WithTransport(ov)
co := &clientOptions{}
o(co)
assert.Equal(t, co.transport, ov)
}

func TestWithTimeout(t *testing.T) {
ov := 1 * time.Second
o := WithTimeout(ov)
co := &clientOptions{}
o(co)
assert.Equal(t, co.timeout, ov)
}

func TestWithBalancer(t *testing.T) {

}

func TestWithUserAgent(t *testing.T) {
ov := "kratos"
o := WithUserAgent(ov)
co := &clientOptions{}
o(co)
assert.Equal(t, co.userAgent, ov)
}

func TestWithMiddleware(t *testing.T) {
}

func TestWithEndpoint(t *testing.T) {
ov := "some-endpoint"
o := WithEndpoint(ov)
co := &clientOptions{}
o(co)
assert.Equal(t, co.endpoint, ov)
}

func TestWithRequestEncoder(t *testing.T) {

}

func TestWithResponseDecoder(t *testing.T) {

}

func TestWithErrorDecoder(t *testing.T) {
}

type mockDiscovery struct {
}

func (*mockDiscovery) GetService(ctx context.Context, serviceName string) ([]*registry.ServiceInstance, error) {
return nil, nil
}

func (*mockDiscovery) Watch(ctx context.Context, serviceName string) (registry.Watcher, error) {
return nil, nil
}

func TestWithDiscovery(t *testing.T) {
ov := &mockDiscovery{}
o := WithDiscovery(ov)
co := &clientOptions{}
o(co)
assert.Equal(t, co.discovery, ov)
}

func TestDefaultRequestEncoder(t *testing.T) {
req1 := &nethttp.Request{
Header: make(nethttp.Header),
Body: ioutil.NopCloser(bytes.NewBufferString("{\"a\":\"1\", \"b\": 2}")),
}
req1.Header.Set("Content-Type", "application/xml")

v1 := &struct {
A string `json:"a"`
B int64 `json:"b"`
}{"a", 1}
b, err1 := DefaultRequestEncoder(context.TODO(), "application/json", v1)
assert.Nil(t, err1)
v1b := &struct {
A string `json:"a"`
B int64 `json:"b"`
}{}
err1 = json.Unmarshal(b, v1b)
assert.Nil(t, err1)
assert.Equal(t, v1, v1b)
}

func TestDefaultResponseDecoder(t *testing.T) {
resp1 := &nethttp.Response{
Header: make(nethttp.Header),
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewBufferString("{\"a\":\"1\", \"b\": 2}")),
}
v1 := &struct {
A string `json:"a"`
B int64 `json:"b"`
}{}
err1 := DefaultResponseDecoder(context.TODO(), resp1, &v1)
assert.Nil(t, err1)
assert.Equal(t, "1", v1.A)
assert.Equal(t, int64(2), v1.B)

resp2 := &nethttp.Response{
Header: make(nethttp.Header),
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewBufferString("{badjson}")),
}
v2 := &struct {
A string `json:"a"`
B int64 `json:"b"`
}{}
err2 := DefaultResponseDecoder(context.TODO(), resp2, &v2)
terr1 := &json.SyntaxError{}
assert.ErrorAs(t, err2, &terr1)
}

func TestDefaultErrorDecoder(t *testing.T) {
for i := 200; i < 300; i++ {
resp := &nethttp.Response{Header: make(nethttp.Header), StatusCode: i}
assert.Nil(t, DefaultErrorDecoder(context.TODO(), resp))
}
resp1 := &nethttp.Response{
Header: make(nethttp.Header),
StatusCode: 300,
Body: ioutil.NopCloser(bytes.NewBufferString("{\"foo\":\"bar\"}")),
}
assert.Error(t, DefaultErrorDecoder(context.TODO(), resp1))

resp2 := &nethttp.Response{
Header: make(nethttp.Header),
StatusCode: 500,
Body: ioutil.NopCloser(bytes.NewBufferString("{\"code\":54321, \"message\": \"hi\", \"reason\": \"FOO\"}")),
}
err2 := DefaultErrorDecoder(context.TODO(), resp2)
assert.Error(t, err2)
assert.Equal(t, int32(54321), err2.(*errors.Error).GetCode())
assert.Equal(t, "hi", err2.(*errors.Error).GetMessage())
assert.Equal(t, "FOO", err2.(*errors.Error).GetReason())
}

func TestCodecForResponse(t *testing.T) {
resp := &nethttp.Response{Header: make(nethttp.Header)}
resp.Header.Set("Content-Type", "application/xml")
c := CodecForResponse(resp)
assert.Equal(t, "xml", c.Name())
}
108 changes: 108 additions & 0 deletions transport/http/codec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package http

import (
"bytes"
"github.com/go-kratos/kratos/v2/errors"
"github.com/stretchr/testify/assert"
"io/ioutil"
nethttp "net/http"
"testing"
)

func TestDefaultRequestDecoder(t *testing.T) {
req1 := &nethttp.Request{
Header: make(nethttp.Header),
Body: ioutil.NopCloser(bytes.NewBufferString("{\"a\":\"1\", \"b\": 2}")),
}
req1.Header.Set("Content-Type", "application/json")

v1 := &struct {
A string `json:"a"`
B int64 `json:"b"`
}{}
err1 := DefaultRequestDecoder(req1, &v1)
assert.Nil(t, err1)
assert.Equal(t, "1", v1.A)
assert.Equal(t, int64(2), v1.B)
}

type mockResponseWriter struct {
StatusCode int
Data []byte
header nethttp.Header
}

func (w *mockResponseWriter) Header() nethttp.Header {
return w.header
}

func (w *mockResponseWriter) Write(b []byte) (int, error) {
w.Data = b
return len(b), nil
}

func (w *mockResponseWriter) WriteHeader(statusCode int) {
w.StatusCode = statusCode
}

type dataWithStatusCode struct {
statusCode int
A string `json:"a"`
B int64 `json:"b"`
}

func (d *dataWithStatusCode) StatusCode() int {
return d.statusCode
}

func TestDefaultResponseEncoder(t *testing.T) {
w := &mockResponseWriter{header: make(nethttp.Header)}
req1 := &nethttp.Request{
Header: make(nethttp.Header),
}
req1.Header.Set("Content-Type", "application/json")

v1 := &dataWithStatusCode{statusCode: 201, A: "1", B: 2}
err := DefaultResponseEncoder(w, req1, v1)
assert.Nil(t, err)
assert.Equal(t, "application/json", w.Header().Get("Content-Type"))
assert.Equal(t, 201, w.StatusCode)
assert.NotNil(t, w.Data)
}

func TestDefaultResponseEncoderWithError(t *testing.T) {
w := &mockResponseWriter{header: make(nethttp.Header)}
req1 := &nethttp.Request{
Header: make(nethttp.Header),
}
req1.Header.Set("Content-Type", "application/json")

v1 := &errors.Error{Code: 511}
err := DefaultResponseEncoder(w, req1, v1)
assert.Nil(t, err)
assert.Equal(t, "application/json", w.Header().Get("Content-Type"))
assert.Equal(t, 511, w.StatusCode)
assert.NotNil(t, w.Data)
}

func TestCodecForRequest(t *testing.T) {
req1 := &nethttp.Request{
Header: make(nethttp.Header),
Body: ioutil.NopCloser(bytes.NewBufferString("<xml></xml>")),
}
req1.Header.Set("Content-Type", "application/xml")

c, ok := CodecForRequest(req1, "Content-Type")
assert.True(t, ok)
assert.Equal(t, "xml", c.Name())

req2 := &nethttp.Request{
Header: make(nethttp.Header),
Body: ioutil.NopCloser(bytes.NewBufferString("{\"a\":\"1\", \"b\": 2}")),
}
req2.Header.Set("Content-Type", "blablablabla")

c, ok = CodecForRequest(req2, "Content-Type")
assert.False(t, ok)
assert.Equal(t, "json", c.Name())
}
33 changes: 33 additions & 0 deletions transport/http/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/go-kratos/kratos/v2/internal/host"
"github.com/stretchr/testify/assert"
)

type testKey struct{}
Expand Down Expand Up @@ -103,3 +104,35 @@ func testClient(t *testing.T, srv *Server) {
}

}

func BenchmarkServer(b *testing.B) {
fn := func(w http.ResponseWriter, r *http.Request) {
data := &testData{Path: r.RequestURI}
json.NewEncoder(w).Encode(data)
if r.Context().Value(testKey{}) != "test" {
w.WriteHeader(500)
}
}
ctx := context.Background()
ctx = context.WithValue(ctx, testKey{}, "test")
srv := NewServer()
srv.HandleFunc("/index", fn)
go func() {
if err := srv.Start(ctx); err != nil {
panic(err)
}
}()
time.Sleep(time.Second)
port, ok := host.Port(srv.lis)
assert.True(b, ok)
client, err := NewClient(context.Background(), WithEndpoint(fmt.Sprintf("127.0.0.1:%d", port)))
assert.NoError(b, err)

b.ResetTimer()
for i := 0; i < b.N; i++ {
var res testData
err := client.Invoke(context.Background(), "POST", "/index", nil, &res)
assert.NoError(b, err)
}
srv.Stop(ctx)
}

0 comments on commit 0ff1c6f

Please sign in to comment.