github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/rpc/subscription_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  	"encoding/json"
    30  	"fmt"
    31  	"net"
    32  	"sync"
    33  	"testing"
    34  	"time"
    35  )
    36  
    37  type NotificationTestService struct {
    38  	mu           sync.Mutex
    39  	unsubscribed bool
    40  
    41  	gotHangSubscriptionReq  chan struct{}
    42  	unblockHangSubscription chan struct{}
    43  }
    44  
    45  func (s *NotificationTestService) Echo(i int) int {
    46  	return i
    47  }
    48  
    49  func (s *NotificationTestService) wasUnsubCallbackCalled() bool {
    50  	s.mu.Lock()
    51  	defer s.mu.Unlock()
    52  	return s.unsubscribed
    53  }
    54  
    55  func (s *NotificationTestService) Unsubscribe(subid string) {
    56  	s.mu.Lock()
    57  	s.unsubscribed = true
    58  	s.mu.Unlock()
    59  }
    60  
    61  func (s *NotificationTestService) SomeSubscription(ctx context.Context, n, val int) (*Subscription, error) {
    62  	notifier, supported := NotifierFromContext(ctx)
    63  	if !supported {
    64  		return nil, ErrNotificationsUnsupported
    65  	}
    66  
    67  //通过显式创建订阅,我们确保将订阅ID发送回客户端
    68  //在第一次订阅之前。调用notify。否则,事件可能会在响应之前发送
    69  //对于eth-subscribe方法。
    70  	subscription := notifier.CreateSubscription()
    71  
    72  	go func() {
    73  //测试需要n个事件,如果我们立即开始发送事件,则某些事件
    74  //可能会删除,因为订阅ID可能不会发送到
    75  //客户。
    76  		time.Sleep(5 * time.Second)
    77  		for i := 0; i < n; i++ {
    78  			if err := notifier.Notify(subscription.ID, val+i); err != nil {
    79  				return
    80  			}
    81  		}
    82  
    83  		select {
    84  		case <-notifier.Closed():
    85  			s.mu.Lock()
    86  			s.unsubscribed = true
    87  			s.mu.Unlock()
    88  		case <-subscription.Err():
    89  			s.mu.Lock()
    90  			s.unsubscribed = true
    91  			s.mu.Unlock()
    92  		}
    93  	}()
    94  
    95  	return subscription, nil
    96  }
    97  
    98  //在s.unblockhangsubscription上挂起订阅块
    99  //发送任何东西。
   100  func (s *NotificationTestService) HangSubscription(ctx context.Context, val int) (*Subscription, error) {
   101  	notifier, supported := NotifierFromContext(ctx)
   102  	if !supported {
   103  		return nil, ErrNotificationsUnsupported
   104  	}
   105  
   106  	s.gotHangSubscriptionReq <- struct{}{}
   107  	<-s.unblockHangSubscription
   108  	subscription := notifier.CreateSubscription()
   109  
   110  	go func() {
   111  		notifier.Notify(subscription.ID, val)
   112  	}()
   113  	return subscription, nil
   114  }
   115  
   116  func TestNotifications(t *testing.T) {
   117  	server := NewServer()
   118  	service := &NotificationTestService{}
   119  
   120  	if err := server.RegisterName("eth", service); err != nil {
   121  		t.Fatalf("unable to register test service %v", err)
   122  	}
   123  
   124  	clientConn, serverConn := net.Pipe()
   125  
   126  	go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions)
   127  
   128  	out := json.NewEncoder(clientConn)
   129  	in := json.NewDecoder(clientConn)
   130  
   131  	n := 5
   132  	val := 12345
   133  	request := map[string]interface{}{
   134  		"id":      1,
   135  		"method":  "eth_subscribe",
   136  		"version": "2.0",
   137  		"params":  []interface{}{"someSubscription", n, val},
   138  	}
   139  
   140  //创建订阅
   141  	if err := out.Encode(request); err != nil {
   142  		t.Fatal(err)
   143  	}
   144  
   145  	var subid string
   146  	response := jsonSuccessResponse{Result: subid}
   147  	if err := in.Decode(&response); err != nil {
   148  		t.Fatal(err)
   149  	}
   150  
   151  	var ok bool
   152  	if _, ok = response.Result.(string); !ok {
   153  		t.Fatalf("expected subscription id, got %T", response.Result)
   154  	}
   155  
   156  	for i := 0; i < n; i++ {
   157  		var notification jsonNotification
   158  		if err := in.Decode(&notification); err != nil {
   159  			t.Fatalf("%v", err)
   160  		}
   161  
   162  		if int(notification.Params.Result.(float64)) != val+i {
   163  			t.Fatalf("expected %d, got %d", val+i, notification.Params.Result)
   164  		}
   165  	}
   166  
   167  clientConn.Close() //导致调用通知取消订阅回调
   168  	time.Sleep(1 * time.Second)
   169  
   170  	if !service.wasUnsubCallbackCalled() {
   171  		t.Error("unsubscribe callback not called after closing connection")
   172  	}
   173  }
   174  
   175  func waitForMessages(t *testing.T, in *json.Decoder, successes chan<- jsonSuccessResponse,
   176  	failures chan<- jsonErrResponse, notifications chan<- jsonNotification, errors chan<- error) {
   177  
   178  //读取和分析服务器消息
   179  	for {
   180  		var rmsg json.RawMessage
   181  		if err := in.Decode(&rmsg); err != nil {
   182  			return
   183  		}
   184  
   185  		var responses []map[string]interface{}
   186  		if rmsg[0] == '[' {
   187  			if err := json.Unmarshal(rmsg, &responses); err != nil {
   188  				errors <- fmt.Errorf("Received invalid message: %s", rmsg)
   189  				return
   190  			}
   191  		} else {
   192  			var msg map[string]interface{}
   193  			if err := json.Unmarshal(rmsg, &msg); err != nil {
   194  				errors <- fmt.Errorf("Received invalid message: %s", rmsg)
   195  				return
   196  			}
   197  			responses = append(responses, msg)
   198  		}
   199  
   200  		for _, msg := range responses {
   201  //确定接收和广播的消息类型
   202  //通过相应的通道
   203  			if _, found := msg["result"]; found {
   204  				successes <- jsonSuccessResponse{
   205  					Version: msg["jsonrpc"].(string),
   206  					Id:      msg["id"],
   207  					Result:  msg["result"],
   208  				}
   209  				continue
   210  			}
   211  			if _, found := msg["error"]; found {
   212  				params := msg["params"].(map[string]interface{})
   213  				failures <- jsonErrResponse{
   214  					Version: msg["jsonrpc"].(string),
   215  					Id:      msg["id"],
   216  					Error:   jsonError{int(params["subscription"].(float64)), params["message"].(string), params["data"]},
   217  				}
   218  				continue
   219  			}
   220  			if _, found := msg["params"]; found {
   221  				params := msg["params"].(map[string]interface{})
   222  				notifications <- jsonNotification{
   223  					Version: msg["jsonrpc"].(string),
   224  					Method:  msg["method"].(string),
   225  					Params:  jsonSubscription{params["subscription"].(string), params["result"]},
   226  				}
   227  				continue
   228  			}
   229  			errors <- fmt.Errorf("Received invalid message: %s", msg)
   230  		}
   231  	}
   232  }
   233  
   234  //testsubscriptionmultiplename空间确保订阅可以存在
   235  //对于多个不同的命名空间。
   236  func TestSubscriptionMultipleNamespaces(t *testing.T) {
   237  	var (
   238  		namespaces             = []string{"eth", "shh", "bzz"}
   239  		server                 = NewServer()
   240  		service                = NotificationTestService{}
   241  		clientConn, serverConn = net.Pipe()
   242  
   243  		out           = json.NewEncoder(clientConn)
   244  		in            = json.NewDecoder(clientConn)
   245  		successes     = make(chan jsonSuccessResponse)
   246  		failures      = make(chan jsonErrResponse)
   247  		notifications = make(chan jsonNotification)
   248  
   249  		errors = make(chan error, 10)
   250  	)
   251  
   252  //安装并启动服务器
   253  	for _, namespace := range namespaces {
   254  		if err := server.RegisterName(namespace, &service); err != nil {
   255  			t.Fatalf("unable to register test service %v", err)
   256  		}
   257  	}
   258  
   259  	go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions)
   260  	defer server.Stop()
   261  
   262  //等待消息并将其写入给定的通道
   263  	go waitForMessages(t, in, successes, failures, notifications, errors)
   264  
   265  //逐个创建订阅
   266  	n := 3
   267  	for i, namespace := range namespaces {
   268  		request := map[string]interface{}{
   269  			"id":      i,
   270  			"method":  fmt.Sprintf("%s_subscribe", namespace),
   271  			"version": "2.0",
   272  			"params":  []interface{}{"someSubscription", n, i},
   273  		}
   274  
   275  		if err := out.Encode(&request); err != nil {
   276  			t.Fatalf("Could not create subscription: %v", err)
   277  		}
   278  	}
   279  
   280  //在一批中创建所有订阅
   281  	var requests []interface{}
   282  	for i, namespace := range namespaces {
   283  		requests = append(requests, map[string]interface{}{
   284  			"id":      i,
   285  			"method":  fmt.Sprintf("%s_subscribe", namespace),
   286  			"version": "2.0",
   287  			"params":  []interface{}{"someSubscription", n, i},
   288  		})
   289  	}
   290  
   291  	if err := out.Encode(&requests); err != nil {
   292  		t.Fatalf("Could not create subscription in batch form: %v", err)
   293  	}
   294  
   295  	timeout := time.After(30 * time.Second)
   296  	subids := make(map[string]string, 2*len(namespaces))
   297  	count := make(map[string]int, 2*len(namespaces))
   298  
   299  	for {
   300  		done := true
   301  		for id := range count {
   302  			if count, found := count[id]; !found || count < (2*n) {
   303  				done = false
   304  			}
   305  		}
   306  
   307  		if done && len(count) == len(namespaces) {
   308  			break
   309  		}
   310  
   311  		select {
   312  		case err := <-errors:
   313  			t.Fatal(err)
   314  case suc := <-successes: //已创建订阅
   315  			subids[namespaces[int(suc.Id.(float64))]] = suc.Result.(string)
   316  		case failure := <-failures:
   317  			t.Errorf("received error: %v", failure.Error)
   318  		case notification := <-notifications:
   319  			if cnt, found := count[notification.Params.Subscription]; found {
   320  				count[notification.Params.Subscription] = cnt + 1
   321  			} else {
   322  				count[notification.Params.Subscription] = 1
   323  			}
   324  		case <-timeout:
   325  			for _, namespace := range namespaces {
   326  				subid, found := subids[namespace]
   327  				if !found {
   328  					t.Errorf("Subscription for '%s' not created", namespace)
   329  					continue
   330  				}
   331  				if count, found := count[subid]; !found || count < n {
   332  					t.Errorf("Didn't receive all notifications (%d<%d) in time for namespace '%s'", count, n, namespace)
   333  				}
   334  			}
   335  			return
   336  		}
   337  	}
   338  }