github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/rpc/client_test.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2016 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package rpc 26 27 import ( 28 "context" 29 "fmt" 30 "math/rand" 31 "net" 32 "net/http" 33 "net/http/httptest" 34 "os" 35 "reflect" 36 "runtime" 37 "sync" 38 "testing" 39 "time" 40 41 "github.com/davecgh/go-spew/spew" 42 "github.com/ethereum/go-ethereum/log" 43 ) 44 45 func TestClientRequest(t *testing.T) { 46 server := newTestServer("service", new(Service)) 47 defer server.Stop() 48 client := DialInProc(server) 49 defer client.Close() 50 51 var resp Result 52 if err := client.Call(&resp, "service_echo", "hello", 10, &Args{"world"}); err != nil { 53 t.Fatal(err) 54 } 55 if !reflect.DeepEqual(resp, Result{"hello", 10, &Args{"world"}}) { 56 t.Errorf("incorrect result %#v", resp) 57 } 58 } 59 60 func TestClientBatchRequest(t *testing.T) { 61 server := newTestServer("service", new(Service)) 62 defer server.Stop() 63 client := DialInProc(server) 64 defer client.Close() 65 66 batch := []BatchElem{ 67 { 68 Method: "service_echo", 69 Args: []interface{}{"hello", 10, &Args{"world"}}, 70 Result: new(Result), 71 }, 72 { 73 Method: "service_echo", 74 Args: []interface{}{"hello2", 11, &Args{"world"}}, 75 Result: new(Result), 76 }, 77 { 78 Method: "no_such_method", 79 Args: []interface{}{1, 2, 3}, 80 Result: new(int), 81 }, 82 } 83 if err := client.BatchCall(batch); err != nil { 84 t.Fatal(err) 85 } 86 wantResult := []BatchElem{ 87 { 88 Method: "service_echo", 89 Args: []interface{}{"hello", 10, &Args{"world"}}, 90 Result: &Result{"hello", 10, &Args{"world"}}, 91 }, 92 { 93 Method: "service_echo", 94 Args: []interface{}{"hello2", 11, &Args{"world"}}, 95 Result: &Result{"hello2", 11, &Args{"world"}}, 96 }, 97 { 98 Method: "no_such_method", 99 Args: []interface{}{1, 2, 3}, 100 Result: new(int), 101 Error: &jsonError{Code: -32601, Message: "The method no_such_method_ does not exist/is not available"}, 102 }, 103 } 104 if !reflect.DeepEqual(batch, wantResult) { 105 t.Errorf("batch results mismatch:\ngot %swant %s", spew.Sdump(batch), spew.Sdump(wantResult)) 106 } 107 } 108 109 //func testclientcancel inproc(t*testing.t)testclientcancel(“inproc”,t) 110 func TestClientCancelWebsocket(t *testing.T) { testClientCancel("ws", t) } 111 func TestClientCancelHTTP(t *testing.T) { testClientCancel("http", t) } 112 func TestClientCancelIPC(t *testing.T) { testClientCancel("ipc", t) } 113 114 //此测试检查通过callContext发出的请求是否可以通过取消来取消 115 //语境。 116 func testClientCancel(transport string, t *testing.T) { 117 server := newTestServer("service", new(Service)) 118 defer server.Stop() 119 120 //我们想要实现的是取消上下文 121 //在请求处理的各个阶段。有趣的案例 122 //是: 123 //-拨号时取消 124 //-执行HTTP请求时取消 125 //-等待响应时取消 126 // 127 //为了触发这些,时间的选择使得连接 128 //在每个其他呼叫的截止时间内终止(maxkillTimeout 129 //是2x maxCancelTimeout)。 130 // 131 //一旦连接断开,很有可能无法连接 132 //成功,因为接受延迟了1秒。 133 maxContextCancelTimeout := 300 * time.Millisecond 134 fl := &flakeyListener{ 135 maxAcceptDelay: 1 * time.Second, 136 maxKillTimeout: 600 * time.Millisecond, 137 } 138 139 var client *Client 140 switch transport { 141 case "ws", "http": 142 c, hs := httpTestClient(server, transport, fl) 143 defer hs.Close() 144 client = c 145 case "ipc": 146 c, l := ipcTestClient(server, fl) 147 defer l.Close() 148 client = c 149 default: 150 panic("unknown transport: " + transport) 151 } 152 153 //这些测试需要很多时间,一次运行它们。 154 //您可能希望使用-parallel 1或comment out运行 155 //如果启用日志记录,则调用T.Parallel。 156 t.Parallel() 157 158 //实际测试从这里开始。 159 var ( 160 wg sync.WaitGroup 161 nreqs = 10 162 ncallers = 6 163 ) 164 caller := func(index int) { 165 defer wg.Done() 166 for i := 0; i < nreqs; i++ { 167 var ( 168 ctx context.Context 169 cancel func() 170 timeout = time.Duration(rand.Int63n(int64(maxContextCancelTimeout))) 171 ) 172 if index < ncallers/2 { 173 //对于一半的调用者,创建一个没有截止日期的上下文 174 //以后再取消。 175 ctx, cancel = context.WithCancel(context.Background()) 176 time.AfterFunc(timeout, cancel) 177 } else { 178 //对于另一半,创建一个带有截止日期的上下文。这是 179 //不同,因为上下文期限用于设置套接字写入 180 //截止日期。 181 ctx, cancel = context.WithTimeout(context.Background(), timeout) 182 } 183 //现在使用上下文执行调用。 184 //这里的关键是没有一个呼叫能成功完成。 185 err := client.CallContext(ctx, nil, "service_sleep", 2*maxContextCancelTimeout) 186 if err != nil { 187 log.Debug(fmt.Sprint("got expected error:", err)) 188 } else { 189 t.Errorf("no error for call with %v wait time", timeout) 190 } 191 cancel() 192 } 193 } 194 wg.Add(ncallers) 195 for i := 0; i < ncallers; i++ { 196 go caller(i) 197 } 198 wg.Wait() 199 } 200 201 func TestClientSubscribeInvalidArg(t *testing.T) { 202 server := newTestServer("service", new(Service)) 203 defer server.Stop() 204 client := DialInProc(server) 205 defer client.Close() 206 207 check := func(shouldPanic bool, arg interface{}) { 208 defer func() { 209 err := recover() 210 if shouldPanic && err == nil { 211 t.Errorf("EthSubscribe should've panicked for %#v", arg) 212 } 213 if !shouldPanic && err != nil { 214 t.Errorf("EthSubscribe shouldn't have panicked for %#v", arg) 215 buf := make([]byte, 1024*1024) 216 buf = buf[:runtime.Stack(buf, false)] 217 t.Error(err) 218 t.Error(string(buf)) 219 } 220 }() 221 client.EthSubscribe(context.Background(), arg, "foo_bar") 222 } 223 check(true, nil) 224 check(true, 1) 225 check(true, (chan int)(nil)) 226 check(true, make(<-chan int)) 227 check(false, make(chan int)) 228 check(false, make(chan<- int)) 229 } 230 231 func TestClientSubscribe(t *testing.T) { 232 server := newTestServer("eth", new(NotificationTestService)) 233 defer server.Stop() 234 client := DialInProc(server) 235 defer client.Close() 236 237 nc := make(chan int) 238 count := 10 239 sub, err := client.EthSubscribe(context.Background(), nc, "someSubscription", count, 0) 240 if err != nil { 241 t.Fatal("can't subscribe:", err) 242 } 243 for i := 0; i < count; i++ { 244 if val := <-nc; val != i { 245 t.Fatalf("value mismatch: got %d, want %d", val, i) 246 } 247 } 248 249 sub.Unsubscribe() 250 select { 251 case v := <-nc: 252 t.Fatal("received value after unsubscribe:", v) 253 case err := <-sub.Err(): 254 if err != nil { 255 t.Fatalf("Err returned a non-nil error after explicit unsubscribe: %q", err) 256 } 257 case <-time.After(1 * time.Second): 258 t.Fatalf("subscription not closed within 1s after unsubscribe") 259 } 260 } 261 262 func TestClientSubscribeCustomNamespace(t *testing.T) { 263 namespace := "custom" 264 server := newTestServer(namespace, new(NotificationTestService)) 265 defer server.Stop() 266 client := DialInProc(server) 267 defer client.Close() 268 269 nc := make(chan int) 270 count := 10 271 sub, err := client.Subscribe(context.Background(), namespace, nc, "someSubscription", count, 0) 272 if err != nil { 273 t.Fatal("can't subscribe:", err) 274 } 275 for i := 0; i < count; i++ { 276 if val := <-nc; val != i { 277 t.Fatalf("value mismatch: got %d, want %d", val, i) 278 } 279 } 280 281 sub.Unsubscribe() 282 select { 283 case v := <-nc: 284 t.Fatal("received value after unsubscribe:", v) 285 case err := <-sub.Err(): 286 if err != nil { 287 t.Fatalf("Err returned a non-nil error after explicit unsubscribe: %q", err) 288 } 289 case <-time.After(1 * time.Second): 290 t.Fatalf("subscription not closed within 1s after unsubscribe") 291 } 292 } 293 294 //在这个测试中,当ethsubscribe 295 //正在等待响应。 296 func TestClientSubscribeClose(t *testing.T) { 297 service := &NotificationTestService{ 298 gotHangSubscriptionReq: make(chan struct{}), 299 unblockHangSubscription: make(chan struct{}), 300 } 301 server := newTestServer("eth", service) 302 defer server.Stop() 303 client := DialInProc(server) 304 defer client.Close() 305 306 var ( 307 nc = make(chan int) 308 errc = make(chan error) 309 sub *ClientSubscription 310 err error 311 ) 312 go func() { 313 sub, err = client.EthSubscribe(context.Background(), nc, "hangSubscription", 999) 314 errc <- err 315 }() 316 317 <-service.gotHangSubscriptionReq 318 client.Close() 319 service.unblockHangSubscription <- struct{}{} 320 321 select { 322 case err := <-errc: 323 if err == nil { 324 t.Errorf("EthSubscribe returned nil error after Close") 325 } 326 if sub != nil { 327 t.Error("EthSubscribe returned non-nil subscription after Close") 328 } 329 case <-time.After(1 * time.Second): 330 t.Fatalf("EthSubscribe did not return within 1s after Close") 331 } 332 } 333 334 //此测试检查当单个订阅服务器 335 //不读取订阅事件。 336 func TestClientNotificationStorm(t *testing.T) { 337 server := newTestServer("eth", new(NotificationTestService)) 338 defer server.Stop() 339 340 doTest := func(count int, wantError bool) { 341 client := DialInProc(server) 342 defer client.Close() 343 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 344 defer cancel() 345 346 //订阅服务器。它将开始发送许多通知 347 //很快。 348 nc := make(chan int) 349 sub, err := client.EthSubscribe(ctx, nc, "someSubscription", count, 0) 350 if err != nil { 351 t.Fatal("can't subscribe:", err) 352 } 353 defer sub.Unsubscribe() 354 355 //处理每个通知,尝试在它们之间运行一个调用。 356 for i := 0; i < count; i++ { 357 select { 358 case val := <-nc: 359 if val != i { 360 t.Fatalf("(%d/%d) unexpected value %d", i, count, val) 361 } 362 case err := <-sub.Err(): 363 if wantError && err != ErrSubscriptionQueueOverflow { 364 t.Fatalf("(%d/%d) got error %q, want %q", i, count, err, ErrSubscriptionQueueOverflow) 365 } else if !wantError { 366 t.Fatalf("(%d/%d) got unexpected error %q", i, count, err) 367 } 368 return 369 } 370 var r int 371 err := client.CallContext(ctx, &r, "eth_echo", i) 372 if err != nil { 373 if !wantError { 374 t.Fatalf("(%d/%d) call error: %v", i, count, err) 375 } 376 return 377 } 378 } 379 } 380 381 doTest(8000, false) 382 doTest(10000, true) 383 } 384 385 func TestClientHTTP(t *testing.T) { 386 server := newTestServer("service", new(Service)) 387 defer server.Stop() 388 389 client, hs := httpTestClient(server, "http", nil) 390 defer hs.Close() 391 defer client.Close() 392 393 //启动并发请求。 394 var ( 395 results = make([]Result, 100) 396 errc = make(chan error) 397 wantResult = Result{"a", 1, new(Args)} 398 ) 399 defer client.Close() 400 for i := range results { 401 i := i 402 go func() { 403 errc <- client.Call(&results[i], "service_echo", 404 wantResult.String, wantResult.Int, wantResult.Args) 405 }() 406 } 407 408 //等待所有任务完成。 409 timeout := time.NewTimer(5 * time.Second) 410 defer timeout.Stop() 411 for i := range results { 412 select { 413 case err := <-errc: 414 if err != nil { 415 t.Fatal(err) 416 } 417 case <-timeout.C: 418 t.Fatalf("timeout (got %d/%d) results)", i+1, len(results)) 419 } 420 } 421 422 //检查结果。 423 for i := range results { 424 if !reflect.DeepEqual(results[i], wantResult) { 425 t.Errorf("result %d mismatch: got %#v, want %#v", i, results[i], wantResult) 426 } 427 } 428 } 429 430 func TestClientReconnect(t *testing.T) { 431 startServer := func(addr string) (*Server, net.Listener) { 432 srv := newTestServer("service", new(Service)) 433 l, err := net.Listen("tcp", addr) 434 if err != nil { 435 t.Fatal(err) 436 } 437 go http.Serve(l, srv.WebsocketHandler([]string{"*"})) 438 return srv, l 439 } 440 441 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 442 defer cancel() 443 444 //启动服务器和相应的客户机。 445 s1, l1 := startServer("127.0.0.1:0") 446 client, err := DialContext(ctx, "ws://“+l1.addr().string()) 447 if err != nil { 448 t.Fatal("can't dial", err) 449 } 450 451 //打个电话。这应该可以工作,因为服务器已启动。 452 var resp Result 453 if err := client.CallContext(ctx, &resp, "service_echo", "", 1, nil); err != nil { 454 t.Fatal(err) 455 } 456 457 //关闭服务器,然后再次尝试呼叫。它不应该起作用。 458 l1.Close() 459 s1.Stop() 460 if err := client.CallContext(ctx, &resp, "service_echo", "", 2, nil); err == nil { 461 t.Error("successful call while the server is down") 462 t.Logf("resp: %#v", resp) 463 } 464 465 //留出一些冷却时间,以便我们可以再次收听相同的地址。 466 time.Sleep(2 * time.Second) 467 468 //重新启动然后再打电话。应重新建立连接。 469 //我们在这里生成多个调用来检查这个是否以某种方式挂起。 470 s2, l2 := startServer(l1.Addr().String()) 471 defer l2.Close() 472 defer s2.Stop() 473 474 start := make(chan struct{}) 475 errors := make(chan error, 20) 476 for i := 0; i < cap(errors); i++ { 477 go func() { 478 <-start 479 var resp Result 480 errors <- client.CallContext(ctx, &resp, "service_echo", "", 3, nil) 481 }() 482 } 483 close(start) 484 errcount := 0 485 for i := 0; i < cap(errors); i++ { 486 if err = <-errors; err != nil { 487 errcount++ 488 } 489 } 490 t.Log("err:", err) 491 if errcount > 1 { 492 t.Errorf("expected one error after disconnect, got %d", errcount) 493 } 494 } 495 496 func newTestServer(serviceName string, service interface{}) *Server { 497 server := NewServer() 498 if err := server.RegisterName(serviceName, service); err != nil { 499 panic(err) 500 } 501 return server 502 } 503 504 func httpTestClient(srv *Server, transport string, fl *flakeyListener) (*Client, *httptest.Server) { 505 //创建HTTP服务器。 506 var hs *httptest.Server 507 switch transport { 508 case "ws": 509 hs = httptest.NewUnstartedServer(srv.WebsocketHandler([]string{"*"})) 510 case "http": 511 hs = httptest.NewUnstartedServer(srv) 512 default: 513 panic("unknown HTTP transport: " + transport) 514 } 515 //根据需要包装侦听器。 516 if fl != nil { 517 fl.Listener = hs.Listener 518 hs.Listener = fl 519 } 520 //连接客户端。 521 hs.Start() 522 client, err := Dial(transport + "://“+hs.listener.addr().string()) 523 if err != nil { 524 panic(err) 525 } 526 return client, hs 527 } 528 529 func ipcTestClient(srv *Server, fl *flakeyListener) (*Client, net.Listener) { 530 //在随机端点上侦听。 531 endpoint := fmt.Sprintf("go-ethereum-test-ipc-%d-%d", os.Getpid(), rand.Int63()) 532 if runtime.GOOS == "windows" { 533 endpoint = `\\.\pipe\` + endpoint 534 } else { 535 endpoint = os.TempDir() + "/" + endpoint 536 } 537 l, err := ipcListen(endpoint) 538 if err != nil { 539 panic(err) 540 } 541 //将侦听器连接到服务器。 542 if fl != nil { 543 fl.Listener = l 544 l = fl 545 } 546 go srv.ServeListener(l) 547 //连接客户端。 548 client, err := Dial(endpoint) 549 if err != nil { 550 panic(err) 551 } 552 return client, l 553 } 554 555 //flakeylistener在随机超时后终止接受的连接。 556 type flakeyListener struct { 557 net.Listener 558 maxKillTimeout time.Duration 559 maxAcceptDelay time.Duration 560 } 561 562 func (l *flakeyListener) Accept() (net.Conn, error) { 563 delay := time.Duration(rand.Int63n(int64(l.maxAcceptDelay))) 564 time.Sleep(delay) 565 566 c, err := l.Listener.Accept() 567 if err == nil { 568 timeout := time.Duration(rand.Int63n(int64(l.maxKillTimeout))) 569 time.AfterFunc(timeout, func() { 570 log.Debug(fmt.Sprintf("killing conn %v after %v", c.LocalAddr(), timeout)) 571 c.Close() 572 }) 573 } 574 return c, err 575 }