github.com/core-coin/go-core/v2@v2.1.9/rpc/testservice_test.go (about)

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