github.com/bcnmy/go-ethereum@v1.10.27/rpc/testservice_test.go (about)

     1  // Copyright 2019 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/binary"
    22  	"errors"
    23  	"strings"
    24  	"sync"
    25  	"time"
    26  )
    27  
    28  func newTestServer() *Server {
    29  	server := NewServer()
    30  	server.idgen = sequentialIDGenerator()
    31  	if err := server.RegisterName("test", new(testService)); err != nil {
    32  		panic(err)
    33  	}
    34  	if err := server.RegisterName("nftest", new(notificationTestService)); err != nil {
    35  		panic(err)
    36  	}
    37  	return server
    38  }
    39  
    40  func sequentialIDGenerator() func() ID {
    41  	var (
    42  		mu      sync.Mutex
    43  		counter uint64
    44  	)
    45  	return func() ID {
    46  		mu.Lock()
    47  		defer mu.Unlock()
    48  		counter++
    49  		id := make([]byte, 8)
    50  		binary.BigEndian.PutUint64(id, counter)
    51  		return encodeID(id)
    52  	}
    53  }
    54  
    55  type testService struct{}
    56  
    57  type echoArgs struct {
    58  	S string
    59  }
    60  
    61  type echoResult struct {
    62  	String string
    63  	Int    int
    64  	Args   *echoArgs
    65  }
    66  
    67  type testError struct{}
    68  
    69  func (testError) Error() string          { return "testError" }
    70  func (testError) ErrorCode() int         { return 444 }
    71  func (testError) ErrorData() interface{} { return "testError data" }
    72  
    73  func (s *testService) NoArgsRets() {}
    74  
    75  func (s *testService) Echo(str string, i int, args *echoArgs) echoResult {
    76  	return echoResult{str, i, args}
    77  }
    78  
    79  func (s *testService) EchoWithCtx(ctx context.Context, str string, i int, args *echoArgs) echoResult {
    80  	return echoResult{str, i, args}
    81  }
    82  
    83  func (s *testService) PeerInfo(ctx context.Context) PeerInfo {
    84  	return PeerInfoFromContext(ctx)
    85  }
    86  
    87  func (s *testService) Sleep(ctx context.Context, duration time.Duration) {
    88  	time.Sleep(duration)
    89  }
    90  
    91  func (s *testService) Block(ctx context.Context) error {
    92  	<-ctx.Done()
    93  	return errors.New("context canceled in testservice_block")
    94  }
    95  
    96  func (s *testService) Rets() (string, error) {
    97  	return "", nil
    98  }
    99  
   100  //lint:ignore ST1008 returns error first on purpose.
   101  func (s *testService) InvalidRets1() (error, string) {
   102  	return nil, ""
   103  }
   104  
   105  func (s *testService) InvalidRets2() (string, string) {
   106  	return "", ""
   107  }
   108  
   109  func (s *testService) InvalidRets3() (string, string, error) {
   110  	return "", "", nil
   111  }
   112  
   113  func (s *testService) ReturnError() error {
   114  	return testError{}
   115  }
   116  
   117  func (s *testService) CallMeBack(ctx context.Context, method string, args []interface{}) (interface{}, error) {
   118  	c, ok := ClientFromContext(ctx)
   119  	if !ok {
   120  		return nil, errors.New("no client")
   121  	}
   122  	var result interface{}
   123  	err := c.Call(&result, method, args...)
   124  	return result, err
   125  }
   126  
   127  func (s *testService) CallMeBackLater(ctx context.Context, method string, args []interface{}) error {
   128  	c, ok := ClientFromContext(ctx)
   129  	if !ok {
   130  		return errors.New("no client")
   131  	}
   132  	go func() {
   133  		<-ctx.Done()
   134  		var result interface{}
   135  		c.Call(&result, method, args...)
   136  	}()
   137  	return nil
   138  }
   139  
   140  func (s *testService) Subscription(ctx context.Context) (*Subscription, error) {
   141  	return nil, nil
   142  }
   143  
   144  type notificationTestService struct {
   145  	unsubscribed            chan string
   146  	gotHangSubscriptionReq  chan struct{}
   147  	unblockHangSubscription chan struct{}
   148  }
   149  
   150  func (s *notificationTestService) Echo(i int) int {
   151  	return i
   152  }
   153  
   154  func (s *notificationTestService) Unsubscribe(subid string) {
   155  	if s.unsubscribed != nil {
   156  		s.unsubscribed <- subid
   157  	}
   158  }
   159  
   160  func (s *notificationTestService) SomeSubscription(ctx context.Context, n, val int) (*Subscription, error) {
   161  	notifier, supported := NotifierFromContext(ctx)
   162  	if !supported {
   163  		return nil, ErrNotificationsUnsupported
   164  	}
   165  
   166  	// By explicitly creating an subscription we make sure that the subscription id is send
   167  	// back to the client before the first subscription.Notify is called. Otherwise the
   168  	// events might be send before the response for the *_subscribe method.
   169  	subscription := notifier.CreateSubscription()
   170  	go func() {
   171  		for i := 0; i < n; i++ {
   172  			if err := notifier.Notify(subscription.ID, val+i); err != nil {
   173  				return
   174  			}
   175  		}
   176  		select {
   177  		case <-notifier.Closed():
   178  		case <-subscription.Err():
   179  		}
   180  		if s.unsubscribed != nil {
   181  			s.unsubscribed <- string(subscription.ID)
   182  		}
   183  	}()
   184  	return subscription, nil
   185  }
   186  
   187  // HangSubscription blocks on s.unblockHangSubscription before sending anything.
   188  func (s *notificationTestService) HangSubscription(ctx context.Context, val int) (*Subscription, error) {
   189  	notifier, supported := NotifierFromContext(ctx)
   190  	if !supported {
   191  		return nil, ErrNotificationsUnsupported
   192  	}
   193  	s.gotHangSubscriptionReq <- struct{}{}
   194  	<-s.unblockHangSubscription
   195  	subscription := notifier.CreateSubscription()
   196  
   197  	go func() {
   198  		notifier.Notify(subscription.ID, val)
   199  	}()
   200  	return subscription, nil
   201  }
   202  
   203  // largeRespService generates arbitrary-size JSON responses.
   204  type largeRespService struct {
   205  	length int
   206  }
   207  
   208  func (x largeRespService) LargeResp() string {
   209  	return strings.Repeat("x", x.length)
   210  }