github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/rpc/subscription_test.go (about)

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