...

Source file src/net/rpc/jsonrpc/all_test.go

Documentation: net/rpc/jsonrpc

		 1  // Copyright 2010 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 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		 interface{} `json:"id"`
		32  	Result Reply			 `json:"result"`
		33  	Error	interface{} `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  	// Send hand-coded requests to server, parse responses.
	 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  	// Assume server is okay (TestServer is above).
	 140  	// Test client against server.
	 141  	cli, srv := net.Pipe()
	 142  	go ServeConn(srv)
	 143  
	 144  	client := NewClient(cli)
	 145  	defer client.Close()
	 146  
	 147  	// Synchronous calls
	 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  	// Out of order.
	 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  	// Error test
	 192  	args = &Args{7, 0}
	 193  	reply = new(Reply)
	 194  	err = client.Call("Arith.Div", args, reply)
	 195  	// expect an error: zero divide
	 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  	// Map
	 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  	// Slice
	 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  	// Array
	 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}`)) // invalid json
	 245  	ServeConn(srv)								 // must return, not loop
	 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!")) // reader will get this error
	 300  	ServeConn(srv)																										// must return, not loop
	 301  }
	 302  
	 303  // Copied from package net.
	 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