OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [rpc/] [server_test.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// 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.
4
 
5
package rpc
6
 
7
import (
8
        "errors"
9
        "fmt"
10
        "io"
11
        "log"
12
        "net"
13
        "net/http/httptest"
14
        "runtime"
15
        "strings"
16
        "sync"
17
        "sync/atomic"
18
        "testing"
19
        "time"
20
)
21
 
22
var (
23
        newServer                 *Server
24
        serverAddr, newServerAddr string
25
        httpServerAddr            string
26
        once, newOnce, httpOnce   sync.Once
27
)
28
 
29
const (
30
        newHttpPath = "/foo"
31
)
32
 
33
type Args struct {
34
        A, B int
35
}
36
 
37
type Reply struct {
38
        C int
39
}
40
 
41
type Arith int
42
 
43
// Some of Arith's methods have value args, some have pointer args. That's deliberate.
44
 
45
func (t *Arith) Add(args Args, reply *Reply) error {
46
        reply.C = args.A + args.B
47
        return nil
48
}
49
 
50
func (t *Arith) Mul(args *Args, reply *Reply) error {
51
        reply.C = args.A * args.B
52
        return nil
53
}
54
 
55
func (t *Arith) Div(args Args, reply *Reply) error {
56
        if args.B == 0 {
57
                return errors.New("divide by zero")
58
        }
59
        reply.C = args.A / args.B
60
        return nil
61
}
62
 
63
func (t *Arith) String(args *Args, reply *string) error {
64
        *reply = fmt.Sprintf("%d+%d=%d", args.A, args.B, args.A+args.B)
65
        return nil
66
}
67
 
68
func (t *Arith) Scan(args string, reply *Reply) (err error) {
69
        _, err = fmt.Sscan(args, &reply.C)
70
        return
71
}
72
 
73
func (t *Arith) Error(args *Args, reply *Reply) error {
74
        panic("ERROR")
75
}
76
 
77
func listenTCP() (net.Listener, string) {
78
        l, e := net.Listen("tcp", "127.0.0.1:0") // any available address
79
        if e != nil {
80
                log.Fatalf("net.Listen tcp :0: %v", e)
81
        }
82
        return l, l.Addr().String()
83
}
84
 
85
func startServer() {
86
        Register(new(Arith))
87
 
88
        var l net.Listener
89
        l, serverAddr = listenTCP()
90
        log.Println("Test RPC server listening on", serverAddr)
91
        go Accept(l)
92
 
93
        HandleHTTP()
94
        httpOnce.Do(startHttpServer)
95
}
96
 
97
func startNewServer() {
98
        newServer = NewServer()
99
        newServer.Register(new(Arith))
100
 
101
        var l net.Listener
102
        l, newServerAddr = listenTCP()
103
        log.Println("NewServer test RPC server listening on", newServerAddr)
104
        go Accept(l)
105
 
106
        newServer.HandleHTTP(newHttpPath, "/bar")
107
        httpOnce.Do(startHttpServer)
108
}
109
 
110
func startHttpServer() {
111
        server := httptest.NewServer(nil)
112
        httpServerAddr = server.Listener.Addr().String()
113
        log.Println("Test HTTP RPC server listening on", httpServerAddr)
114
}
115
 
116
func TestRPC(t *testing.T) {
117
        once.Do(startServer)
118
        testRPC(t, serverAddr)
119
        newOnce.Do(startNewServer)
120
        testRPC(t, newServerAddr)
121
}
122
 
123
func testRPC(t *testing.T, addr string) {
124
        client, err := Dial("tcp", addr)
125
        if err != nil {
126
                t.Fatal("dialing", err)
127
        }
128
 
129
        // Synchronous calls
130
        args := &Args{7, 8}
131
        reply := new(Reply)
132
        err = client.Call("Arith.Add", args, reply)
133
        if err != nil {
134
                t.Errorf("Add: expected no error but got string %q", err.Error())
135
        }
136
        if reply.C != args.A+args.B {
137
                t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
138
        }
139
 
140
        // Nonexistent method
141
        args = &Args{7, 0}
142
        reply = new(Reply)
143
        err = client.Call("Arith.BadOperation", args, reply)
144
        // expect an error
145
        if err == nil {
146
                t.Error("BadOperation: expected error")
147
        } else if !strings.HasPrefix(err.Error(), "rpc: can't find method ") {
148
                t.Errorf("BadOperation: expected can't find method error; got %q", err)
149
        }
150
 
151
        // Unknown service
152
        args = &Args{7, 8}
153
        reply = new(Reply)
154
        err = client.Call("Arith.Unknown", args, reply)
155
        if err == nil {
156
                t.Error("expected error calling unknown service")
157
        } else if strings.Index(err.Error(), "method") < 0 {
158
                t.Error("expected error about method; got", err)
159
        }
160
 
161
        // Out of order.
162
        args = &Args{7, 8}
163
        mulReply := new(Reply)
164
        mulCall := client.Go("Arith.Mul", args, mulReply, nil)
165
        addReply := new(Reply)
166
        addCall := client.Go("Arith.Add", args, addReply, nil)
167
 
168
        addCall = <-addCall.Done
169
        if addCall.Error != nil {
170
                t.Errorf("Add: expected no error but got string %q", addCall.Error.Error())
171
        }
172
        if addReply.C != args.A+args.B {
173
                t.Errorf("Add: expected %d got %d", addReply.C, args.A+args.B)
174
        }
175
 
176
        mulCall = <-mulCall.Done
177
        if mulCall.Error != nil {
178
                t.Errorf("Mul: expected no error but got string %q", mulCall.Error.Error())
179
        }
180
        if mulReply.C != args.A*args.B {
181
                t.Errorf("Mul: expected %d got %d", mulReply.C, args.A*args.B)
182
        }
183
 
184
        // Error test
185
        args = &Args{7, 0}
186
        reply = new(Reply)
187
        err = client.Call("Arith.Div", args, reply)
188
        // expect an error: zero divide
189
        if err == nil {
190
                t.Error("Div: expected error")
191
        } else if err.Error() != "divide by zero" {
192
                t.Error("Div: expected divide by zero error; got", err)
193
        }
194
 
195
        // Bad type.
196
        reply = new(Reply)
197
        err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use
198
        if err == nil {
199
                t.Error("expected error calling Arith.Add with wrong arg type")
200
        } else if strings.Index(err.Error(), "type") < 0 {
201
                t.Error("expected error about type; got", err)
202
        }
203
 
204
        // Non-struct argument
205
        const Val = 12345
206
        str := fmt.Sprint(Val)
207
        reply = new(Reply)
208
        err = client.Call("Arith.Scan", &str, reply)
209
        if err != nil {
210
                t.Errorf("Scan: expected no error but got string %q", err.Error())
211
        } else if reply.C != Val {
212
                t.Errorf("Scan: expected %d got %d", Val, reply.C)
213
        }
214
 
215
        // Non-struct reply
216
        args = &Args{27, 35}
217
        str = ""
218
        err = client.Call("Arith.String", args, &str)
219
        if err != nil {
220
                t.Errorf("String: expected no error but got string %q", err.Error())
221
        }
222
        expect := fmt.Sprintf("%d+%d=%d", args.A, args.B, args.A+args.B)
223
        if str != expect {
224
                t.Errorf("String: expected %s got %s", expect, str)
225
        }
226
 
227
        args = &Args{7, 8}
228
        reply = new(Reply)
229
        err = client.Call("Arith.Mul", args, reply)
230
        if err != nil {
231
                t.Errorf("Mul: expected no error but got string %q", err.Error())
232
        }
233
        if reply.C != args.A*args.B {
234
                t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B)
235
        }
236
}
237
 
238
func TestHTTP(t *testing.T) {
239
        once.Do(startServer)
240
        testHTTPRPC(t, "")
241
        newOnce.Do(startNewServer)
242
        testHTTPRPC(t, newHttpPath)
243
}
244
 
245
func testHTTPRPC(t *testing.T, path string) {
246
        var client *Client
247
        var err error
248
        if path == "" {
249
                client, err = DialHTTP("tcp", httpServerAddr)
250
        } else {
251
                client, err = DialHTTPPath("tcp", httpServerAddr, path)
252
        }
253
        if err != nil {
254
                t.Fatal("dialing", err)
255
        }
256
 
257
        // Synchronous calls
258
        args := &Args{7, 8}
259
        reply := new(Reply)
260
        err = client.Call("Arith.Add", args, reply)
261
        if err != nil {
262
                t.Errorf("Add: expected no error but got string %q", err.Error())
263
        }
264
        if reply.C != args.A+args.B {
265
                t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
266
        }
267
}
268
 
269
// CodecEmulator provides a client-like api and a ServerCodec interface.
270
// Can be used to test ServeRequest.
271
type CodecEmulator struct {
272
        server        *Server
273
        serviceMethod string
274
        args          *Args
275
        reply         *Reply
276
        err           error
277
}
278
 
279
func (codec *CodecEmulator) Call(serviceMethod string, args *Args, reply *Reply) error {
280
        codec.serviceMethod = serviceMethod
281
        codec.args = args
282
        codec.reply = reply
283
        codec.err = nil
284
        var serverError error
285
        if codec.server == nil {
286
                serverError = ServeRequest(codec)
287
        } else {
288
                serverError = codec.server.ServeRequest(codec)
289
        }
290
        if codec.err == nil && serverError != nil {
291
                codec.err = serverError
292
        }
293
        return codec.err
294
}
295
 
296
func (codec *CodecEmulator) ReadRequestHeader(req *Request) error {
297
        req.ServiceMethod = codec.serviceMethod
298
        req.Seq = 0
299
        return nil
300
}
301
 
302
func (codec *CodecEmulator) ReadRequestBody(argv interface{}) error {
303
        if codec.args == nil {
304
                return io.ErrUnexpectedEOF
305
        }
306
        *(argv.(*Args)) = *codec.args
307
        return nil
308
}
309
 
310
func (codec *CodecEmulator) WriteResponse(resp *Response, reply interface{}) error {
311
        if resp.Error != "" {
312
                codec.err = errors.New(resp.Error)
313
        } else {
314
                *codec.reply = *(reply.(*Reply))
315
        }
316
        return nil
317
}
318
 
319
func (codec *CodecEmulator) Close() error {
320
        return nil
321
}
322
 
323
func TestServeRequest(t *testing.T) {
324
        once.Do(startServer)
325
        testServeRequest(t, nil)
326
        newOnce.Do(startNewServer)
327
        testServeRequest(t, newServer)
328
}
329
 
330
func testServeRequest(t *testing.T, server *Server) {
331
        client := CodecEmulator{server: server}
332
 
333
        args := &Args{7, 8}
334
        reply := new(Reply)
335
        err := client.Call("Arith.Add", args, reply)
336
        if err != nil {
337
                t.Errorf("Add: expected no error but got string %q", err.Error())
338
        }
339
        if reply.C != args.A+args.B {
340
                t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
341
        }
342
 
343
        err = client.Call("Arith.Add", nil, reply)
344
        if err == nil {
345
                t.Errorf("expected error calling Arith.Add with nil arg")
346
        }
347
}
348
 
349
type ReplyNotPointer int
350
type ArgNotPublic int
351
type ReplyNotPublic int
352
type local struct{}
353
 
354
func (t *ReplyNotPointer) ReplyNotPointer(args *Args, reply Reply) error {
355
        return nil
356
}
357
 
358
func (t *ArgNotPublic) ArgNotPublic(args *local, reply *Reply) error {
359
        return nil
360
}
361
 
362
func (t *ReplyNotPublic) ReplyNotPublic(args *Args, reply *local) error {
363
        return nil
364
}
365
 
366
// Check that registration handles lots of bad methods and a type with no suitable methods.
367
func TestRegistrationError(t *testing.T) {
368
        err := Register(new(ReplyNotPointer))
369
        if err == nil {
370
                t.Errorf("expected error registering ReplyNotPointer")
371
        }
372
        err = Register(new(ArgNotPublic))
373
        if err == nil {
374
                t.Errorf("expected error registering ArgNotPublic")
375
        }
376
        err = Register(new(ReplyNotPublic))
377
        if err == nil {
378
                t.Errorf("expected error registering ReplyNotPublic")
379
        }
380
}
381
 
382
type WriteFailCodec int
383
 
384
func (WriteFailCodec) WriteRequest(*Request, interface{}) error {
385
        // the panic caused by this error used to not unlock a lock.
386
        return errors.New("fail")
387
}
388
 
389
func (WriteFailCodec) ReadResponseHeader(*Response) error {
390
        time.Sleep(120 * time.Second)
391
        panic("unreachable")
392
}
393
 
394
func (WriteFailCodec) ReadResponseBody(interface{}) error {
395
        time.Sleep(120 * time.Second)
396
        panic("unreachable")
397
}
398
 
399
func (WriteFailCodec) Close() error {
400
        return nil
401
}
402
 
403
func TestSendDeadlock(t *testing.T) {
404
        client := NewClientWithCodec(WriteFailCodec(0))
405
 
406
        done := make(chan bool)
407
        go func() {
408
                testSendDeadlock(client)
409
                testSendDeadlock(client)
410
                done <- true
411
        }()
412
        select {
413
        case <-done:
414
                return
415
        case <-time.After(5 * time.Second):
416
                t.Fatal("deadlock")
417
        }
418
}
419
 
420
func testSendDeadlock(client *Client) {
421
        defer func() {
422
                recover()
423
        }()
424
        args := &Args{7, 8}
425
        reply := new(Reply)
426
        client.Call("Arith.Add", args, reply)
427
}
428
 
429
func dialDirect() (*Client, error) {
430
        return Dial("tcp", serverAddr)
431
}
432
 
433
func dialHTTP() (*Client, error) {
434
        return DialHTTP("tcp", httpServerAddr)
435
}
436
 
437
func countMallocs(dial func() (*Client, error), t *testing.T) uint64 {
438
        once.Do(startServer)
439
        client, err := dial()
440
        if err != nil {
441
                t.Fatal("error dialing", err)
442
        }
443
        args := &Args{7, 8}
444
        reply := new(Reply)
445
        memstats := new(runtime.MemStats)
446
        runtime.ReadMemStats(memstats)
447
        mallocs := 0 - memstats.Mallocs
448
        const count = 100
449
        for i := 0; i < count; i++ {
450
                err := client.Call("Arith.Add", args, reply)
451
                if err != nil {
452
                        t.Errorf("Add: expected no error but got string %q", err.Error())
453
                }
454
                if reply.C != args.A+args.B {
455
                        t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
456
                }
457
        }
458
        runtime.ReadMemStats(memstats)
459
        mallocs += memstats.Mallocs
460
        return mallocs / count
461
}
462
 
463
func TestCountMallocs(t *testing.T) {
464
        fmt.Printf("mallocs per rpc round trip: %d\n", countMallocs(dialDirect, t))
465
}
466
 
467
func TestCountMallocsOverHTTP(t *testing.T) {
468
        fmt.Printf("mallocs per HTTP rpc round trip: %d\n", countMallocs(dialHTTP, t))
469
}
470
 
471
type writeCrasher struct {
472
        done chan bool
473
}
474
 
475
func (writeCrasher) Close() error {
476
        return nil
477
}
478
 
479
func (w *writeCrasher) Read(p []byte) (int, error) {
480
        <-w.done
481
        return 0, io.EOF
482
}
483
 
484
func (writeCrasher) Write(p []byte) (int, error) {
485
        return 0, errors.New("fake write failure")
486
}
487
 
488
func TestClientWriteError(t *testing.T) {
489
        w := &writeCrasher{done: make(chan bool)}
490
        c := NewClient(w)
491
        res := false
492
        err := c.Call("foo", 1, &res)
493
        if err == nil {
494
                t.Fatal("expected error")
495
        }
496
        if err.Error() != "fake write failure" {
497
                t.Error("unexpected value of error:", err)
498
        }
499
        w.done <- true
500
}
501
 
502
func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
503
        b.StopTimer()
504
        once.Do(startServer)
505
        client, err := dial()
506
        if err != nil {
507
                b.Fatal("error dialing:", err)
508
        }
509
 
510
        // Synchronous calls
511
        args := &Args{7, 8}
512
        procs := runtime.GOMAXPROCS(-1)
513
        N := int32(b.N)
514
        var wg sync.WaitGroup
515
        wg.Add(procs)
516
        b.StartTimer()
517
 
518
        for p := 0; p < procs; p++ {
519
                go func() {
520
                        reply := new(Reply)
521
                        for atomic.AddInt32(&N, -1) >= 0 {
522
                                err := client.Call("Arith.Add", args, reply)
523
                                if err != nil {
524
                                        b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error())
525
                                }
526
                                if reply.C != args.A+args.B {
527
                                        b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B)
528
                                }
529
                        }
530
                        wg.Done()
531
                }()
532
        }
533
        wg.Wait()
534
}
535
 
536
func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
537
        const MaxConcurrentCalls = 100
538
        b.StopTimer()
539
        once.Do(startServer)
540
        client, err := dial()
541
        if err != nil {
542
                b.Fatal("error dialing:", err)
543
        }
544
 
545
        // Asynchronous calls
546
        args := &Args{7, 8}
547
        procs := 4 * runtime.GOMAXPROCS(-1)
548
        send := int32(b.N)
549
        recv := int32(b.N)
550
        var wg sync.WaitGroup
551
        wg.Add(procs)
552
        gate := make(chan bool, MaxConcurrentCalls)
553
        res := make(chan *Call, MaxConcurrentCalls)
554
        b.StartTimer()
555
 
556
        for p := 0; p < procs; p++ {
557
                go func() {
558
                        for atomic.AddInt32(&send, -1) >= 0 {
559
                                gate <- true
560
                                reply := new(Reply)
561
                                client.Go("Arith.Add", args, reply, res)
562
                        }
563
                }()
564
                go func() {
565
                        for call := range res {
566
                                A := call.Args.(*Args).A
567
                                B := call.Args.(*Args).B
568
                                C := call.Reply.(*Reply).C
569
                                if A+B != C {
570
                                        b.Fatalf("incorrect reply: Add: expected %d got %d", A+B, C)
571
                                }
572
                                <-gate
573
                                if atomic.AddInt32(&recv, -1) == 0 {
574
                                        close(res)
575
                                }
576
                        }
577
                        wg.Done()
578
                }()
579
        }
580
        wg.Wait()
581
}
582
 
583
func BenchmarkEndToEnd(b *testing.B) {
584
        benchmarkEndToEnd(dialDirect, b)
585
}
586
 
587
func BenchmarkEndToEndHTTP(b *testing.B) {
588
        benchmarkEndToEnd(dialHTTP, b)
589
}
590
 
591
func BenchmarkEndToEndAsync(b *testing.B) {
592
        benchmarkEndToEndAsync(dialDirect, b)
593
}
594
 
595
func BenchmarkEndToEndAsyncHTTP(b *testing.B) {
596
        benchmarkEndToEndAsync(dialHTTP, b)
597
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.