github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/net/rpc/jsonrpc/all_test.go (about)

     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  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"net"
    14  	"net/rpc"
    15  	"testing"
    16  )
    17  
    18  type Args struct {
    19  	A, B int
    20  }
    21  
    22  type Reply struct {
    23  	C int
    24  }
    25  
    26  type Arith int
    27  
    28  type ArithAddResp struct {
    29  	Id     interface{} `json:"id"`
    30  	Result Reply       `json:"result"`
    31  	Error  interface{} `json:"error"`
    32  }
    33  
    34  func (t *Arith) Add(args *Args, reply *Reply) error {
    35  	reply.C = args.A + args.B
    36  	return nil
    37  }
    38  
    39  func (t *Arith) Mul(args *Args, reply *Reply) error {
    40  	reply.C = args.A * args.B
    41  	return nil
    42  }
    43  
    44  func (t *Arith) Div(args *Args, reply *Reply) error {
    45  	if args.B == 0 {
    46  		return errors.New("divide by zero")
    47  	}
    48  	reply.C = args.A / args.B
    49  	return nil
    50  }
    51  
    52  func (t *Arith) Error(args *Args, reply *Reply) error {
    53  	panic("ERROR")
    54  }
    55  
    56  func init() {
    57  	rpc.Register(new(Arith))
    58  }
    59  
    60  func TestServerNoParams(t *testing.T) {
    61  	cli, srv := net.Pipe()
    62  	defer cli.Close()
    63  	go ServeConn(srv)
    64  	dec := json.NewDecoder(cli)
    65  
    66  	fmt.Fprintf(cli, `{"method": "Arith.Add", "id": "123"}`)
    67  	var resp ArithAddResp
    68  	if err := dec.Decode(&resp); err != nil {
    69  		t.Fatalf("Decode after no params: %s", err)
    70  	}
    71  	if resp.Error == nil {
    72  		t.Fatalf("Expected error, got nil")
    73  	}
    74  }
    75  
    76  func TestServerEmptyMessage(t *testing.T) {
    77  	cli, srv := net.Pipe()
    78  	defer cli.Close()
    79  	go ServeConn(srv)
    80  	dec := json.NewDecoder(cli)
    81  
    82  	fmt.Fprintf(cli, "{}")
    83  	var resp ArithAddResp
    84  	if err := dec.Decode(&resp); err != nil {
    85  		t.Fatalf("Decode after empty: %s", err)
    86  	}
    87  	if resp.Error == nil {
    88  		t.Fatalf("Expected error, got nil")
    89  	}
    90  }
    91  
    92  func TestServer(t *testing.T) {
    93  	cli, srv := net.Pipe()
    94  	defer cli.Close()
    95  	go ServeConn(srv)
    96  	dec := json.NewDecoder(cli)
    97  
    98  	// Send hand-coded requests to server, parse responses.
    99  	for i := 0; i < 10; i++ {
   100  		fmt.Fprintf(cli, `{"method": "Arith.Add", "id": "\u%04d", "params": [{"A": %d, "B": %d}]}`, i, i, i+1)
   101  		var resp ArithAddResp
   102  		err := dec.Decode(&resp)
   103  		if err != nil {
   104  			t.Fatalf("Decode: %s", err)
   105  		}
   106  		if resp.Error != nil {
   107  			t.Fatalf("resp.Error: %s", resp.Error)
   108  		}
   109  		if resp.Id.(string) != string(i) {
   110  			t.Fatalf("resp: bad id %q want %q", resp.Id.(string), string(i))
   111  		}
   112  		if resp.Result.C != 2*i+1 {
   113  			t.Fatalf("resp: bad result: %d+%d=%d", i, i+1, resp.Result.C)
   114  		}
   115  	}
   116  }
   117  
   118  func TestClient(t *testing.T) {
   119  	// Assume server is okay (TestServer is above).
   120  	// Test client against server.
   121  	cli, srv := net.Pipe()
   122  	go ServeConn(srv)
   123  
   124  	client := NewClient(cli)
   125  	defer client.Close()
   126  
   127  	// Synchronous calls
   128  	args := &Args{7, 8}
   129  	reply := new(Reply)
   130  	err := client.Call("Arith.Add", args, reply)
   131  	if err != nil {
   132  		t.Errorf("Add: expected no error but got string %q", err.Error())
   133  	}
   134  	if reply.C != args.A+args.B {
   135  		t.Errorf("Add: got %d expected %d", reply.C, args.A+args.B)
   136  	}
   137  
   138  	args = &Args{7, 8}
   139  	reply = new(Reply)
   140  	err = client.Call("Arith.Mul", args, reply)
   141  	if err != nil {
   142  		t.Errorf("Mul: expected no error but got string %q", err.Error())
   143  	}
   144  	if reply.C != args.A*args.B {
   145  		t.Errorf("Mul: got %d expected %d", reply.C, args.A*args.B)
   146  	}
   147  
   148  	// Out of order.
   149  	args = &Args{7, 8}
   150  	mulReply := new(Reply)
   151  	mulCall := client.Go("Arith.Mul", args, mulReply, nil)
   152  	addReply := new(Reply)
   153  	addCall := client.Go("Arith.Add", args, addReply, nil)
   154  
   155  	addCall = <-addCall.Done
   156  	if addCall.Error != nil {
   157  		t.Errorf("Add: expected no error but got string %q", addCall.Error.Error())
   158  	}
   159  	if addReply.C != args.A+args.B {
   160  		t.Errorf("Add: got %d expected %d", addReply.C, args.A+args.B)
   161  	}
   162  
   163  	mulCall = <-mulCall.Done
   164  	if mulCall.Error != nil {
   165  		t.Errorf("Mul: expected no error but got string %q", mulCall.Error.Error())
   166  	}
   167  	if mulReply.C != args.A*args.B {
   168  		t.Errorf("Mul: got %d expected %d", mulReply.C, args.A*args.B)
   169  	}
   170  
   171  	// Error test
   172  	args = &Args{7, 0}
   173  	reply = new(Reply)
   174  	err = client.Call("Arith.Div", args, reply)
   175  	// expect an error: zero divide
   176  	if err == nil {
   177  		t.Error("Div: expected error")
   178  	} else if err.Error() != "divide by zero" {
   179  		t.Error("Div: expected divide by zero error; got", err)
   180  	}
   181  }
   182  
   183  func TestMalformedInput(t *testing.T) {
   184  	cli, srv := net.Pipe()
   185  	go cli.Write([]byte(`{id:1}`)) // invalid json
   186  	ServeConn(srv)                 // must return, not loop
   187  }
   188  
   189  func TestMalformedOutput(t *testing.T) {
   190  	cli, srv := net.Pipe()
   191  	go srv.Write([]byte(`{"id":0,"result":null,"error":null}`))
   192  	go ioutil.ReadAll(srv)
   193  
   194  	client := NewClient(cli)
   195  	defer client.Close()
   196  
   197  	args := &Args{7, 8}
   198  	reply := new(Reply)
   199  	err := client.Call("Arith.Add", args, reply)
   200  	if err == nil {
   201  		t.Error("expected error")
   202  	}
   203  }
   204  
   205  func TestUnexpectedError(t *testing.T) {
   206  	cli, srv := myPipe()
   207  	go cli.PipeWriter.CloseWithError(errors.New("unexpected error!")) // reader will get this error
   208  	ServeConn(srv)                                                    // must return, not loop
   209  }
   210  
   211  // Copied from package net.
   212  func myPipe() (*pipe, *pipe) {
   213  	r1, w1 := io.Pipe()
   214  	r2, w2 := io.Pipe()
   215  
   216  	return &pipe{r1, w2}, &pipe{r2, w1}
   217  }
   218  
   219  type pipe struct {
   220  	*io.PipeReader
   221  	*io.PipeWriter
   222  }
   223  
   224  type pipeAddr int
   225  
   226  func (pipeAddr) Network() string {
   227  	return "pipe"
   228  }
   229  
   230  func (pipeAddr) String() string {
   231  	return "pipe"
   232  }
   233  
   234  func (p *pipe) Close() error {
   235  	err := p.PipeReader.Close()
   236  	err1 := p.PipeWriter.Close()
   237  	if err == nil {
   238  		err = err1
   239  	}
   240  	return err
   241  }
   242  
   243  func (p *pipe) LocalAddr() net.Addr {
   244  	return pipeAddr(0)
   245  }
   246  
   247  func (p *pipe) RemoteAddr() net.Addr {
   248  	return pipeAddr(0)
   249  }
   250  
   251  func (p *pipe) SetTimeout(nsec int64) error {
   252  	return errors.New("net.Pipe does not support timeouts")
   253  }
   254  
   255  func (p *pipe) SetReadTimeout(nsec int64) error {
   256  	return errors.New("net.Pipe does not support timeouts")
   257  }
   258  
   259  func (p *pipe) SetWriteTimeout(nsec int64) error {
   260  	return errors.New("net.Pipe does not support timeouts")
   261  }