1 // Copyright 2009 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.
20 serverAddr
, newServerAddr
string
22 once
, newOnce
, httpOnce sync
.Once
40 func (t
*Arith
) Add(args
*Args
, reply
*Reply
) os
.Error
{
41 reply
.C
= args
.A
+ args
.B
45 func (t
*Arith
) Mul(args
*Args
, reply
*Reply
) os
.Error
{
46 reply
.C
= args
.A
* args
.B
50 func (t
*Arith
) Div(args
*Args
, reply
*Reply
) os
.Error
{
52 return os
.ErrorString("divide by zero")
54 reply
.C
= args
.A
/ args
.B
58 func (t
*Arith
) String(args
*Args
, reply
*string) os
.Error
{
59 *reply
= fmt
.Sprintf("%d+%d=%d", args
.A
, args
.B
, args
.A
+args
.B
)
63 func (t
*Arith
) Scan(args
*string, reply
*Reply
) (err os
.Error
) {
64 _
, err
= fmt
.Sscan(*args
, &reply
.C
)
68 func (t
*Arith
) Error(args
*Args
, reply
*Reply
) os
.Error
{
72 func listenTCP() (net
.Listener
, string) {
73 l
, e
:= net
.Listen("tcp", "127.0.0.1:0") // any available address
75 log
.Exitf("net.Listen tcp :0: %v", e
)
77 return l
, l
.Addr().String()
84 l
, serverAddr
= listenTCP()
85 log
.Println("Test RPC server listening on", serverAddr
)
89 httpOnce
.Do(startHttpServer
)
92 func startNewServer() {
94 s
.Register(new(Arith
))
97 l
, newServerAddr
= listenTCP()
98 log
.Println("NewServer test RPC server listening on", newServerAddr
)
101 s
.HandleHTTP(newHttpPath
, "/bar")
102 httpOnce
.Do(startHttpServer
)
105 func startHttpServer() {
107 l
, httpServerAddr
= listenTCP()
108 httpServerAddr
= l
.Addr().String()
109 log
.Println("Test HTTP RPC server listening on", httpServerAddr
)
110 go http
.Serve(l
, nil)
113 func TestRPC(t
*testing
.T
) {
115 testRPC(t
, serverAddr
)
116 newOnce
.Do(startNewServer
)
117 testRPC(t
, newServerAddr
)
120 func testRPC(t
*testing
.T
, addr
string) {
121 client
, err
:= Dial("tcp", addr
)
123 t
.Fatal("dialing", err
)
129 err
= client
.Call("Arith.Add", args
, reply
)
131 t
.Errorf("Add: expected no error but got string %q", err
.String())
133 if reply
.C
!= args
.A
+args
.B
{
134 t
.Errorf("Add: expected %d got %d", reply
.C
, args
.A
+args
.B
)
139 err
= client
.Call("Arith.Mul", args
, reply
)
141 t
.Errorf("Mul: expected no error but got string %q", err
.String())
143 if reply
.C
!= args
.A
*args
.B
{
144 t
.Errorf("Mul: expected %d got %d", reply
.C
, args
.A
*args
.B
)
149 mulReply
:= new(Reply
)
150 mulCall
:= client
.Go("Arith.Mul", args
, mulReply
, nil)
151 addReply
:= new(Reply
)
152 addCall
:= client
.Go("Arith.Add", args
, addReply
, nil)
154 addCall
= <-addCall
.Done
155 if addCall
.Error
!= nil {
156 t
.Errorf("Add: expected no error but got string %q", addCall
.Error
.String())
158 if addReply
.C
!= args
.A
+args
.B
{
159 t
.Errorf("Add: expected %d got %d", addReply
.C
, args
.A
+args
.B
)
162 mulCall
= <-mulCall
.Done
163 if mulCall
.Error
!= nil {
164 t
.Errorf("Mul: expected no error but got string %q", mulCall
.Error
.String())
166 if mulReply
.C
!= args
.A
*args
.B
{
167 t
.Errorf("Mul: expected %d got %d", mulReply
.C
, args
.A
*args
.B
)
173 err
= client
.Call("Arith.Div", args
, reply
)
174 // expect an error: zero divide
176 t
.Error("Div: expected error")
177 } else if err
.String() != "divide by zero" {
178 t
.Error("Div: expected divide by zero error; got", err
)
181 // Non-struct argument
183 str
:= fmt
.Sprint(Val
)
185 err
= client
.Call("Arith.Scan", &str
, reply
)
187 t
.Errorf("Scan: expected no error but got string %q", err
.String())
188 } else if reply
.C
!= Val
{
189 t
.Errorf("Scan: expected %d got %d", Val
, reply
.C
)
195 err
= client
.Call("Arith.String", args
, &str
)
197 t
.Errorf("String: expected no error but got string %q", err
.String())
199 expect
:= fmt
.Sprintf("%d+%d=%d", args
.A
, args
.B
, args
.A
+args
.B
)
201 t
.Errorf("String: expected %s got %s", expect
, str
)
205 func TestHTTPRPC(t
*testing
.T
) {
208 newOnce
.Do(startNewServer
)
209 testHTTPRPC(t
, newHttpPath
)
212 func testHTTPRPC(t
*testing
.T
, path
string) {
216 client
, err
= DialHTTP("tcp", httpServerAddr
)
218 client
, err
= DialHTTPPath("tcp", httpServerAddr
, path
)
221 t
.Fatal("dialing", err
)
227 err
= client
.Call("Arith.Add", args
, reply
)
229 t
.Errorf("Add: expected no error but got string %q", err
.String())
231 if reply
.C
!= args
.A
+args
.B
{
232 t
.Errorf("Add: expected %d got %d", reply
.C
, args
.A
+args
.B
)
236 func TestCheckUnknownService(t
*testing
.T
) {
239 conn
, err
:= net
.Dial("tcp", "", serverAddr
)
241 t
.Fatal("dialing:", err
)
244 client
:= NewClient(conn
)
248 err
= client
.Call("Unknown.Add", args
, reply
)
250 t
.Error("expected error calling unknown service")
251 } else if strings
.Index(err
.String(), "service") < 0 {
252 t
.Error("expected error about service; got", err
)
256 func TestCheckUnknownMethod(t
*testing
.T
) {
259 conn
, err
:= net
.Dial("tcp", "", serverAddr
)
261 t
.Fatal("dialing:", err
)
264 client
:= NewClient(conn
)
268 err
= client
.Call("Arith.Unknown", args
, reply
)
270 t
.Error("expected error calling unknown service")
271 } else if strings
.Index(err
.String(), "method") < 0 {
272 t
.Error("expected error about method; got", err
)
276 func TestCheckBadType(t
*testing
.T
) {
279 conn
, err
:= net
.Dial("tcp", "", serverAddr
)
281 t
.Fatal("dialing:", err
)
284 client
:= NewClient(conn
)
287 err
= client
.Call("Arith.Add", reply
, reply
) // args, reply would be the correct thing to use
289 t
.Error("expected error calling Arith.Add with wrong arg type")
290 } else if strings
.Index(err
.String(), "type") < 0 {
291 t
.Error("expected error about type; got", err
)
295 type ArgNotPointer
int
296 type ReplyNotPointer
int
297 type ArgNotPublic
int
298 type ReplyNotPublic
int
301 func (t
*ArgNotPointer
) ArgNotPointer(args Args
, reply
*Reply
) os
.Error
{
305 func (t
*ReplyNotPointer
) ReplyNotPointer(args
*Args
, reply Reply
) os
.Error
{
309 func (t
*ArgNotPublic
) ArgNotPublic(args
*local
, reply
*Reply
) os
.Error
{
313 func (t
*ReplyNotPublic
) ReplyNotPublic(args
*Args
, reply
*local
) os
.Error
{
317 // Check that registration handles lots of bad methods and a type with no suitable methods.
318 func TestRegistrationError(t
*testing
.T
) {
319 err
:= Register(new(ArgNotPointer
))
321 t
.Errorf("expected error registering ArgNotPointer")
323 err
= Register(new(ReplyNotPointer
))
325 t
.Errorf("expected error registering ReplyNotPointer")
327 err
= Register(new(ArgNotPublic
))
329 t
.Errorf("expected error registering ArgNotPublic")
331 err
= Register(new(ReplyNotPublic
))
333 t
.Errorf("expected error registering ReplyNotPublic")
337 type WriteFailCodec
int
339 func (WriteFailCodec
) WriteRequest(*Request
, interface{}) os
.Error
{
340 // the panic caused by this error used to not unlock a lock.
341 return os
.NewError("fail")
344 func (WriteFailCodec
) ReadResponseHeader(*Response
) os
.Error
{
349 func (WriteFailCodec
) ReadResponseBody(interface{}) os
.Error
{
354 func (WriteFailCodec
) Close() os
.Error
{
358 func TestSendDeadlock(t
*testing
.T
) {
359 client
:= NewClientWithCodec(WriteFailCodec(0))
361 done
:= make(chan bool)
363 testSendDeadlock(client
)
364 testSendDeadlock(client
)
367 for i
:= 0; i
< 50; i
++ {
368 time
.Sleep(100 * 1e6
)
377 func testSendDeadlock(client
*Client
) {
383 client
.Call("Arith.Add", args
, reply
)