* test http
* fix response codec
* benchmark
pull/1055/head v2.0.0-rc3
Windfarer 4 years ago committed by GitHub
parent dc80d0865f
commit 0ff1c6f89a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      go.mod
  2. 1
      go.sum
  3. 2
      transport/http/client.go
  4. 174
      transport/http/client_test.go
  5. 108
      transport/http/codec_test.go
  6. 33
      transport/http/server_test.go

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

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

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

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

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

@ -10,6 +10,7 @@ import (
"time"
"github.com/go-kratos/kratos/v2/internal/host"
"github.com/stretchr/testify/assert"
)
type testKey struct{}
@ -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)
}

Loading…
Cancel
Save