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  }