Black Lives Matter. Support the Equal Justice Initiative.

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