github.com/flashbots/go-ethereum@v1.9.7/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 "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 Args struct { 57 S string 58 } 59 60 type Result struct { 61 String string 62 Int int 63 Args *Args 64 } 65 66 func (s *testService) NoArgsRets() {} 67 68 func (s *testService) Echo(str string, i int, args *Args) Result { 69 return Result{str, i, args} 70 } 71 72 func (s *testService) EchoWithCtx(ctx context.Context, str string, i int, args *Args) Result { 73 return Result{str, i, args} 74 } 75 76 func (s *testService) Sleep(ctx context.Context, duration time.Duration) { 77 time.Sleep(duration) 78 } 79 80 func (s *testService) Rets() (string, error) { 81 return "", nil 82 } 83 84 func (s *testService) InvalidRets1() (error, string) { 85 return nil, "" 86 } 87 88 func (s *testService) InvalidRets2() (string, string) { 89 return "", "" 90 } 91 92 func (s *testService) InvalidRets3() (string, string, error) { 93 return "", "", nil 94 } 95 96 func (s *testService) CallMeBack(ctx context.Context, method string, args []interface{}) (interface{}, error) { 97 c, ok := ClientFromContext(ctx) 98 if !ok { 99 return nil, errors.New("no client") 100 } 101 var result interface{} 102 err := c.Call(&result, method, args...) 103 return result, err 104 } 105 106 func (s *testService) CallMeBackLater(ctx context.Context, method string, args []interface{}) error { 107 c, ok := ClientFromContext(ctx) 108 if !ok { 109 return errors.New("no client") 110 } 111 go func() { 112 <-ctx.Done() 113 var result interface{} 114 c.Call(&result, method, args...) 115 }() 116 return nil 117 } 118 119 func (s *testService) Subscription(ctx context.Context) (*Subscription, error) { 120 return nil, nil 121 } 122 123 type notificationTestService struct { 124 unsubscribed chan string 125 gotHangSubscriptionReq chan struct{} 126 unblockHangSubscription chan struct{} 127 } 128 129 func (s *notificationTestService) Echo(i int) int { 130 return i 131 } 132 133 func (s *notificationTestService) Unsubscribe(subid string) { 134 if s.unsubscribed != nil { 135 s.unsubscribed <- subid 136 } 137 } 138 139 func (s *notificationTestService) SomeSubscription(ctx context.Context, n, val int) (*Subscription, error) { 140 notifier, supported := NotifierFromContext(ctx) 141 if !supported { 142 return nil, ErrNotificationsUnsupported 143 } 144 145 // By explicitly creating an subscription we make sure that the subscription id is send 146 // back to the client before the first subscription.Notify is called. Otherwise the 147 // events might be send before the response for the *_subscribe method. 148 subscription := notifier.CreateSubscription() 149 go func() { 150 for i := 0; i < n; i++ { 151 if err := notifier.Notify(subscription.ID, val+i); err != nil { 152 return 153 } 154 } 155 select { 156 case <-notifier.Closed(): 157 case <-subscription.Err(): 158 } 159 if s.unsubscribed != nil { 160 s.unsubscribed <- string(subscription.ID) 161 } 162 }() 163 return subscription, nil 164 } 165 166 // HangSubscription blocks on s.unblockHangSubscription before sending anything. 167 func (s *notificationTestService) HangSubscription(ctx context.Context, val int) (*Subscription, error) { 168 notifier, supported := NotifierFromContext(ctx) 169 if !supported { 170 return nil, ErrNotificationsUnsupported 171 } 172 s.gotHangSubscriptionReq <- struct{}{} 173 <-s.unblockHangSubscription 174 subscription := notifier.CreateSubscription() 175 176 go func() { 177 notifier.Notify(subscription.ID, val) 178 }() 179 return subscription, nil 180 }