OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / tendermint / tmlibs / common / http_test.go
1 package common_test
2
3 import (
4         "bytes"
5         "encoding/json"
6         "errors"
7         "io"
8         "io/ioutil"
9         "net/http"
10         "net/http/httptest"
11         "reflect"
12         "strings"
13         "sync"
14         "testing"
15
16         "github.com/stretchr/testify/assert"
17         "github.com/stretchr/testify/require"
18
19         "github.com/tendermint/tmlibs/common"
20 )
21
22 func TestWriteSuccess(t *testing.T) {
23         w := httptest.NewRecorder()
24         common.WriteSuccess(w, "foo")
25         assert.Equal(t, w.Code, 200, "should get a 200")
26 }
27
28 var blankErrResponse = new(common.ErrorResponse)
29
30 func TestWriteError(t *testing.T) {
31         tests := [...]struct {
32                 msg  string
33                 code int
34         }{
35                 0: {
36                         msg:  "this is a message",
37                         code: 419,
38                 },
39         }
40
41         for i, tt := range tests {
42                 w := httptest.NewRecorder()
43                 msg := tt.msg
44
45                 // First check without a defined code, should send back a 400
46                 common.WriteError(w, errors.New(msg))
47                 assert.Equal(t, w.Code, http.StatusBadRequest, "#%d: should get a 400", i)
48                 blob, err := ioutil.ReadAll(w.Body)
49                 if err != nil {
50                         assert.Fail(t, "expecting a successful ioutil.ReadAll", "#%d", i)
51                         continue
52                 }
53
54                 recv := new(common.ErrorResponse)
55                 if err := json.Unmarshal(blob, recv); err != nil {
56                         assert.Fail(t, "expecting a successful json.Unmarshal", "#%d", i)
57                         continue
58                 }
59
60                 assert.Equal(t, reflect.DeepEqual(recv, blankErrResponse), false, "expecting a non-blank error response")
61
62                 // Now test with an error that's .HTTPCode() int conforming
63
64                 // Reset w
65                 w = httptest.NewRecorder()
66
67                 common.WriteError(w, common.ErrorWithCode(errors.New("foo"), tt.code))
68                 assert.Equal(t, w.Code, tt.code, "case #%d", i)
69         }
70 }
71
72 type marshalFailer struct{}
73
74 var errFooFailed = errors.New("foo failed here")
75
76 func (mf *marshalFailer) MarshalJSON() ([]byte, error) {
77         return nil, errFooFailed
78 }
79
80 func TestWriteCode(t *testing.T) {
81         codes := [...]int{
82                 0: http.StatusOK,
83                 1: http.StatusBadRequest,
84                 2: http.StatusUnauthorized,
85                 3: http.StatusInternalServerError,
86         }
87
88         for i, code := range codes {
89                 w := httptest.NewRecorder()
90                 common.WriteCode(w, "foo", code)
91                 assert.Equal(t, w.Code, code, "#%d", i)
92
93                 // Then for the failed JSON marshaling
94                 w = httptest.NewRecorder()
95                 common.WriteCode(w, &marshalFailer{}, code)
96                 wantCode := http.StatusBadRequest
97                 assert.Equal(t, w.Code, wantCode, "#%d", i)
98                 assert.True(t, strings.Contains(w.Body.String(), errFooFailed.Error()),
99                         "#%d: expected %q in the error message", i, errFooFailed)
100         }
101 }
102
103 type saver struct {
104         Foo int    `json:"foo" validate:"min=10"`
105         Bar string `json:"bar"`
106 }
107
108 type rcloser struct {
109         closeOnce sync.Once
110         body      *bytes.Buffer
111         closeChan chan bool
112 }
113
114 var errAlreadyClosed = errors.New("already closed")
115
116 func (rc *rcloser) Close() error {
117         var err = errAlreadyClosed
118         rc.closeOnce.Do(func() {
119                 err = nil
120                 rc.closeChan <- true
121                 close(rc.closeChan)
122         })
123         return err
124 }
125
126 func (rc *rcloser) Read(b []byte) (int, error) {
127         return rc.body.Read(b)
128 }
129
130 var _ io.ReadCloser = (*rcloser)(nil)
131
132 func makeReq(strBody string) (*http.Request, <-chan bool) {
133         closeChan := make(chan bool, 1)
134         buf := new(bytes.Buffer)
135         buf.Write([]byte(strBody))
136         req := &http.Request{
137                 Header: make(http.Header),
138                 Body:   &rcloser{body: buf, closeChan: closeChan},
139         }
140         return req, closeChan
141 }
142
143 func TestParseRequestJSON(t *testing.T) {
144         tests := [...]struct {
145                 body    string
146                 wantErr bool
147                 useNil  bool
148         }{
149                 0: {wantErr: true, body: ``},
150                 1: {body: `{}`},
151                 2: {body: `{"foo": 2}`}, // Not that the validate tags don't matter here since we are just parsing
152                 3: {body: `{"foo": "abcd"}`, wantErr: true},
153                 4: {useNil: true, wantErr: true},
154         }
155
156         for i, tt := range tests {
157                 req, closeChan := makeReq(tt.body)
158                 if tt.useNil {
159                         req.Body = nil
160                 }
161                 sav := new(saver)
162                 err := common.ParseRequestJSON(req, sav)
163                 if tt.wantErr {
164                         assert.NotEqual(t, err, nil, "#%d: want non-nil error", i)
165                         continue
166                 }
167                 assert.Equal(t, err, nil, "#%d: want nil error", i)
168                 wasClosed := <-closeChan
169                 assert.Equal(t, wasClosed, true, "#%d: should have invoked close", i)
170         }
171 }
172
173 func TestFparseJSON(t *testing.T) {
174         r1 := strings.NewReader(`{"foo": 1}`)
175         sav := new(saver)
176         require.Equal(t, common.FparseJSON(r1, sav), nil, "expecting successful parsing")
177         r2 := strings.NewReader(`{"bar": "blockchain"}`)
178         require.Equal(t, common.FparseJSON(r2, sav), nil, "expecting successful parsing")
179         require.Equal(t, reflect.DeepEqual(sav, &saver{Foo: 1, Bar: "blockchain"}), true, "should have parsed both")
180
181         // Now with a nil body
182         require.NotEqual(t, nil, common.FparseJSON(nil, sav), "expecting a nil error report")
183 }
184
185 func TestFparseAndValidateJSON(t *testing.T) {
186         r1 := strings.NewReader(`{"foo": 1}`)
187         sav := new(saver)
188         require.NotEqual(t, common.FparseAndValidateJSON(r1, sav), nil, "expecting validation to fail")
189         r1 = strings.NewReader(`{"foo": 100}`)
190         require.Equal(t, common.FparseJSON(r1, sav), nil, "expecting successful parsing")
191         r2 := strings.NewReader(`{"bar": "blockchain"}`)
192         require.Equal(t, common.FparseAndValidateJSON(r2, sav), nil, "expecting successful parsing")
193         require.Equal(t, reflect.DeepEqual(sav, &saver{Foo: 100, Bar: "blockchain"}), true, "should have parsed both")
194
195         // Now with a nil body
196         require.NotEqual(t, nil, common.FparseJSON(nil, sav), "expecting a nil error report")
197 }
198
199 var blankSaver = new(saver)
200
201 func TestParseAndValidateRequestJSON(t *testing.T) {
202         tests := [...]struct {
203                 body    string
204                 wantErr bool
205                 useNil  bool
206         }{
207                 0: {wantErr: true, body: ``},
208                 1: {body: `{}`, wantErr: true},         // Here it should fail since Foo doesn't meet the minimum value
209                 2: {body: `{"foo": 2}`, wantErr: true}, // Here validation should fail
210                 3: {body: `{"foo": "abcd"}`, wantErr: true},
211                 4: {useNil: true, wantErr: true},
212                 5: {body: `{"foo": 100}`}, // Must succeed
213         }
214
215         for i, tt := range tests {
216                 req, closeChan := makeReq(tt.body)
217                 if tt.useNil {
218                         req.Body = nil
219                 }
220                 sav := new(saver)
221                 err := common.ParseRequestAndValidateJSON(req, sav)
222                 if tt.wantErr {
223                         assert.NotEqual(t, err, nil, "#%d: want non-nil error", i)
224                         continue
225                 }
226
227                 assert.Equal(t, err, nil, "#%d: want nil error", i)
228                 assert.False(t, reflect.DeepEqual(blankSaver, sav), "#%d: expecting a set saver", i)
229
230                 wasClosed := <-closeChan
231                 assert.Equal(t, wasClosed, true, "#%d: should have invoked close", i)
232         }
233 }
234
235 func TestErrorWithCode(t *testing.T) {
236         tests := [...]struct {
237                 code int
238                 err  error
239         }{
240                 0: {code: 500, err: errors.New("funky")},
241                 1: {code: 406, err: errors.New("purist")},
242         }
243
244         for i, tt := range tests {
245                 errRes := common.ErrorWithCode(tt.err, tt.code)
246                 assert.Equal(t, errRes.Error(), tt.err.Error(), "#%d: expecting the error values to be equal", i)
247                 assert.Equal(t, errRes.Code, tt.code, "expecting the same status code", i)
248                 assert.Equal(t, errRes.HTTPCode(), tt.code, "expecting the same status code", i)
249         }
250 }