github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/rpc/notification_test.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package rpc
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"net"
    23  	"testing"
    24  	"time"
    25  )
    26  
    27  type NotificationTestService struct{}
    28  
    29  var (
    30  	unsubCallbackCalled = false
    31  )
    32  
    33  func (s *NotificationTestService) Unsubscribe(subid string) {
    34  	unsubCallbackCalled = true
    35  }
    36  
    37  func (s *NotificationTestService) SomeSubscription(ctx context.Context, n, val int) (Subscription, error) {
    38  	notifier, supported := NotifierFromContext(ctx)
    39  	if !supported {
    40  		return nil, ErrNotificationsUnsupported
    41  	}
    42  
    43  	// by explicitly creating an subscription we make sure that the subscription id is send back to the client
    44  	// before the first subscription.Notify is called. Otherwise the events might be send before the response
    45  	// for the eth_subscribe method.
    46  	subscription, err := notifier.NewSubscription(s.Unsubscribe)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	go func() {
    52  		for i := 0; i < n; i++ {
    53  			if err := subscription.Notify(val + i); err != nil {
    54  				return
    55  			}
    56  		}
    57  	}()
    58  
    59  	return subscription, nil
    60  }
    61  
    62  func TestNotifications(t *testing.T) {
    63  	server := NewServer()
    64  	service := &NotificationTestService{}
    65  
    66  	if err := server.RegisterName("eth", service); err != nil {
    67  		t.Fatalf("unable to register test service %v", err)
    68  	}
    69  
    70  	clientConn, serverConn := net.Pipe()
    71  
    72  	go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions)
    73  
    74  	out := json.NewEncoder(clientConn)
    75  	in := json.NewDecoder(clientConn)
    76  
    77  	n := 5
    78  	val := 12345
    79  	request := map[string]interface{}{
    80  		"id":      1,
    81  		"method":  "eth_subscribe",
    82  		"version": "2.0",
    83  		"params":  []interface{}{"someSubscription", n, val},
    84  	}
    85  
    86  	// create subscription
    87  	if err := out.Encode(request); err != nil {
    88  		t.Fatal(err)
    89  	}
    90  
    91  	var subid string
    92  	response := JSONResponse{Result: subid}
    93  	if err := in.Decode(&response); err != nil {
    94  		t.Fatal(err)
    95  	}
    96  
    97  	var ok bool
    98  	if subid, ok = response.Result.(string); !ok {
    99  		t.Fatalf("expected subscription id, got %T", response.Result)
   100  	}
   101  
   102  	for i := 0; i < n; i++ {
   103  		var notification jsonNotification
   104  		if err := in.Decode(&notification); err != nil {
   105  			t.Fatalf("%v", err)
   106  		}
   107  
   108  		if int(notification.Params.Result.(float64)) != val+i {
   109  			t.Fatalf("expected %d, got %d", val+i, notification.Params.Result)
   110  		}
   111  	}
   112  
   113  	clientConn.Close() // causes notification unsubscribe callback to be called
   114  	time.Sleep(1 * time.Second)
   115  
   116  	if !unsubCallbackCalled {
   117  		t.Error("unsubscribe callback not called after closing connection")
   118  	}
   119  }