blob: 98c0eadd32bb9f3bd68249ffa0c21eb1fc698e61 [file] [log] [blame]
// Copyright 2009 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 rpc
import (
"http"
"log"
"net"
"once"
"os"
"strings"
"testing"
)
var serverAddr string
var httpServerAddr string
const second = 1e9
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.ErrorString("divide by zero")
}
reply.C = args.A / args.B
return nil
}
func (t *Arith) Error(args *Args, reply *Reply) os.Error {
panicln("ERROR")
}
func startServer() {
Register(new(Arith))
l, e := net.Listen("tcp", ":0") // any available address
if e != nil {
log.Exitf("net.Listen tcp :0: %v", e)
}
serverAddr = l.Addr().String()
log.Stderr("Test RPC server listening on ", serverAddr)
go Accept(l)
HandleHTTP()
l, e = net.Listen("tcp", ":0") // any available address
if e != nil {
log.Stderrf("net.Listen tcp :0: %v", e)
os.Exit(1)
}
httpServerAddr = l.Addr().String()
log.Stderr("Test HTTP RPC server listening on ", httpServerAddr)
go http.Serve(l, nil)
}
func TestRPC(t *testing.T) {
once.Do(startServer)
client, err := Dial("tcp", serverAddr)
if err != nil {
t.Fatal("dialing", err)
}
// 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)
}
}
func TestHTTPRPC(t *testing.T) {
once.Do(startServer)
client, err := DialHTTP("tcp", httpServerAddr)
if err != nil {
t.Fatal("dialing", err)
}
// 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)
}
}
func TestCheckUnknownService(t *testing.T) {
once.Do(startServer)
conn, err := net.Dial("tcp", "", serverAddr)
if err != nil {
t.Fatal("dialing:", err)
}
client := NewClient(conn)
args := &Args{7, 8}
reply := new(Reply)
err = client.Call("Unknown.Add", args, reply)
if err == nil {
t.Error("expected error calling unknown service")
} else if strings.Index(err.String(), "service") < 0 {
t.Error("expected error about service; got", err)
}
}
func TestCheckUnknownMethod(t *testing.T) {
once.Do(startServer)
conn, err := net.Dial("tcp", "", serverAddr)
if err != nil {
t.Fatal("dialing:", err)
}
client := NewClient(conn)
args := &Args{7, 8}
reply := new(Reply)
err = client.Call("Arith.Unknown", args, reply)
if err == nil {
t.Error("expected error calling unknown service")
} else if strings.Index(err.String(), "method") < 0 {
t.Error("expected error about method; got", err)
}
}
func TestCheckBadType(t *testing.T) {
once.Do(startServer)
conn, err := net.Dial("tcp", "", serverAddr)
if err != nil {
t.Fatal("dialing:", err)
}
client := NewClient(conn)
reply := new(Reply)
err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use
if err == nil {
t.Error("expected error calling Arith.Add with wrong arg type")
} else if strings.Index(err.String(), "type") < 0 {
t.Error("expected error about type; got", err)
}
}
type Bad int
type local struct{}
func (t *Bad) ArgNotPointer(args Args, reply *Reply) os.Error {
return nil
}
func (t *Bad) ArgNotPointerToStruct(args *int, reply *Reply) os.Error {
return nil
}
func (t *Bad) ReplyNotPointer(args *Args, reply Reply) os.Error {
return nil
}
func (t *Bad) ReplyNotPointerToStruct(args *Args, reply *int) os.Error {
return nil
}
func (t *Bad) ArgNotPublic(args *local, reply *Reply) os.Error {
return nil
}
func (t *Bad) ReplyNotPublic(args *Args, reply *local) os.Error {
return nil
}
// Check that registration handles lots of bad methods and a type with no suitable methods.
func TestRegistrationError(t *testing.T) {
err := Register(new(Bad))
if err == nil {
t.Errorf("expected error registering bad type")
}
}