Skip to content

Commit 8fdcb89

Browse files
committed
Merge pull request #14 from qiniu/develop
Release v7.0.7: qiniupkg.com/x/{jsonutil.v7, mockhttp.v7, ts.v7}
2 parents 0a6d002 + c34dcb4 commit 8fdcb89

File tree

6 files changed

+345
-0
lines changed

6 files changed

+345
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@ go get qiniupkg.com/x
1414
* [qiniupkg.com/x/bytes.v7](http://godoc.org/qiniupkg.com/x/bytes.v7)
1515
* [qiniupkg.com/x/config.v7](http://godoc.org/qiniupkg.com/x/config.v7)
1616
* [qiniupkg.com/x/ctype.v7](http://godoc.org/qiniupkg.com/x/ctype.v7)
17+
* [qiniupkg.com/x/jsonutil.v7](http://godoc.org/qiniupkg.com/x/jsonutil.v7)
1718
* [qiniupkg.com/x/log.v7](http://godoc.org/qiniupkg.com/x/log.v7)
19+
* [qiniupkg.com/x/mockhttp.v7](http://godoc.org/qiniupkg.com/x/mockhttp.v7)
1820
* [qiniupkg.com/x/reqid.v7](http://godoc.org/qiniupkg.com/x/reqid.v7)
1921
* [qiniupkg.com/x/rpc.v7](http://godoc.org/qiniupkg.com/x/rpc.v7)
2022
* [qiniupkg.com/x/rpc.v7/gob](http://godoc.org/qiniupkg.com/x/rpc.v7/gob)
23+
* [qiniupkg.com/x/ts.v7](http://godoc.org/qiniupkg.com/x/ts.v7)
2124
* [qiniupkg.com/x/url.v7](http://godoc.org/qiniupkg.com/x/url.v7)
2225
* [qiniupkg.com/x/xlog.v7](http://godoc.org/qiniupkg.com/x/xlog.v7)
26+

jsonutil.v7/unmarshal_string.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package jsonutil
2+
3+
import (
4+
"encoding/json"
5+
"reflect"
6+
"unsafe"
7+
)
8+
9+
// ----------------------------------------------------------
10+
11+
func Unmarshal(data string, v interface{}) error {
12+
13+
sh := *(*reflect.StringHeader)(unsafe.Pointer(&data))
14+
arr := (*[1<<30]byte)(unsafe.Pointer(sh.Data))
15+
return json.Unmarshal(arr[:sh.Len], v)
16+
}
17+
18+
// ----------------------------------------------------------
19+

jsonutil.v7/unmarshal_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package jsonutil
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func Test(t *testing.T) {
8+
9+
var ret struct {
10+
Id string `json:"id"`
11+
}
12+
err := Unmarshal(`{"id": "123"}`, &ret)
13+
if err != nil {
14+
t.Fatal("Unmarshal failed:", err)
15+
}
16+
if ret.Id != "123" {
17+
t.Fatal("Unmarshal uncorrect:", ret.Id)
18+
}
19+
}

mockhttp.v7/mockhttp.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package mockhttp
2+
3+
import (
4+
"errors"
5+
"io"
6+
"io/ioutil"
7+
"net/http"
8+
"net/http/httptest"
9+
"strconv"
10+
11+
"qiniupkg.com/x/log.v7"
12+
)
13+
14+
var (
15+
ErrServerNotFound = errors.New("server not found")
16+
)
17+
18+
// --------------------------------------------------------------------
19+
20+
type mockServerRequestBody struct {
21+
reader io.Reader
22+
closeSignal bool
23+
}
24+
25+
func (r *mockServerRequestBody) Read(p []byte) (int, error) {
26+
if r.closeSignal || r.reader == nil {
27+
return 0, io.EOF
28+
}
29+
return r.reader.Read(p)
30+
}
31+
32+
func (r *mockServerRequestBody) Close() error {
33+
r.closeSignal = true
34+
if c, ok := r.reader.(io.Closer); ok {
35+
return c.Close()
36+
}
37+
return nil
38+
}
39+
40+
// --------------------------------------------------------------------
41+
// type Transport
42+
43+
type Transport struct {
44+
route map[string]http.Handler
45+
}
46+
47+
func NewTransport() *Transport {
48+
49+
return &Transport{
50+
route: make(map[string]http.Handler),
51+
}
52+
}
53+
54+
func (p *Transport) ListenAndServe(host string, h http.Handler) {
55+
56+
if h == nil {
57+
h = http.DefaultServeMux
58+
}
59+
p.route[host] = h
60+
}
61+
62+
func (p *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
63+
64+
h := p.route[req.URL.Host]
65+
if h == nil {
66+
log.Warn("Server not found:", req.Host)
67+
return nil, ErrServerNotFound
68+
}
69+
70+
cp := *req
71+
cp.URL.Scheme = ""
72+
cp.URL.Host = ""
73+
cp.RemoteAddr = "127.0.0.1:8000"
74+
cp.Body = &mockServerRequestBody{req.Body, false}
75+
req = &cp
76+
77+
rw := httptest.NewRecorder()
78+
h.ServeHTTP(rw, req)
79+
80+
req.Body.Close()
81+
82+
ctlen := int64(-1)
83+
if v := rw.HeaderMap.Get("Content-Length"); v != "" {
84+
ctlen, _ = strconv.ParseInt(v, 10, 64)
85+
}
86+
87+
return &http.Response{
88+
Status: "",
89+
StatusCode: rw.Code,
90+
Header: rw.HeaderMap,
91+
Body: ioutil.NopCloser(rw.Body),
92+
ContentLength: ctlen,
93+
TransferEncoding: nil,
94+
Close: false,
95+
Trailer: nil,
96+
Request: req,
97+
}, nil
98+
}
99+
100+
// --------------------------------------------------------------------
101+
102+
var DefaultTransport = NewTransport()
103+
var DefaultClient = &http.Client{Transport: DefaultTransport}
104+
105+
func ListenAndServe(host string, h http.Handler) {
106+
107+
DefaultTransport.ListenAndServe(host, h)
108+
}
109+
110+
// --------------------------------------------------------------------

mockhttp.v7/mockhttp_test.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package mockhttp_test
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"io/ioutil"
8+
"net/http"
9+
"strconv"
10+
"strings"
11+
"testing"
12+
13+
"qiniupkg.com/x/mockhttp.v7"
14+
"qiniupkg.com/x/rpc.v7"
15+
)
16+
17+
// --------------------------------------------------------------------
18+
19+
func reply(w http.ResponseWriter, code int, data interface{}) {
20+
21+
msg, _ := json.Marshal(data)
22+
h := w.Header()
23+
h.Set("Content-Length", strconv.Itoa(len(msg)))
24+
h.Set("Content-Type", "application/json")
25+
w.WriteHeader(code)
26+
w.Write(msg)
27+
}
28+
29+
// --------------------------------------------------------------------
30+
31+
type FooRet struct {
32+
A int `json:"a"`
33+
B string `json:"b"`
34+
C string `json:"c"`
35+
}
36+
37+
type HandleRet map[string]string
38+
39+
type FooServer struct{}
40+
41+
func (p *FooServer) foo(w http.ResponseWriter, req *http.Request) {
42+
reply(w, 200, &FooRet{1, req.Host, req.URL.Path})
43+
}
44+
45+
func (p *FooServer) handle(w http.ResponseWriter, req *http.Request) {
46+
reply(w, 200, HandleRet{"foo": "1", "bar": "2"})
47+
}
48+
49+
func (p *FooServer) postDump(w http.ResponseWriter, req *http.Request) {
50+
req.Body.Close()
51+
io.Copy(w, req.Body)
52+
}
53+
54+
func (p *FooServer) RegisterHandlers(mux *http.ServeMux) {
55+
mux.HandleFunc("/foo", func(w http.ResponseWriter, req *http.Request) { p.foo(w, req) })
56+
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { p.handle(w, req) })
57+
mux.HandleFunc("/dump", func(w http.ResponseWriter, req *http.Request) { p.postDump(w, req) })
58+
}
59+
60+
// --------------------------------------------------------------------
61+
62+
func TestBasic(t *testing.T) {
63+
64+
server := new(FooServer)
65+
server.RegisterHandlers(http.DefaultServeMux)
66+
67+
mockhttp.ListenAndServe("foo.com", nil)
68+
69+
c := rpc.Client{mockhttp.DefaultClient}
70+
{
71+
var foo FooRet
72+
err := c.Call(nil, &foo, "POST", "http://foo.com/foo")
73+
if err != nil {
74+
t.Fatal("call foo failed:", err)
75+
}
76+
if foo.A != 1 || foo.B != "foo.com" || foo.C != "/foo" {
77+
t.Fatal("call foo: invalid ret")
78+
}
79+
fmt.Println(foo)
80+
}
81+
{
82+
var ret map[string]string
83+
err := c.Call(nil, &ret, "POST", "http://foo.com/bar")
84+
if err != nil {
85+
t.Fatal("call foo failed:", err)
86+
}
87+
if ret["foo"] != "1" || ret["bar"] != "2" {
88+
t.Fatal("call bar: invalid ret")
89+
}
90+
fmt.Println(ret)
91+
}
92+
{
93+
resp, err := c.Post("http://foo.com/dump", "", nil)
94+
if err != nil {
95+
t.Fatal("post foo failed:", err)
96+
}
97+
resp.Body.Close()
98+
resp, err = c.Post("http://foo.com/dump", "", strings.NewReader("abc"))
99+
if err != nil {
100+
t.Fatal("post foo failed:", err)
101+
}
102+
defer resp.Body.Close()
103+
b, err := ioutil.ReadAll(resp.Body)
104+
if err != nil {
105+
t.Fatal("ioutil.ReadAll:", err)
106+
}
107+
if len(b) != 0 {
108+
t.Fatal("body should be empty:", string(b))
109+
}
110+
}
111+
}
112+
113+
// --------------------------------------------------------------------
114+

ts.v7/testing.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package ts
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"runtime"
8+
"strconv"
9+
"testing"
10+
)
11+
12+
const logStackLevel = 2
13+
14+
func log(skip int, t *testing.T, args ...interface{}) {
15+
16+
_, file, line, _ := runtime.Caller(skip)
17+
_, fname := filepath.Split(file)
18+
args1 := make([]interface{}, len(args)+1)
19+
args1[0] = fname + ":" + strconv.Itoa(line) + ":"
20+
copy(args1[1:], args)
21+
22+
if os.PathSeparator == '/' {
23+
fmt.Fprintln(os.Stdout, args1...)
24+
} else {
25+
t.Log(args1...)
26+
}
27+
}
28+
29+
func logf(skip int, t *testing.T, format string, args ...interface{}) {
30+
31+
_, file, line, _ := runtime.Caller(skip)
32+
_, fname := filepath.Split(file)
33+
args2 := make([]interface{}, len(args)+2)
34+
args2[0] = fname
35+
args2[1] = line
36+
copy(args2[2:], args)
37+
38+
if os.PathSeparator == '/' {
39+
fmt.Fprintf(os.Stderr, "%s:%d: "+format+"\n", args2...)
40+
} else {
41+
t.Logf("%s:%d: "+format, args2...)
42+
}
43+
}
44+
45+
// Log formats its arguments using default formatting, analogous to Print(),
46+
// and records the text in the error log.
47+
func Log(t *testing.T, args ...interface{}) {
48+
log(logStackLevel, t, args...)
49+
}
50+
51+
// Logf formats its arguments according to the format, analogous to Printf(),
52+
// and records the text in the error log.
53+
func Logf(t *testing.T, format string, args ...interface{}) {
54+
logf(logStackLevel, t, format, args...)
55+
}
56+
57+
// Error is equivalent to Log() followed by Fail().
58+
func Error(t *testing.T, args ...interface{}) {
59+
log(logStackLevel, t, args...)
60+
t.Fail()
61+
}
62+
63+
// Errorf is equivalent to Logf() followed by Fail().
64+
func Errorf(t *testing.T, format string, args ...interface{}) {
65+
logf(logStackLevel, t, format, args...)
66+
t.Fail()
67+
}
68+
69+
// Fatal is equivalent to Log() followed by FailNow().
70+
func Fatal(t *testing.T, args ...interface{}) {
71+
log(logStackLevel, t, args...)
72+
t.FailNow()
73+
}
74+
75+
// Fatalf is equivalent to Logf() followed by FailNow().
76+
func Fatalf(t *testing.T, format string, args ...interface{}) {
77+
logf(logStackLevel, t, format, args...)
78+
t.FailNow()
79+
}

0 commit comments

Comments
 (0)