// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package jsonrpc import ( "fmt" "json" "net" "os" "rpc" "testing" ) type Args struct { A, B int } type Reply struct { C int } type Arith int func (t *Arith) Add(args *Args, reply *Reply) os.Error { reply.C = args.A + args.B return nil } func (t *Arith) Mul(args *Args, reply *Reply) os.Error { reply.C = args.A * args.B return nil } func (t *Arith) Div(args *Args, reply *Reply) os.Error { if args.B == 0 { return os.NewError("divide by zero") } reply.C = args.A / args.B return nil } func (t *Arith) Error(args *Args, reply *Reply) os.Error { panic("ERROR") } func init() { rpc.Register(new(Arith)) } func TestServer(t *testing.T) { type addResp struct { Id interface{} `json:"id"` Result Reply `json:"result"` Error interface{} `json:"error"` } cli, srv := net.Pipe() defer cli.Close() go ServeConn(srv) dec := json.NewDecoder(cli) // Send hand-coded requests to server, parse responses. for i := 0; i < 10; i++ { fmt.Fprintf(cli, `{"method": "Arith.Add", "id": "\u%04d", "params": [{"A": %d, "B": %d}]}`, i, i, i+1) var resp addResp err := dec.Decode(&resp) if err != nil { t.Fatalf("Decode: %s", err) } if resp.Error != nil { t.Fatalf("resp.Error: %s", resp.Error) } if resp.Id.(string) != string(i) { t.Fatalf("resp: bad id %q want %q", resp.Id.(string), string(i)) } if resp.Result.C != 2*i+1 { t.Fatalf("resp: bad result: %d+%d=%d", i, i+1, resp.Result.C) } } fmt.Fprintf(cli, "{}\n") var resp addResp if err := dec.Decode(&resp); err != nil { t.Fatalf("Decode after empty: %s", err) } if resp.Error == nil { t.Fatalf("Expected error, got nil") } } func TestClient(t *testing.T) { // Assume server is okay (TestServer is above). // Test client against server. cli, srv := net.Pipe() go ServeConn(srv) client := NewClient(cli) defer client.Close() // Synchronous calls args := &Args{7, 8} reply := new(Reply) err := client.Call("Arith.Add", args, reply) if err != nil { t.Errorf("Add: expected no error but got string %q", err.String()) } if reply.C != args.A+args.B { t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B) } args = &Args{7, 8} reply = new(Reply) err = client.Call("Arith.Mul", args, reply) if err != nil { t.Errorf("Mul: expected no error but got string %q", err.String()) } if reply.C != args.A*args.B { t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B) } // Out of order. args = &Args{7, 8} mulReply := new(Reply) mulCall := client.Go("Arith.Mul", args, mulReply, nil) addReply := new(Reply) addCall := client.Go("Arith.Add", args, addReply, nil) addCall = <-addCall.Done if addCall.Error != nil { t.Errorf("Add: expected no error but got string %q", addCall.Error.String()) } if addReply.C != args.A+args.B { t.Errorf("Add: expected %d got %d", addReply.C, args.A+args.B) } mulCall = <-mulCall.Done if mulCall.Error != nil { t.Errorf("Mul: expected no error but got string %q", mulCall.Error.String()) } if mulReply.C != args.A*args.B { t.Errorf("Mul: expected %d got %d", mulReply.C, args.A*args.B) } // Error test args = &Args{7, 0} reply = new(Reply) err = client.Call("Arith.Div", args, reply) // expect an error: zero divide if err == nil { t.Error("Div: expected error") } else if err.String() != "divide by zero" { t.Error("Div: expected divide by zero error; got", err) } }