1
2
3
4
5 package jsonrpc
6
7 import (
8 "bytes"
9 "encoding/json"
10 "errors"
11 "fmt"
12 "io"
13 "net"
14 "net/rpc"
15 "reflect"
16 "strings"
17 "testing"
18 )
19
20 type Args struct {
21 A, B int
22 }
23
24 type Reply struct {
25 C int
26 }
27
28 type Arith int
29
30 type ArithAddResp struct {
31 Id any `json:"id"`
32 Result Reply `json:"result"`
33 Error any `json:"error"`
34 }
35
36 func (t *Arith) Add(args *Args, reply *Reply) error {
37 reply.C = args.A + args.B
38 return nil
39 }
40
41 func (t *Arith) Mul(args *Args, reply *Reply) error {
42 reply.C = args.A * args.B
43 return nil
44 }
45
46 func (t *Arith) Div(args *Args, reply *Reply) error {
47 if args.B == 0 {
48 return errors.New("divide by zero")
49 }
50 reply.C = args.A / args.B
51 return nil
52 }
53
54 func (t *Arith) Error(args *Args, reply *Reply) error {
55 panic("ERROR")
56 }
57
58 type BuiltinTypes struct{}
59
60 func (BuiltinTypes) Map(i int, reply *map[int]int) error {
61 (*reply)[i] = i
62 return nil
63 }
64
65 func (BuiltinTypes) Slice(i int, reply *[]int) error {
66 *reply = append(*reply, i)
67 return nil
68 }
69
70 func (BuiltinTypes) Array(i int, reply *[1]int) error {
71 (*reply)[0] = i
72 return nil
73 }
74
75 func init() {
76 rpc.Register(new(Arith))
77 rpc.Register(BuiltinTypes{})
78 }
79
80 func TestServerNoParams(t *testing.T) {
81 cli, srv := net.Pipe()
82 defer cli.Close()
83 go ServeConn(srv)
84 dec := json.NewDecoder(cli)
85
86 fmt.Fprintf(cli, `{"method": "Arith.Add", "id": "123"}`)
87 var resp ArithAddResp
88 if err := dec.Decode(&resp); err != nil {
89 t.Fatalf("Decode after no params: %s", err)
90 }
91 if resp.Error == nil {
92 t.Fatalf("Expected error, got nil")
93 }
94 }
95
96 func TestServerEmptyMessage(t *testing.T) {
97 cli, srv := net.Pipe()
98 defer cli.Close()
99 go ServeConn(srv)
100 dec := json.NewDecoder(cli)
101
102 fmt.Fprintf(cli, "{}")
103 var resp ArithAddResp
104 if err := dec.Decode(&resp); err != nil {
105 t.Fatalf("Decode after empty: %s", err)
106 }
107 if resp.Error == nil {
108 t.Fatalf("Expected error, got nil")
109 }
110 }
111
112 func TestServer(t *testing.T) {
113 cli, srv := net.Pipe()
114 defer cli.Close()
115 go ServeConn(srv)
116 dec := json.NewDecoder(cli)
117
118
119 for i := 0; i < 10; i++ {
120 fmt.Fprintf(cli, `{"method": "Arith.Add", "id": "\u%04d", "params": [{"A": %d, "B": %d}]}`, i, i, i+1)
121 var resp ArithAddResp
122 err := dec.Decode(&resp)
123 if err != nil {
124 t.Fatalf("Decode: %s", err)
125 }
126 if resp.Error != nil {
127 t.Fatalf("resp.Error: %s", resp.Error)
128 }
129 if resp.Id.(string) != string(rune(i)) {
130 t.Fatalf("resp: bad id %q want %q", resp.Id.(string), string(rune(i)))
131 }
132 if resp.Result.C != 2*i+1 {
133 t.Fatalf("resp: bad result: %d+%d=%d", i, i+1, resp.Result.C)
134 }
135 }
136 }
137
138 func TestClient(t *testing.T) {
139
140
141 cli, srv := net.Pipe()
142 go ServeConn(srv)
143
144 client := NewClient(cli)
145 defer client.Close()
146
147
148 args := &Args{7, 8}
149 reply := new(Reply)
150 err := client.Call("Arith.Add", args, reply)
151 if err != nil {
152 t.Errorf("Add: expected no error but got string %q", err.Error())
153 }
154 if reply.C != args.A+args.B {
155 t.Errorf("Add: got %d expected %d", reply.C, args.A+args.B)
156 }
157
158 args = &Args{7, 8}
159 reply = new(Reply)
160 err = client.Call("Arith.Mul", args, reply)
161 if err != nil {
162 t.Errorf("Mul: expected no error but got string %q", err.Error())
163 }
164 if reply.C != args.A*args.B {
165 t.Errorf("Mul: got %d expected %d", reply.C, args.A*args.B)
166 }
167
168
169 args = &Args{7, 8}
170 mulReply := new(Reply)
171 mulCall := client.Go("Arith.Mul", args, mulReply, nil)
172 addReply := new(Reply)
173 addCall := client.Go("Arith.Add", args, addReply, nil)
174
175 addCall = <-addCall.Done
176 if addCall.Error != nil {
177 t.Errorf("Add: expected no error but got string %q", addCall.Error.Error())
178 }
179 if addReply.C != args.A+args.B {
180 t.Errorf("Add: got %d expected %d", addReply.C, args.A+args.B)
181 }
182
183 mulCall = <-mulCall.Done
184 if mulCall.Error != nil {
185 t.Errorf("Mul: expected no error but got string %q", mulCall.Error.Error())
186 }
187 if mulReply.C != args.A*args.B {
188 t.Errorf("Mul: got %d expected %d", mulReply.C, args.A*args.B)
189 }
190
191
192 args = &Args{7, 0}
193 reply = new(Reply)
194 err = client.Call("Arith.Div", args, reply)
195
196 if err == nil {
197 t.Error("Div: expected error")
198 } else if err.Error() != "divide by zero" {
199 t.Error("Div: expected divide by zero error; got", err)
200 }
201 }
202
203 func TestBuiltinTypes(t *testing.T) {
204 cli, srv := net.Pipe()
205 go ServeConn(srv)
206
207 client := NewClient(cli)
208 defer client.Close()
209
210
211 arg := 7
212 replyMap := map[int]int{}
213 err := client.Call("BuiltinTypes.Map", arg, &replyMap)
214 if err != nil {
215 t.Errorf("Map: expected no error but got string %q", err.Error())
216 }
217 if replyMap[arg] != arg {
218 t.Errorf("Map: expected %d got %d", arg, replyMap[arg])
219 }
220
221
222 replySlice := []int{}
223 err = client.Call("BuiltinTypes.Slice", arg, &replySlice)
224 if err != nil {
225 t.Errorf("Slice: expected no error but got string %q", err.Error())
226 }
227 if e := []int{arg}; !reflect.DeepEqual(replySlice, e) {
228 t.Errorf("Slice: expected %v got %v", e, replySlice)
229 }
230
231
232 replyArray := [1]int{}
233 err = client.Call("BuiltinTypes.Array", arg, &replyArray)
234 if err != nil {
235 t.Errorf("Array: expected no error but got string %q", err.Error())
236 }
237 if e := [1]int{arg}; !reflect.DeepEqual(replyArray, e) {
238 t.Errorf("Array: expected %v got %v", e, replyArray)
239 }
240 }
241
242 func TestMalformedInput(t *testing.T) {
243 cli, srv := net.Pipe()
244 go cli.Write([]byte(`{id:1}`))
245 ServeConn(srv)
246 }
247
248 func TestMalformedOutput(t *testing.T) {
249 cli, srv := net.Pipe()
250 go srv.Write([]byte(`{"id":0,"result":null,"error":null}`))
251 go io.ReadAll(srv)
252
253 client := NewClient(cli)
254 defer client.Close()
255
256 args := &Args{7, 8}
257 reply := new(Reply)
258 err := client.Call("Arith.Add", args, reply)
259 if err == nil {
260 t.Error("expected error")
261 }
262 }
263
264 func TestServerErrorHasNullResult(t *testing.T) {
265 var out bytes.Buffer
266 sc := NewServerCodec(struct {
267 io.Reader
268 io.Writer
269 io.Closer
270 }{
271 Reader: strings.NewReader(`{"method": "Arith.Add", "id": "123", "params": []}`),
272 Writer: &out,
273 Closer: io.NopCloser(nil),
274 })
275 r := new(rpc.Request)
276 if err := sc.ReadRequestHeader(r); err != nil {
277 t.Fatal(err)
278 }
279 const valueText = "the value we don't want to see"
280 const errorText = "some error"
281 err := sc.WriteResponse(&rpc.Response{
282 ServiceMethod: "Method",
283 Seq: 1,
284 Error: errorText,
285 }, valueText)
286 if err != nil {
287 t.Fatal(err)
288 }
289 if !strings.Contains(out.String(), errorText) {
290 t.Fatalf("Response didn't contain expected error %q: %s", errorText, &out)
291 }
292 if strings.Contains(out.String(), valueText) {
293 t.Errorf("Response contains both an error and value: %s", &out)
294 }
295 }
296
297 func TestUnexpectedError(t *testing.T) {
298 cli, srv := myPipe()
299 go cli.PipeWriter.CloseWithError(errors.New("unexpected error!"))
300 ServeConn(srv)
301 }
302
303
304 func myPipe() (*pipe, *pipe) {
305 r1, w1 := io.Pipe()
306 r2, w2 := io.Pipe()
307
308 return &pipe{r1, w2}, &pipe{r2, w1}
309 }
310
311 type pipe struct {
312 *io.PipeReader
313 *io.PipeWriter
314 }
315
316 type pipeAddr int
317
318 func (pipeAddr) Network() string {
319 return "pipe"
320 }
321
322 func (pipeAddr) String() string {
323 return "pipe"
324 }
325
326 func (p *pipe) Close() error {
327 err := p.PipeReader.Close()
328 err1 := p.PipeWriter.Close()
329 if err == nil {
330 err = err1
331 }
332 return err
333 }
334
335 func (p *pipe) LocalAddr() net.Addr {
336 return pipeAddr(0)
337 }
338
339 func (p *pipe) RemoteAddr() net.Addr {
340 return pipeAddr(0)
341 }
342
343 func (p *pipe) SetTimeout(nsec int64) error {
344 return errors.New("net.Pipe does not support timeouts")
345 }
346
347 func (p *pipe) SetReadTimeout(nsec int64) error {
348 return errors.New("net.Pipe does not support timeouts")
349 }
350
351 func (p *pipe) SetWriteTimeout(nsec int64) error {
352 return errors.New("net.Pipe does not support timeouts")
353 }
354
View as plain text