storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/rpc/json2/json_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Copyright 2012 The Gorilla Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 // Copyright 2020 MinIO, Inc. All rights reserved. 7 // forked from https://github.com/gorilla/rpc/v2 8 // modified to be used with MinIO under Apache 9 // 2.0 license that can be found in the LICENSE file. 10 11 package json2 12 13 import ( 14 "bytes" 15 "encoding/json" 16 "errors" 17 "net/http" 18 "strings" 19 "testing" 20 21 "storj.io/minio/pkg/rpc" 22 ) 23 24 // ResponseRecorder is an implementation of http.ResponseWriter that 25 // records its mutations for later inspection in tests. 26 type ResponseRecorder struct { 27 Code int // the HTTP response code from WriteHeader 28 HeaderMap http.Header // the HTTP response headers 29 Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to 30 Flushed bool 31 } 32 33 // NewRecorder returns an initialized ResponseRecorder. 34 func NewRecorder() *ResponseRecorder { 35 return &ResponseRecorder{ 36 HeaderMap: make(http.Header), 37 Body: new(bytes.Buffer), 38 } 39 } 40 41 // DefaultRemoteAddr is the default remote address to return in RemoteAddr if 42 // an explicit DefaultRemoteAddr isn't set on ResponseRecorder. 43 const DefaultRemoteAddr = "1.2.3.4" 44 45 // Header returns the response headers. 46 func (rw *ResponseRecorder) Header() http.Header { 47 return rw.HeaderMap 48 } 49 50 // Write always succeeds and writes to rw.Body, if not nil. 51 func (rw *ResponseRecorder) Write(buf []byte) (int, error) { 52 if rw.Body != nil { 53 rw.Body.Write(buf) 54 } 55 if rw.Code == 0 { 56 rw.Code = http.StatusOK 57 } 58 return len(buf), nil 59 } 60 61 // WriteHeader sets rw.Code. 62 func (rw *ResponseRecorder) WriteHeader(code int) { 63 rw.Code = code 64 } 65 66 // Flush sets rw.Flushed to true. 67 func (rw *ResponseRecorder) Flush() { 68 rw.Flushed = true 69 } 70 71 // ---------------------------------------------------------------------------- 72 73 var ErrResponseError = errors.New("response error") 74 var ErrMappedResponseError = errors.New("mapped response error") 75 76 type Service1Request struct { 77 A int 78 B int 79 } 80 81 type Service1NoParamsRequest struct { 82 V string `json:"jsonrpc"` 83 M string `json:"method"` 84 ID uint64 `json:"id"` 85 } 86 87 type Service1ParamsArrayRequest struct { 88 V string `json:"jsonrpc"` 89 P []struct { 90 T string 91 } `json:"params"` 92 M string `json:"method"` 93 ID uint64 `json:"id"` 94 } 95 96 type Service1Response struct { 97 Result int 98 } 99 100 type Service1 struct { 101 } 102 103 const Service1DefaultResponse = 9999 104 105 func (t *Service1) Multiply(r *http.Request, req *Service1Request, res *Service1Response) error { 106 if req.A == 0 && req.B == 0 { 107 // Sentinel value for test with no params. 108 res.Result = Service1DefaultResponse 109 } else { 110 res.Result = req.A * req.B 111 } 112 return nil 113 } 114 115 func (t *Service1) ResponseError(r *http.Request, req *Service1Request, res *Service1Response) error { 116 return ErrResponseError 117 } 118 119 func (t *Service1) MappedResponseError(r *http.Request, req *Service1Request, res *Service1Response) error { 120 return ErrMappedResponseError 121 } 122 123 func execute(t *testing.T, s *rpc.Server, method string, req, res interface{}) error { 124 if !s.HasMethod(method) { 125 t.Fatal("Expected to be registered:", method) 126 } 127 128 buf, _ := EncodeClientRequest(method, req) 129 body := bytes.NewBuffer(buf) 130 r, _ := http.NewRequest("POST", "http://localhost:8080/", body) 131 r.Header.Set("Content-Type", "application/json") 132 133 w := NewRecorder() 134 s.ServeHTTP(w, r) 135 136 return DecodeClientResponse(w.Body, res) 137 } 138 139 func executeRaw(t *testing.T, s *rpc.Server, req interface{}, res interface{}) error { 140 j, _ := json.Marshal(req) 141 r, _ := http.NewRequest("POST", "http://localhost:8080/", bytes.NewBuffer(j)) 142 r.Header.Set("Content-Type", "application/json") 143 144 w := NewRecorder() 145 s.ServeHTTP(w, r) 146 147 return DecodeClientResponse(w.Body, res) 148 } 149 150 func executeInvalidJSON(t *testing.T, s *rpc.Server, res interface{}) error { 151 r, _ := http.NewRequest("POST", "http://localhost:8080/", strings.NewReader(`not even a json`)) 152 r.Header.Set("Content-Type", "application/json") 153 154 w := NewRecorder() 155 s.ServeHTTP(w, r) 156 157 return DecodeClientResponse(w.Body, res) 158 } 159 160 func TestService(t *testing.T) { 161 s := rpc.NewServer() 162 s.RegisterCodec(NewCodec(), "application/json") 163 s.RegisterService(new(Service1), "") 164 165 var res Service1Response 166 if err := execute(t, s, "Service1.Multiply", &Service1Request{4, 2}, &res); err != nil { 167 t.Error("Expected err to be nil, but got:", err) 168 } 169 if res.Result != 8 { 170 t.Errorf("Wrong response: %v.", res.Result) 171 } 172 173 if err := execute(t, s, "Service1.ResponseError", &Service1Request{4, 2}, &res); err == nil { 174 t.Errorf("Expected to get %q, but got nil", ErrResponseError) 175 } else if err.Error() != ErrResponseError.Error() { 176 t.Errorf("Expected to get %q, but got %q", ErrResponseError, err) 177 } 178 179 // No parameters. 180 res = Service1Response{} 181 if err := executeRaw(t, s, &Service1NoParamsRequest{"2.0", "Service1.Multiply", 1}, &res); err != nil { 182 t.Error(err) 183 } 184 if res.Result != Service1DefaultResponse { 185 t.Errorf("Wrong response: got %v, want %v", res.Result, Service1DefaultResponse) 186 } 187 188 // Parameters as by-position. 189 res = Service1Response{} 190 req := Service1ParamsArrayRequest{ 191 V: "2.0", 192 P: []struct { 193 T string 194 }{{ 195 T: "test", 196 }}, 197 M: "Service1.Multiply", 198 ID: 1, 199 } 200 if err := executeRaw(t, s, &req, &res); err != nil { 201 t.Error(err) 202 } 203 if res.Result != Service1DefaultResponse { 204 t.Errorf("Wrong response: got %v, want %v", res.Result, Service1DefaultResponse) 205 } 206 207 res = Service1Response{} 208 if err := executeInvalidJSON(t, s, &res); err == nil { 209 t.Error("Expected to receive an E_PARSE error, but got nil") 210 } else if jsonRpcErr, ok := err.(*Error); !ok { 211 t.Errorf("Expected to receive an Error, but got %T: %s", err, err) 212 } else if jsonRpcErr.Code != E_PARSE { 213 t.Errorf("Expected to receive an E_PARSE JSON-RPC error (%d) but got %d", E_PARSE, jsonRpcErr.Code) 214 } 215 } 216 217 func TestServiceWithErrorMapper(t *testing.T) { 218 const mappedErrorCode = 100 219 220 // errorMapper maps ErrMappedResponseError to an Error with mappedErrorCode Code, everything else is returned as-is 221 errorMapper := func(err error) error { 222 if err == ErrMappedResponseError { 223 return &Error{ 224 Code: mappedErrorCode, 225 Message: err.Error(), 226 } 227 } 228 // Map everything else to E_SERVER 229 return &Error{ 230 Code: E_SERVER, 231 Message: err.Error(), 232 } 233 } 234 235 s := rpc.NewServer() 236 s.RegisterCodec(NewCustomCodecWithErrorMapper(rpc.DefaultEncoderSelector, errorMapper), "application/json") 237 s.RegisterService(new(Service1), "") 238 239 var res Service1Response 240 if err := execute(t, s, "Service1.MappedResponseError", &Service1Request{4, 2}, &res); err == nil { 241 t.Errorf("Expected to get a JSON-RPC error, but got nil") 242 } else if jsonRpcErr, ok := err.(*Error); !ok { 243 t.Errorf("Expected to get an *Error, but got %T: %s", err, err) 244 } else if jsonRpcErr.Code != mappedErrorCode { 245 t.Errorf("Expected to get Code %d, but got %d", mappedErrorCode, jsonRpcErr.Code) 246 } else if jsonRpcErr.Message != ErrMappedResponseError.Error() { 247 t.Errorf("Expected to get Message %q, but got %q", ErrMappedResponseError.Error(), jsonRpcErr.Message) 248 } 249 250 // Unmapped error behaves as usual 251 if err := execute(t, s, "Service1.ResponseError", &Service1Request{4, 2}, &res); err == nil { 252 t.Errorf("Expected to get a JSON-RPC error, but got nil") 253 } else if jsonRpcErr, ok := err.(*Error); !ok { 254 t.Errorf("Expected to get an *Error, but got %T: %s", err, err) 255 } else if jsonRpcErr.Code != E_SERVER { 256 t.Errorf("Expected to get Code %d, but got %d", E_SERVER, jsonRpcErr.Code) 257 } else if jsonRpcErr.Message != ErrResponseError.Error() { 258 t.Errorf("Expected to get Message %q, but got %q", ErrResponseError.Error(), jsonRpcErr.Message) 259 } 260 261 // Malformed request without method: our framework tries to return an error: we shouldn't map that one 262 malformedRequest := struct { 263 V string `json:"jsonrpc"` 264 ID string `json:"id"` 265 }{ 266 V: "3.0", 267 ID: "any", 268 } 269 if err := executeRaw(t, s, &malformedRequest, &res); err == nil { 270 t.Errorf("Expected to get a JSON-RPC error, but got nil") 271 } else if jsonRpcErr, ok := err.(*Error); !ok { 272 t.Errorf("Expected to get an *Error, but got %T: %s", err, err) 273 } else if jsonRpcErr.Code != E_INVALID_REQ { 274 t.Errorf("Expected to get an E_INVALID_REQ error (%d), but got %d", E_INVALID_REQ, jsonRpcErr.Code) 275 } 276 } 277 278 func TestDecodeNullResult(t *testing.T) { 279 data := `{"jsonrpc": "2.0", "id": 12345, "result": null}` 280 reader := bytes.NewReader([]byte(data)) 281 var result interface{} 282 283 err := DecodeClientResponse(reader, &result) 284 285 if err != ErrNullResult { 286 t.Error("Expected err no be ErrNullResult, but got:", err) 287 } 288 289 if result != nil { 290 t.Error("Expected result to be nil, but got:", result) 291 } 292 }