github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/rpc/rpc_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package rpc_test 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "net" 10 "reflect" 11 "regexp" 12 "sync" 13 stdtesting "testing" 14 "time" 15 16 "github.com/juju/loggo" 17 jc "github.com/juju/testing/checkers" 18 gc "gopkg.in/check.v1" 19 20 "github.com/juju/juju/rpc" 21 "github.com/juju/juju/rpc/jsoncodec" 22 "github.com/juju/juju/rpc/rpcreflect" 23 "github.com/juju/juju/testing" 24 ) 25 26 var logger = loggo.GetLogger("juju.rpc") 27 28 type rpcSuite struct { 29 testing.BaseSuite 30 } 31 32 var _ = gc.Suite(&rpcSuite{}) 33 34 func TestAll(t *stdtesting.T) { 35 gc.TestingT(t) 36 } 37 38 type callInfo struct { 39 rcvr interface{} 40 method string 41 arg interface{} 42 } 43 44 type callError callInfo 45 46 func (e *callError) Error() string { 47 return fmt.Sprintf("error calling %s", e.method) 48 } 49 50 type stringVal struct { 51 Val string 52 } 53 54 type Root struct { 55 mu sync.Mutex 56 conn *rpc.Conn 57 calls []*callInfo 58 returnErr bool 59 simple map[string]*SimpleMethods 60 delayed map[string]*DelayedMethods 61 errorInst *ErrorMethods 62 } 63 64 func (r *Root) callError(rcvr interface{}, name string, arg interface{}) error { 65 if r.returnErr { 66 return &callError{rcvr, name, arg} 67 } 68 return nil 69 } 70 71 func (r *Root) SimpleMethods(id string) (*SimpleMethods, error) { 72 r.mu.Lock() 73 defer r.mu.Unlock() 74 if a := r.simple[id]; a != nil { 75 return a, nil 76 } 77 return nil, fmt.Errorf("unknown SimpleMethods id") 78 } 79 80 func (r *Root) DelayedMethods(id string) (*DelayedMethods, error) { 81 r.mu.Lock() 82 defer r.mu.Unlock() 83 if a := r.delayed[id]; a != nil { 84 return a, nil 85 } 86 return nil, fmt.Errorf("unknown DelayedMethods id") 87 } 88 89 func (r *Root) ErrorMethods(id string) (*ErrorMethods, error) { 90 if r.errorInst == nil { 91 return nil, fmt.Errorf("no error methods") 92 } 93 return r.errorInst, nil 94 } 95 96 func (r *Root) Discard1() {} 97 98 func (r *Root) Discard2(id string) error { return nil } 99 100 func (r *Root) Discard3(id string) int { return 0 } 101 102 func (r *Root) CallbackMethods(string) (*CallbackMethods, error) { 103 return &CallbackMethods{r}, nil 104 } 105 106 func (r *Root) InterfaceMethods(id string) (InterfaceMethods, error) { 107 logger.Infof("interface methods called") 108 m, err := r.SimpleMethods(id) 109 if err != nil { 110 return nil, err 111 } 112 return m, nil 113 } 114 115 type InterfaceMethods interface { 116 Call1r1e(s stringVal) (stringVal, error) 117 } 118 119 type ChangeAPIMethods struct { 120 r *Root 121 } 122 123 func (r *Root) ChangeAPIMethods(string) (*ChangeAPIMethods, error) { 124 return &ChangeAPIMethods{r}, nil 125 } 126 127 func (t *Root) called(rcvr interface{}, method string, arg interface{}) { 128 t.mu.Lock() 129 t.calls = append(t.calls, &callInfo{rcvr, method, arg}) 130 t.mu.Unlock() 131 } 132 133 type SimpleMethods struct { 134 root *Root 135 id string 136 } 137 138 // Each Call method is named in this standard form: 139 // 140 // Call<narg>r<nret><e> 141 // 142 // where narg is the number of arguments, nret is the number of returned 143 // values (not including the error) and e is the letter 'e' if the 144 // method returns an error. 145 146 func (a *SimpleMethods) Call0r0() { 147 a.root.called(a, "Call0r0", nil) 148 } 149 150 func (a *SimpleMethods) Call0r1() stringVal { 151 a.root.called(a, "Call0r1", nil) 152 return stringVal{"Call0r1 ret"} 153 } 154 155 func (a *SimpleMethods) Call0r1e() (stringVal, error) { 156 a.root.called(a, "Call0r1e", nil) 157 return stringVal{"Call0r1e ret"}, a.root.callError(a, "Call0r1e", nil) 158 } 159 160 func (a *SimpleMethods) Call0r0e() error { 161 a.root.called(a, "Call0r0e", nil) 162 return a.root.callError(a, "Call0r0e", nil) 163 } 164 165 func (a *SimpleMethods) Call1r0(s stringVal) { 166 a.root.called(a, "Call1r0", s) 167 } 168 169 func (a *SimpleMethods) Call1r1(s stringVal) stringVal { 170 a.root.called(a, "Call1r1", s) 171 return stringVal{"Call1r1 ret"} 172 } 173 174 func (a *SimpleMethods) Call1r1e(s stringVal) (stringVal, error) { 175 a.root.called(a, "Call1r1e", s) 176 return stringVal{"Call1r1e ret"}, a.root.callError(a, "Call1r1e", s) 177 } 178 179 func (a *SimpleMethods) Call1r0e(s stringVal) error { 180 a.root.called(a, "Call1r0e", s) 181 return a.root.callError(a, "Call1r0e", s) 182 } 183 184 func (a *SimpleMethods) SliceArg(struct{ X []string }) stringVal { 185 return stringVal{"SliceArg ret"} 186 } 187 188 func (a *SimpleMethods) Discard1(int) {} 189 190 func (a *SimpleMethods) Discard2(struct{}, struct{}) {} 191 192 func (a *SimpleMethods) Discard3() int { return 0 } 193 194 func (a *SimpleMethods) Discard4() (_, _ struct{}) { return } 195 196 type DelayedMethods struct { 197 ready chan struct{} 198 done chan string 199 doneError chan error 200 } 201 202 func (a *DelayedMethods) Delay() (stringVal, error) { 203 if a.ready != nil { 204 a.ready <- struct{}{} 205 } 206 select { 207 case s := <-a.done: 208 return stringVal{s}, nil 209 case err := <-a.doneError: 210 return stringVal{}, err 211 } 212 } 213 214 type ErrorMethods struct { 215 err error 216 } 217 218 func (e *ErrorMethods) Call() error { 219 return e.err 220 } 221 222 type CallbackMethods struct { 223 root *Root 224 } 225 226 type int64val struct { 227 I int64 228 } 229 230 func (a *CallbackMethods) Factorial(x int64val) (int64val, error) { 231 if x.I <= 1 { 232 return int64val{1}, nil 233 } 234 var r int64val 235 err := a.root.conn.Call(rpc.Request{"CallbackMethods", 0, "", "Factorial"}, int64val{x.I - 1}, &r) 236 if err != nil { 237 return int64val{}, err 238 } 239 return int64val{x.I * r.I}, nil 240 } 241 242 func (a *ChangeAPIMethods) ChangeAPI() { 243 a.r.conn.Serve(&changedAPIRoot{}, nil) 244 } 245 246 func (a *ChangeAPIMethods) RemoveAPI() { 247 a.r.conn.Serve(nil, nil) 248 } 249 250 type changedAPIRoot struct{} 251 252 func (r *changedAPIRoot) NewlyAvailable(string) (newlyAvailableMethods, error) { 253 return newlyAvailableMethods{}, nil 254 } 255 256 type newlyAvailableMethods struct{} 257 258 func (newlyAvailableMethods) NewMethod() stringVal { 259 return stringVal{"new method result"} 260 } 261 262 type VariableMethods1 struct { 263 sm *SimpleMethods 264 } 265 266 func (vm *VariableMethods1) Call0r1() stringVal { 267 return vm.sm.Call0r1() 268 } 269 270 type VariableMethods2 struct { 271 sm *SimpleMethods 272 } 273 274 func (vm *VariableMethods2) Call1r1(s stringVal) stringVal { 275 return vm.sm.Call1r1(s) 276 } 277 278 type RestrictedMethods struct { 279 InterfaceMethods 280 } 281 282 type CustomMethodFinder struct { 283 root *Root 284 } 285 286 type wrapper func(*SimpleMethods) reflect.Value 287 288 type customMethodCaller struct { 289 wrap wrapper 290 root *Root 291 objMethod rpcreflect.ObjMethod 292 expectedType reflect.Type 293 } 294 295 func (c customMethodCaller) ParamsType() reflect.Type { 296 return c.objMethod.Params 297 } 298 299 func (c customMethodCaller) ResultType() reflect.Type { 300 return c.objMethod.Result 301 } 302 303 func (c customMethodCaller) Call(objId string, arg reflect.Value) (reflect.Value, error) { 304 sm, err := c.root.SimpleMethods(objId) 305 if err != nil { 306 return reflect.Value{}, err 307 } 308 obj := c.wrap(sm) 309 if reflect.TypeOf(obj) != c.expectedType { 310 logger.Errorf("got the wrong type back, expected %s got %T", c.expectedType, obj) 311 } 312 logger.Debugf("calling: %T %v %#v", obj, obj, c.objMethod) 313 return c.objMethod.Call(obj, arg) 314 } 315 316 func (cc *CustomMethodFinder) FindMethod( 317 rootMethodName string, version int, objMethodName string, 318 ) ( 319 rpcreflect.MethodCaller, error, 320 ) { 321 logger.Debugf("got to FindMethod: %q %d %q", rootMethodName, version, objMethodName) 322 if rootMethodName != "MultiVersion" { 323 return nil, &rpcreflect.CallNotImplementedError{ 324 RootMethod: rootMethodName, 325 } 326 } 327 var goType reflect.Type 328 var wrap wrapper 329 switch version { 330 case 0: 331 goType = reflect.TypeOf((*VariableMethods1)(nil)) 332 wrap = func(sm *SimpleMethods) reflect.Value { 333 return reflect.ValueOf(&VariableMethods1{sm}) 334 } 335 case 1: 336 goType = reflect.TypeOf((*VariableMethods2)(nil)) 337 wrap = func(sm *SimpleMethods) reflect.Value { 338 return reflect.ValueOf(&VariableMethods2{sm}) 339 } 340 case 2: 341 goType = reflect.TypeOf((*RestrictedMethods)(nil)) 342 wrap = func(sm *SimpleMethods) reflect.Value { 343 methods := &RestrictedMethods{InterfaceMethods: sm} 344 return reflect.ValueOf(methods) 345 } 346 default: 347 return nil, &rpcreflect.CallNotImplementedError{ 348 RootMethod: rootMethodName, 349 Version: version, 350 } 351 } 352 logger.Debugf("found type: %s", goType) 353 objType := rpcreflect.ObjTypeOf(goType) 354 objMethod, err := objType.Method(objMethodName) 355 if err != nil { 356 return nil, &rpcreflect.CallNotImplementedError{ 357 RootMethod: rootMethodName, 358 Version: version, 359 Method: objMethodName, 360 } 361 } 362 return customMethodCaller{ 363 objMethod: objMethod, 364 root: cc.root, 365 wrap: wrap, 366 expectedType: goType, 367 }, nil 368 } 369 370 func SimpleRoot() *Root { 371 root := &Root{ 372 simple: make(map[string]*SimpleMethods), 373 } 374 root.simple["a99"] = &SimpleMethods{root: root, id: "a99"} 375 return root 376 } 377 378 func (*rpcSuite) TestRPC(c *gc.C) { 379 root := SimpleRoot() 380 client, srvDone, clientNotifier, serverNotifier := newRPCClientServer(c, root, nil, false) 381 defer closeClient(c, client, srvDone) 382 for narg := 0; narg < 2; narg++ { 383 for nret := 0; nret < 2; nret++ { 384 for nerr := 0; nerr < 2; nerr++ { 385 retErr := nerr != 0 386 p := testCallParams{ 387 client: client, 388 clientNotifier: clientNotifier, 389 serverNotifier: serverNotifier, 390 entry: "SimpleMethods", 391 narg: narg, 392 nret: nret, 393 retErr: retErr, 394 testErr: false, 395 } 396 root.testCall(c, p) 397 if retErr { 398 p.testErr = true 399 root.testCall(c, p) 400 } 401 } 402 } 403 } 404 } 405 406 func callName(narg, nret int, retErr bool) string { 407 e := "" 408 if retErr { 409 e = "e" 410 } 411 return fmt.Sprintf("Call%dr%d%s", narg, nret, e) 412 } 413 414 type testCallParams struct { 415 // client holds the client-side of the rpc connection that 416 // will be used to make the call. 417 client *rpc.Conn 418 419 // clientNotifier holds the notifier for the client side. 420 clientNotifier *notifier 421 422 // serverNotifier holds the notifier for the server side. 423 serverNotifier *notifier 424 425 // entry holds the top-level type that will be invoked 426 // (e.g. "SimpleMethods"). 427 entry string 428 429 // narg holds the number of arguments accepted by the 430 // call (0 or 1). 431 narg int 432 433 // nret holds the number of values returned by the 434 // call (0 or 1). 435 nret int 436 437 // retErr specifies whether the call returns an error. 438 retErr bool 439 440 // testErr specifies whether the call should be made to return an error. 441 testErr bool 442 443 // version specifies what version of the interface to call, defaults to 0. 444 version int 445 } 446 447 // request returns the RPC request for the test call. 448 func (p testCallParams) request() rpc.Request { 449 return rpc.Request{ 450 Type: p.entry, 451 Version: p.version, 452 Id: "a99", 453 Action: callName(p.narg, p.nret, p.retErr), 454 } 455 } 456 457 // error message returns the error message that the test call 458 // should return if it returns an error. 459 func (p testCallParams) errorMessage() string { 460 return fmt.Sprintf("error calling %s", p.request().Action) 461 } 462 463 func (root *Root) testCall(c *gc.C, p testCallParams) { 464 p.clientNotifier.reset() 465 p.serverNotifier.reset() 466 root.calls = nil 467 root.returnErr = p.testErr 468 c.Logf("test call %s", p.request().Action) 469 var r stringVal 470 err := p.client.Call(p.request(), stringVal{"arg"}, &r) 471 switch { 472 case p.retErr && p.testErr: 473 c.Assert(err, gc.DeepEquals, &rpc.RequestError{ 474 Message: p.errorMessage(), 475 }) 476 c.Assert(r, gc.Equals, stringVal{}) 477 case p.nret > 0: 478 c.Check(r, gc.Equals, stringVal{p.request().Action + " ret"}) 479 } 480 if !p.testErr { 481 c.Check(err, jc.ErrorIsNil) 482 } 483 484 // Check that the call was actually made, the right 485 // parameters were received and the right result returned. 486 root.mu.Lock() 487 defer root.mu.Unlock() 488 489 root.assertCallMade(c, p) 490 491 requestId := root.assertClientNotified(c, p, &r) 492 493 root.assertServerNotified(c, p, requestId) 494 } 495 496 func (root *Root) assertCallMade(c *gc.C, p testCallParams) { 497 expectCall := callInfo{ 498 rcvr: root.simple["a99"], 499 method: p.request().Action, 500 } 501 if p.narg > 0 { 502 expectCall.arg = stringVal{"arg"} 503 } 504 c.Assert(root.calls, gc.HasLen, 1) 505 c.Assert(*root.calls[0], gc.Equals, expectCall) 506 } 507 508 // assertClientNotified asserts that the right client notifications 509 // were made for the given test call parameters. The value of r 510 // holds the result parameter passed to the call. 511 // It returns the request id. 512 func (root *Root) assertClientNotified(c *gc.C, p testCallParams, r interface{}) uint64 { 513 c.Assert(p.clientNotifier.serverRequests, gc.HasLen, 0) 514 c.Assert(p.clientNotifier.serverReplies, gc.HasLen, 0) 515 516 // Test that there was a notification for the request. 517 c.Assert(p.clientNotifier.clientRequests, gc.HasLen, 1) 518 clientReq := p.clientNotifier.clientRequests[0] 519 requestId := clientReq.hdr.RequestId 520 clientReq.hdr.RequestId = 0 // Ignore the exact value of the request id to start with. 521 c.Assert(clientReq.hdr, gc.DeepEquals, rpc.Header{ 522 Request: p.request(), 523 }) 524 c.Assert(clientReq.body, gc.Equals, stringVal{"arg"}) 525 526 // Test that there was a notification for the reply. 527 c.Assert(p.clientNotifier.clientReplies, gc.HasLen, 1) 528 clientReply := p.clientNotifier.clientReplies[0] 529 c.Assert(clientReply.req, gc.Equals, p.request()) 530 if p.retErr && p.testErr { 531 c.Assert(clientReply.body, gc.Equals, nil) 532 } else { 533 c.Assert(clientReply.body, gc.Equals, r) 534 } 535 if p.retErr && p.testErr { 536 c.Assert(clientReply.hdr, gc.DeepEquals, rpc.Header{ 537 RequestId: requestId, 538 Error: p.errorMessage(), 539 }) 540 } else { 541 c.Assert(clientReply.hdr, gc.DeepEquals, rpc.Header{ 542 RequestId: requestId, 543 }) 544 } 545 return requestId 546 } 547 548 // assertServerNotified asserts that the right server notifications 549 // were made for the given test call parameters. The id of the request 550 // is held in requestId. 551 func (root *Root) assertServerNotified(c *gc.C, p testCallParams, requestId uint64) { 552 // Check that the right server notifications were made. 553 c.Assert(p.serverNotifier.clientRequests, gc.HasLen, 0) 554 c.Assert(p.serverNotifier.clientReplies, gc.HasLen, 0) 555 556 // Test that there was a notification for the request. 557 c.Assert(p.serverNotifier.serverRequests, gc.HasLen, 1) 558 serverReq := p.serverNotifier.serverRequests[0] 559 c.Assert(serverReq.hdr, gc.DeepEquals, rpc.Header{ 560 RequestId: requestId, 561 Request: p.request(), 562 }) 563 if p.narg > 0 { 564 c.Assert(serverReq.body, gc.Equals, stringVal{"arg"}) 565 } else { 566 c.Assert(serverReq.body, gc.Equals, struct{}{}) 567 } 568 569 // Test that there was a notification for the reply. 570 c.Assert(p.serverNotifier.serverReplies, gc.HasLen, 1) 571 serverReply := p.serverNotifier.serverReplies[0] 572 c.Assert(serverReply.req, gc.Equals, p.request()) 573 if p.retErr && p.testErr || p.nret == 0 { 574 c.Assert(serverReply.body, gc.Equals, struct{}{}) 575 } else { 576 c.Assert(serverReply.body, gc.Equals, stringVal{p.request().Action + " ret"}) 577 } 578 if p.retErr && p.testErr { 579 c.Assert(serverReply.hdr, gc.Equals, rpc.Header{ 580 RequestId: requestId, 581 Error: p.errorMessage(), 582 }) 583 } else { 584 c.Assert(serverReply.hdr, gc.Equals, rpc.Header{ 585 RequestId: requestId, 586 }) 587 } 588 } 589 590 func (*rpcSuite) TestInterfaceMethods(c *gc.C) { 591 root := SimpleRoot() 592 client, srvDone, clientNotifier, serverNotifier := newRPCClientServer(c, root, nil, false) 593 defer closeClient(c, client, srvDone) 594 p := testCallParams{ 595 client: client, 596 clientNotifier: clientNotifier, 597 serverNotifier: serverNotifier, 598 entry: "InterfaceMethods", 599 narg: 1, 600 nret: 1, 601 retErr: true, 602 testErr: false, 603 } 604 605 root.testCall(c, p) 606 p.testErr = true 607 root.testCall(c, p) 608 // Call0r0 is defined on the underlying SimpleMethods, but is not 609 // exposed at the InterfaceMethods level, so this call should fail with 610 // CodeNotImplemented. 611 var r stringVal 612 err := client.Call(rpc.Request{"InterfaceMethods", 0, "a99", "Call0r0"}, stringVal{"arg"}, &r) 613 c.Assert(err, gc.DeepEquals, &rpc.RequestError{ 614 Message: "no such request - method InterfaceMethods.Call0r0 is not implemented", 615 Code: rpc.CodeNotImplemented, 616 }) 617 } 618 619 func (*rpcSuite) TestCustomMethodFinderV0(c *gc.C) { 620 root := &CustomMethodFinder{SimpleRoot()} 621 client, srvDone, clientNotifier, serverNotifier := newRPCClientServer(c, root, nil, false) 622 defer closeClient(c, client, srvDone) 623 // V0 of MultiVersion implements only VariableMethods1.Call0r1. 624 p := testCallParams{ 625 client: client, 626 clientNotifier: clientNotifier, 627 serverNotifier: serverNotifier, 628 entry: "MultiVersion", 629 version: 0, 630 narg: 0, 631 nret: 1, 632 retErr: false, 633 testErr: false, 634 } 635 636 root.root.testCall(c, p) 637 // Call1r1 is exposed in version 1, but not in version 0. 638 var r stringVal 639 err := client.Call(rpc.Request{"MultiVersion", 0, "a99", "Call1r1"}, stringVal{"arg"}, &r) 640 c.Assert(err, gc.DeepEquals, &rpc.RequestError{ 641 Message: "no such request - method MultiVersion.Call1r1 is not implemented", 642 Code: rpc.CodeNotImplemented, 643 }) 644 } 645 646 func (*rpcSuite) TestCustomMethodFinderV1(c *gc.C) { 647 root := &CustomMethodFinder{SimpleRoot()} 648 client, srvDone, clientNotifier, serverNotifier := newRPCClientServer(c, root, nil, false) 649 defer closeClient(c, client, srvDone) 650 // V1 of MultiVersion implements only VariableMethods2.Call1r1. 651 p := testCallParams{ 652 client: client, 653 clientNotifier: clientNotifier, 654 serverNotifier: serverNotifier, 655 entry: "MultiVersion", 656 version: 1, 657 narg: 1, 658 nret: 1, 659 retErr: false, 660 testErr: false, 661 } 662 663 root.root.testCall(c, p) 664 // Call0r1 is exposed in version 0, but not in version 1. 665 var r stringVal 666 err := client.Call(rpc.Request{"MultiVersion", 1, "a99", "Call0r1"}, nil, &r) 667 c.Assert(err, gc.DeepEquals, &rpc.RequestError{ 668 Message: "no such request - method MultiVersion(1).Call0r1 is not implemented", 669 Code: rpc.CodeNotImplemented, 670 }) 671 } 672 673 func (*rpcSuite) TestCustomMethodFinderV2(c *gc.C) { 674 root := &CustomMethodFinder{SimpleRoot()} 675 client, srvDone, clientNotifier, serverNotifier := newRPCClientServer(c, root, nil, false) 676 defer closeClient(c, client, srvDone) 677 p := testCallParams{ 678 client: client, 679 clientNotifier: clientNotifier, 680 serverNotifier: serverNotifier, 681 entry: "MultiVersion", 682 version: 2, 683 narg: 1, 684 nret: 1, 685 retErr: true, 686 testErr: false, 687 } 688 689 root.root.testCall(c, p) 690 // By embedding the InterfaceMethods inside a concrete 691 // RestrictedMethods type, we actually only expose the methods defined 692 // in InterfaceMethods. 693 var r stringVal 694 err := client.Call(rpc.Request{"MultiVersion", 2, "a99", "Call0r1e"}, nil, &r) 695 c.Assert(err, gc.DeepEquals, &rpc.RequestError{ 696 Message: `no such request - method MultiVersion(2).Call0r1e is not implemented`, 697 Code: rpc.CodeNotImplemented, 698 }) 699 } 700 701 func (*rpcSuite) TestCustomMethodFinderUnknownVersion(c *gc.C) { 702 root := &CustomMethodFinder{SimpleRoot()} 703 client, srvDone, _, _ := newRPCClientServer(c, root, nil, false) 704 defer closeClient(c, client, srvDone) 705 var r stringVal 706 // Unknown version 5 707 err := client.Call(rpc.Request{"MultiVersion", 5, "a99", "Call0r1"}, nil, &r) 708 c.Assert(err, gc.DeepEquals, &rpc.RequestError{ 709 Message: `unknown version (5) of interface "MultiVersion"`, 710 Code: rpc.CodeNotImplemented, 711 }) 712 } 713 714 func (*rpcSuite) TestConcurrentCalls(c *gc.C) { 715 start1 := make(chan string) 716 start2 := make(chan string) 717 ready1 := make(chan struct{}) 718 ready2 := make(chan struct{}) 719 720 root := &Root{ 721 delayed: map[string]*DelayedMethods{ 722 "1": {ready: ready1, done: start1}, 723 "2": {ready: ready2, done: start2}, 724 }, 725 } 726 727 client, srvDone, _, _ := newRPCClientServer(c, root, nil, false) 728 defer closeClient(c, client, srvDone) 729 call := func(id string, done chan<- struct{}) { 730 var r stringVal 731 err := client.Call(rpc.Request{"DelayedMethods", 0, id, "Delay"}, nil, &r) 732 c.Check(err, jc.ErrorIsNil) 733 c.Check(r.Val, gc.Equals, "return "+id) 734 done <- struct{}{} 735 } 736 done1 := make(chan struct{}) 737 done2 := make(chan struct{}) 738 go call("1", done1) 739 go call("2", done2) 740 741 // Check that both calls are running concurrently. 742 chanRead(c, ready1, "method 1 ready") 743 chanRead(c, ready2, "method 2 ready") 744 745 // Let the requests complete. 746 start1 <- "return 1" 747 start2 <- "return 2" 748 chanRead(c, done1, "method 1 done") 749 chanRead(c, done2, "method 2 done") 750 } 751 752 type codedError struct { 753 m string 754 code string 755 } 756 757 func (e *codedError) Error() string { 758 return e.m 759 } 760 761 func (e *codedError) ErrorCode() string { 762 return e.code 763 } 764 765 func (*rpcSuite) TestErrorCode(c *gc.C) { 766 root := &Root{ 767 errorInst: &ErrorMethods{&codedError{"message", "code"}}, 768 } 769 client, srvDone, _, _ := newRPCClientServer(c, root, nil, false) 770 defer closeClient(c, client, srvDone) 771 err := client.Call(rpc.Request{"ErrorMethods", 0, "", "Call"}, nil, nil) 772 c.Assert(err, gc.ErrorMatches, `request error: message \(code\)`) 773 c.Assert(err.(rpc.ErrorCoder).ErrorCode(), gc.Equals, "code") 774 } 775 776 func (*rpcSuite) TestTransformErrors(c *gc.C) { 777 root := &Root{ 778 errorInst: &ErrorMethods{&codedError{"message", "code"}}, 779 } 780 tfErr := func(err error) error { 781 c.Check(err, gc.NotNil) 782 if e, ok := err.(*codedError); ok { 783 return &codedError{ 784 m: "transformed: " + e.m, 785 code: "transformed: " + e.code, 786 } 787 } 788 return fmt.Errorf("transformed: %v", err) 789 } 790 client, srvDone, _, _ := newRPCClientServer(c, root, tfErr, false) 791 defer closeClient(c, client, srvDone) 792 // First, we don't transform methods we can't find. 793 err := client.Call(rpc.Request{"foo", 0, "", "bar"}, nil, nil) 794 c.Assert(err, gc.DeepEquals, &rpc.RequestError{ 795 Message: `unknown object type "foo"`, 796 Code: rpc.CodeNotImplemented, 797 }) 798 799 err = client.Call(rpc.Request{"ErrorMethods", 0, "", "NoMethod"}, nil, nil) 800 c.Assert(err, gc.DeepEquals, &rpc.RequestError{ 801 Message: "no such request - method ErrorMethods.NoMethod is not implemented", 802 Code: rpc.CodeNotImplemented, 803 }) 804 805 // We do transform any errors that happen from calling the RootMethod 806 // and beyond. 807 err = client.Call(rpc.Request{"ErrorMethods", 0, "", "Call"}, nil, nil) 808 c.Assert(err, gc.DeepEquals, &rpc.RequestError{ 809 Message: "transformed: message", 810 Code: "transformed: code", 811 }) 812 813 root.errorInst.err = nil 814 err = client.Call(rpc.Request{"ErrorMethods", 0, "", "Call"}, nil, nil) 815 c.Assert(err, jc.ErrorIsNil) 816 817 root.errorInst = nil 818 err = client.Call(rpc.Request{"ErrorMethods", 0, "", "Call"}, nil, nil) 819 c.Assert(err, gc.DeepEquals, &rpc.RequestError{ 820 Message: "transformed: no error methods", 821 }) 822 823 } 824 825 func (*rpcSuite) TestServerWaitsForOutstandingCalls(c *gc.C) { 826 ready := make(chan struct{}) 827 start := make(chan string) 828 root := &Root{ 829 delayed: map[string]*DelayedMethods{ 830 "1": { 831 ready: ready, 832 done: start, 833 }, 834 }, 835 } 836 client, srvDone, _, _ := newRPCClientServer(c, root, nil, false) 837 defer closeClient(c, client, srvDone) 838 done := make(chan struct{}) 839 go func() { 840 var r stringVal 841 err := client.Call(rpc.Request{"DelayedMethods", 0, "1", "Delay"}, nil, &r) 842 c.Check(err, gc.Equals, rpc.ErrShutdown) 843 done <- struct{}{} 844 }() 845 chanRead(c, ready, "DelayedMethods.Delay ready") 846 client.Close() 847 select { 848 case err := <-srvDone: 849 c.Fatalf("server returned while outstanding operation in progress: %v", err) 850 <-done 851 case <-time.After(25 * time.Millisecond): 852 } 853 start <- "xxx" 854 } 855 856 func chanRead(c *gc.C, ch <-chan struct{}, what string) { 857 select { 858 case <-ch: 859 return 860 case <-time.After(3 * time.Second): 861 c.Fatalf("timeout on channel read %s", what) 862 } 863 } 864 865 func (*rpcSuite) TestCompatibility(c *gc.C) { 866 root := &Root{ 867 simple: make(map[string]*SimpleMethods), 868 } 869 a0 := &SimpleMethods{root: root, id: "a0"} 870 root.simple["a0"] = a0 871 872 client, srvDone, _, _ := newRPCClientServer(c, root, nil, false) 873 defer closeClient(c, client, srvDone) 874 call := func(method string, arg, ret interface{}) (passedArg interface{}) { 875 root.calls = nil 876 err := client.Call(rpc.Request{"SimpleMethods", 0, "a0", method}, arg, ret) 877 c.Assert(err, jc.ErrorIsNil) 878 c.Assert(root.calls, gc.HasLen, 1) 879 info := root.calls[0] 880 c.Assert(info.rcvr, gc.Equals, a0) 881 c.Assert(info.method, gc.Equals, method) 882 return info.arg 883 } 884 type extra struct { 885 Val string 886 Extra string 887 } 888 // Extra fields in request and response. 889 var r extra 890 arg := call("Call1r1", extra{"x", "y"}, &r) 891 c.Assert(arg, gc.Equals, stringVal{"x"}) 892 893 // Nil argument as request. 894 r = extra{} 895 arg = call("Call1r1", nil, &r) 896 c.Assert(arg, gc.Equals, stringVal{}) 897 898 // Nil argument as response. 899 arg = call("Call1r1", stringVal{"x"}, nil) 900 c.Assert(arg, gc.Equals, stringVal{"x"}) 901 902 // Non-nil argument for no response. 903 r = extra{} 904 arg = call("Call1r0", stringVal{"x"}, &r) 905 c.Assert(arg, gc.Equals, stringVal{"x"}) 906 c.Assert(r, gc.Equals, extra{}) 907 } 908 909 func (*rpcSuite) TestBadCall(c *gc.C) { 910 root := &Root{ 911 simple: make(map[string]*SimpleMethods), 912 } 913 a0 := &SimpleMethods{root: root, id: "a0"} 914 root.simple["a0"] = a0 915 client, srvDone, clientNotifier, serverNotifier := newRPCClientServer(c, root, nil, false) 916 defer closeClient(c, client, srvDone) 917 918 testBadCall(c, client, clientNotifier, serverNotifier, 919 rpc.Request{"BadSomething", 0, "a0", "No"}, 920 `unknown object type "BadSomething"`, 921 rpc.CodeNotImplemented, 922 false, 923 ) 924 testBadCall(c, client, clientNotifier, serverNotifier, 925 rpc.Request{"SimpleMethods", 0, "xx", "No"}, 926 "no such request - method SimpleMethods.No is not implemented", 927 rpc.CodeNotImplemented, 928 false, 929 ) 930 testBadCall(c, client, clientNotifier, serverNotifier, 931 rpc.Request{"SimpleMethods", 0, "xx", "Call0r0"}, 932 `unknown SimpleMethods id`, 933 "", 934 true, 935 ) 936 } 937 938 func testBadCall( 939 c *gc.C, 940 client *rpc.Conn, 941 clientNotifier, serverNotifier *notifier, 942 req rpc.Request, 943 expectedErr string, 944 expectedErrCode string, 945 requestKnown bool, 946 ) { 947 clientNotifier.reset() 948 serverNotifier.reset() 949 err := client.Call(req, nil, nil) 950 msg := expectedErr 951 if expectedErrCode != "" { 952 msg += " (" + expectedErrCode + ")" 953 } 954 c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta("request error: "+msg)) 955 956 // Test that there was a notification for the client request. 957 c.Assert(clientNotifier.clientRequests, gc.HasLen, 1) 958 clientReq := clientNotifier.clientRequests[0] 959 requestId := clientReq.hdr.RequestId 960 c.Assert(clientReq, gc.DeepEquals, requestEvent{ 961 hdr: rpc.Header{ 962 RequestId: requestId, 963 Request: req, 964 }, 965 body: struct{}{}, 966 }) 967 // Test that there was a notification for the client reply. 968 c.Assert(clientNotifier.clientReplies, gc.HasLen, 1) 969 clientReply := clientNotifier.clientReplies[0] 970 c.Assert(clientReply, gc.DeepEquals, replyEvent{ 971 req: req, 972 hdr: rpc.Header{ 973 RequestId: requestId, 974 Error: expectedErr, 975 ErrorCode: expectedErrCode, 976 }, 977 }) 978 979 // Test that there was a notification for the server request. 980 c.Assert(serverNotifier.serverRequests, gc.HasLen, 1) 981 serverReq := serverNotifier.serverRequests[0] 982 983 // From docs on ServerRequest: 984 // If the request was not recognized or there was 985 // an error reading the body, body will be nil. 986 var expectBody interface{} 987 if requestKnown { 988 expectBody = struct{}{} 989 } 990 c.Assert(serverReq, gc.DeepEquals, requestEvent{ 991 hdr: rpc.Header{ 992 RequestId: requestId, 993 Request: req, 994 }, 995 body: expectBody, 996 }) 997 998 // Test that there was a notification for the server reply. 999 c.Assert(serverNotifier.serverReplies, gc.HasLen, 1) 1000 serverReply := serverNotifier.serverReplies[0] 1001 c.Assert(serverReply, gc.DeepEquals, replyEvent{ 1002 hdr: rpc.Header{ 1003 RequestId: requestId, 1004 Error: expectedErr, 1005 ErrorCode: expectedErrCode, 1006 }, 1007 req: req, 1008 body: struct{}{}, 1009 }) 1010 } 1011 1012 func (*rpcSuite) TestContinueAfterReadBodyError(c *gc.C) { 1013 root := &Root{ 1014 simple: make(map[string]*SimpleMethods), 1015 } 1016 a0 := &SimpleMethods{root: root, id: "a0"} 1017 root.simple["a0"] = a0 1018 client, srvDone, _, _ := newRPCClientServer(c, root, nil, false) 1019 defer closeClient(c, client, srvDone) 1020 1021 var ret stringVal 1022 arg0 := struct { 1023 X map[string]int 1024 }{ 1025 X: map[string]int{"hello": 65}, 1026 } 1027 err := client.Call(rpc.Request{"SimpleMethods", 0, "a0", "SliceArg"}, arg0, &ret) 1028 c.Assert(err, gc.ErrorMatches, `request error: json: cannot unmarshal object into Go value of type \[\]string`) 1029 1030 err = client.Call(rpc.Request{"SimpleMethods", 0, "a0", "SliceArg"}, arg0, &ret) 1031 c.Assert(err, gc.ErrorMatches, `request error: json: cannot unmarshal object into Go value of type \[\]string`) 1032 1033 arg1 := struct { 1034 X []string 1035 }{ 1036 X: []string{"one"}, 1037 } 1038 err = client.Call(rpc.Request{"SimpleMethods", 0, "a0", "SliceArg"}, arg1, &ret) 1039 c.Assert(err, jc.ErrorIsNil) 1040 c.Assert(ret.Val, gc.Equals, "SliceArg ret") 1041 } 1042 1043 func (*rpcSuite) TestErrorAfterClientClose(c *gc.C) { 1044 client, srvDone, _, _ := newRPCClientServer(c, &Root{}, nil, false) 1045 err := client.Close() 1046 c.Assert(err, jc.ErrorIsNil) 1047 err = client.Call(rpc.Request{"Foo", 0, "", "Bar"}, nil, nil) 1048 c.Assert(err, gc.Equals, rpc.ErrShutdown) 1049 err = chanReadError(c, srvDone, "server done") 1050 c.Assert(err, jc.ErrorIsNil) 1051 } 1052 1053 func (*rpcSuite) TestClientCloseIdempotent(c *gc.C) { 1054 client, _, _, _ := newRPCClientServer(c, &Root{}, nil, false) 1055 err := client.Close() 1056 c.Assert(err, jc.ErrorIsNil) 1057 err = client.Close() 1058 c.Assert(err, jc.ErrorIsNil) 1059 err = client.Close() 1060 c.Assert(err, jc.ErrorIsNil) 1061 } 1062 1063 type KillerCleanerRoot struct { 1064 events []string 1065 Root 1066 } 1067 1068 func (r *KillerCleanerRoot) Kill() { 1069 r.events = append(r.events, "kill") 1070 } 1071 1072 func (r *KillerCleanerRoot) Cleanup() { 1073 r.events = append(r.events, "cleanup") 1074 } 1075 1076 func (*rpcSuite) TestRootIsKilledAndCleaned(c *gc.C) { 1077 root := &KillerCleanerRoot{} 1078 client, srvDone, _, _ := newRPCClientServer(c, root, nil, false) 1079 err := client.Close() 1080 c.Assert(err, jc.ErrorIsNil) 1081 err = chanReadError(c, srvDone, "server done") 1082 c.Assert(err, jc.ErrorIsNil) 1083 // Kill should happen first. 1084 c.Assert(root.events, jc.DeepEquals, []string{"kill", "cleanup"}) 1085 } 1086 1087 func (*rpcSuite) TestBidirectional(c *gc.C) { 1088 srvRoot := &Root{} 1089 client, srvDone, _, _ := newRPCClientServer(c, srvRoot, nil, true) 1090 defer closeClient(c, client, srvDone) 1091 clientRoot := &Root{conn: client} 1092 client.Serve(clientRoot, nil) 1093 var r int64val 1094 err := client.Call(rpc.Request{"CallbackMethods", 0, "", "Factorial"}, int64val{12}, &r) 1095 c.Assert(err, jc.ErrorIsNil) 1096 c.Assert(r.I, gc.Equals, int64(479001600)) 1097 } 1098 1099 func (*rpcSuite) TestServerRequestWhenNotServing(c *gc.C) { 1100 srvRoot := &Root{} 1101 client, srvDone, _, _ := newRPCClientServer(c, srvRoot, nil, true) 1102 defer closeClient(c, client, srvDone) 1103 var r int64val 1104 err := client.Call(rpc.Request{"CallbackMethods", 0, "", "Factorial"}, int64val{12}, &r) 1105 c.Assert(err, gc.ErrorMatches, "request error: request error: no service") 1106 } 1107 1108 func (*rpcSuite) TestChangeAPI(c *gc.C) { 1109 srvRoot := &Root{} 1110 client, srvDone, _, _ := newRPCClientServer(c, srvRoot, nil, true) 1111 defer closeClient(c, client, srvDone) 1112 var s stringVal 1113 err := client.Call(rpc.Request{"NewlyAvailable", 0, "", "NewMethod"}, nil, &s) 1114 c.Assert(err, gc.ErrorMatches, `request error: unknown object type "NewlyAvailable" \(not implemented\)`) 1115 err = client.Call(rpc.Request{"ChangeAPIMethods", 0, "", "ChangeAPI"}, nil, nil) 1116 c.Assert(err, jc.ErrorIsNil) 1117 err = client.Call(rpc.Request{"ChangeAPIMethods", 0, "", "ChangeAPI"}, nil, nil) 1118 c.Assert(err, gc.ErrorMatches, `request error: unknown object type "ChangeAPIMethods" \(not implemented\)`) 1119 err = client.Call(rpc.Request{"NewlyAvailable", 0, "", "NewMethod"}, nil, &s) 1120 c.Assert(err, jc.ErrorIsNil) 1121 c.Assert(s, gc.Equals, stringVal{"new method result"}) 1122 } 1123 1124 func (*rpcSuite) TestChangeAPIToNil(c *gc.C) { 1125 srvRoot := &Root{} 1126 client, srvDone, _, _ := newRPCClientServer(c, srvRoot, nil, true) 1127 defer closeClient(c, client, srvDone) 1128 1129 err := client.Call(rpc.Request{"ChangeAPIMethods", 0, "", "RemoveAPI"}, nil, nil) 1130 c.Assert(err, jc.ErrorIsNil) 1131 1132 err = client.Call(rpc.Request{"ChangeAPIMethods", 0, "", "RemoveAPI"}, nil, nil) 1133 c.Assert(err, gc.ErrorMatches, "request error: no service") 1134 } 1135 1136 func (*rpcSuite) TestChangeAPIWhileServingRequest(c *gc.C) { 1137 ready := make(chan struct{}) 1138 done := make(chan error) 1139 srvRoot := &Root{ 1140 delayed: map[string]*DelayedMethods{ 1141 "1": {ready: ready, doneError: done}, 1142 }, 1143 } 1144 transform := func(err error) error { 1145 return fmt.Errorf("transformed: %v", err) 1146 } 1147 client, srvDone, _, _ := newRPCClientServer(c, srvRoot, transform, true) 1148 defer closeClient(c, client, srvDone) 1149 1150 result := make(chan error) 1151 go func() { 1152 result <- client.Call(rpc.Request{"DelayedMethods", 0, "1", "Delay"}, nil, nil) 1153 }() 1154 chanRead(c, ready, "method ready") 1155 1156 err := client.Call(rpc.Request{"ChangeAPIMethods", 0, "", "ChangeAPI"}, nil, nil) 1157 c.Assert(err, jc.ErrorIsNil) 1158 1159 // Ensure that not only does the request in progress complete, 1160 // but that the original transformErrors function is called. 1161 done <- fmt.Errorf("an error") 1162 select { 1163 case r := <-result: 1164 c.Assert(r, gc.ErrorMatches, "request error: transformed: an error") 1165 case <-time.After(3 * time.Second): 1166 c.Fatalf("timeout on channel read") 1167 } 1168 } 1169 1170 func chanReadError(c *gc.C, ch <-chan error, what string) error { 1171 select { 1172 case e := <-ch: 1173 return e 1174 case <-time.After(3 * time.Second): 1175 c.Fatalf("timeout on channel read %s", what) 1176 } 1177 panic("unreachable") 1178 } 1179 1180 // newRPCClientServer starts an RPC server serving a connection from a 1181 // single client. When the server has finished serving the connection, 1182 // it sends a value on the returned channel. 1183 // If bidir is true, requests can flow in both directions. 1184 func newRPCClientServer(c *gc.C, root interface{}, tfErr func(error) error, bidir bool) (client *rpc.Conn, srvDone chan error, clientNotifier, serverNotifier *notifier) { 1185 l, err := net.Listen("tcp", "127.0.0.1:0") 1186 c.Assert(err, jc.ErrorIsNil) 1187 1188 srvDone = make(chan error, 1) 1189 clientNotifier = new(notifier) 1190 serverNotifier = new(notifier) 1191 go func() { 1192 conn, err := l.Accept() 1193 if err != nil { 1194 srvDone <- nil 1195 return 1196 } 1197 defer l.Close() 1198 role := roleServer 1199 if bidir { 1200 role = roleBoth 1201 } 1202 rpcConn := rpc.NewConn(NewJSONCodec(conn, role), serverNotifier) 1203 if custroot, ok := root.(*CustomMethodFinder); ok { 1204 rpcConn.ServeFinder(custroot, tfErr) 1205 custroot.root.conn = rpcConn 1206 } else { 1207 rpcConn.Serve(root, tfErr) 1208 } 1209 if root, ok := root.(*Root); ok { 1210 root.conn = rpcConn 1211 } 1212 rpcConn.Start() 1213 <-rpcConn.Dead() 1214 srvDone <- rpcConn.Close() 1215 }() 1216 conn, err := net.Dial("tcp", l.Addr().String()) 1217 c.Assert(err, jc.ErrorIsNil) 1218 role := roleClient 1219 if bidir { 1220 role = roleBoth 1221 } 1222 client = rpc.NewConn(NewJSONCodec(conn, role), clientNotifier) 1223 client.Start() 1224 return client, srvDone, clientNotifier, serverNotifier 1225 } 1226 1227 func closeClient(c *gc.C, client *rpc.Conn, srvDone <-chan error) { 1228 err := client.Close() 1229 c.Assert(err, jc.ErrorIsNil) 1230 err = chanReadError(c, srvDone, "server done") 1231 c.Assert(err, jc.ErrorIsNil) 1232 } 1233 1234 type encoder interface { 1235 Encode(e interface{}) error 1236 } 1237 1238 type decoder interface { 1239 Decode(e interface{}) error 1240 } 1241 1242 // testCodec wraps an rpc.Codec with extra error checking code. 1243 type testCodec struct { 1244 role connRole 1245 rpc.Codec 1246 } 1247 1248 func (c *testCodec) WriteMessage(hdr *rpc.Header, x interface{}) error { 1249 if reflect.ValueOf(x).Kind() != reflect.Struct { 1250 panic(fmt.Errorf("WriteRequest bad param; want struct got %T (%#v)", x, x)) 1251 } 1252 if c.role != roleBoth && hdr.IsRequest() != (c.role == roleClient) { 1253 panic(fmt.Errorf("codec role %v; header wrong type %#v", c.role, hdr)) 1254 } 1255 logger.Infof("send header: %#v; body: %#v", hdr, x) 1256 return c.Codec.WriteMessage(hdr, x) 1257 } 1258 1259 func (c *testCodec) ReadHeader(hdr *rpc.Header) error { 1260 err := c.Codec.ReadHeader(hdr) 1261 if err != nil { 1262 return err 1263 } 1264 logger.Infof("got header %#v", hdr) 1265 if c.role != roleBoth && hdr.IsRequest() == (c.role == roleClient) { 1266 panic(fmt.Errorf("codec role %v; read wrong type %#v", c.role, hdr)) 1267 } 1268 return nil 1269 } 1270 1271 func (c *testCodec) ReadBody(r interface{}, isRequest bool) error { 1272 if v := reflect.ValueOf(r); v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { 1273 panic(fmt.Errorf("ReadResponseBody bad destination; want *struct got %T", r)) 1274 } 1275 if c.role != roleBoth && isRequest == (c.role == roleClient) { 1276 panic(fmt.Errorf("codec role %v; read wrong body type %#v", c.role, r)) 1277 } 1278 // Note: this will need to change if we want to test a non-JSON codec. 1279 var m json.RawMessage 1280 err := c.Codec.ReadBody(&m, isRequest) 1281 if err != nil { 1282 return err 1283 } 1284 logger.Infof("got response body: %q", m) 1285 err = json.Unmarshal(m, r) 1286 logger.Infof("unmarshalled into %#v", r) 1287 return err 1288 } 1289 1290 type connRole string 1291 1292 const ( 1293 roleBoth connRole = "both" 1294 roleClient connRole = "client" 1295 roleServer connRole = "server" 1296 ) 1297 1298 func NewJSONCodec(c net.Conn, role connRole) rpc.Codec { 1299 return &testCodec{ 1300 role: role, 1301 Codec: jsoncodec.NewNet(c), 1302 } 1303 } 1304 1305 type requestEvent struct { 1306 hdr rpc.Header 1307 body interface{} 1308 } 1309 1310 type replyEvent struct { 1311 req rpc.Request 1312 hdr rpc.Header 1313 body interface{} 1314 } 1315 1316 type notifier struct { 1317 mu sync.Mutex 1318 serverRequests []requestEvent 1319 serverReplies []replyEvent 1320 clientRequests []requestEvent 1321 clientReplies []replyEvent 1322 } 1323 1324 func (n *notifier) reset() { 1325 n.mu.Lock() 1326 defer n.mu.Unlock() 1327 n.serverRequests = nil 1328 n.serverReplies = nil 1329 n.clientRequests = nil 1330 n.clientReplies = nil 1331 } 1332 1333 func (n *notifier) ServerRequest(hdr *rpc.Header, body interface{}) { 1334 n.mu.Lock() 1335 defer n.mu.Unlock() 1336 n.serverRequests = append(n.serverRequests, requestEvent{ 1337 hdr: *hdr, 1338 body: body, 1339 }) 1340 } 1341 1342 func (n *notifier) ServerReply(req rpc.Request, hdr *rpc.Header, body interface{}, timeSpent time.Duration) { 1343 n.mu.Lock() 1344 defer n.mu.Unlock() 1345 n.serverReplies = append(n.serverReplies, replyEvent{ 1346 req: req, 1347 hdr: *hdr, 1348 body: body, 1349 }) 1350 } 1351 1352 func (n *notifier) ClientRequest(hdr *rpc.Header, body interface{}) { 1353 n.mu.Lock() 1354 defer n.mu.Unlock() 1355 n.clientRequests = append(n.clientRequests, requestEvent{ 1356 hdr: *hdr, 1357 body: body, 1358 }) 1359 } 1360 1361 func (n *notifier) ClientReply(req rpc.Request, hdr *rpc.Header, body interface{}) { 1362 n.mu.Lock() 1363 defer n.mu.Unlock() 1364 n.clientReplies = append(n.clientReplies, replyEvent{ 1365 req: req, 1366 hdr: *hdr, 1367 body: body, 1368 }) 1369 }