github.com/snowblossomcoin/go-ethereum@v1.9.25/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 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) Sleep(ctx context.Context, duration time.Duration) { 83 time.Sleep(duration) 84 } 85 86 func (s *testService) Block(ctx context.Context) error { 87 <-ctx.Done() 88 return errors.New("context canceled in testservice_block") 89 } 90 91 func (s *testService) Rets() (string, error) { 92 return "", nil 93 } 94 95 //lint:ignore ST1008 returns error first on purpose. 96 func (s *testService) InvalidRets1() (error, string) { 97 return nil, "" 98 } 99 100 func (s *testService) InvalidRets2() (string, string) { 101 return "", "" 102 } 103 104 func (s *testService) InvalidRets3() (string, string, error) { 105 return "", "", nil 106 } 107 108 func (s *testService) ReturnError() error { 109 return testError{} 110 } 111 112 func (s *testService) CallMeBack(ctx context.Context, method string, args []interface{}) (interface{}, error) { 113 c, ok := ClientFromContext(ctx) 114 if !ok { 115 return nil, errors.New("no client") 116 } 117 var result interface{} 118 err := c.Call(&result, method, args...) 119 return result, err 120 } 121 122 func (s *testService) CallMeBackLater(ctx context.Context, method string, args []interface{}) error { 123 c, ok := ClientFromContext(ctx) 124 if !ok { 125 return errors.New("no client") 126 } 127 go func() { 128 <-ctx.Done() 129 var result interface{} 130 c.Call(&result, method, args...) 131 }() 132 return nil 133 } 134 135 func (s *testService) Subscription(ctx context.Context) (*Subscription, error) { 136 return nil, nil 137 } 138 139 type notificationTestService struct { 140 unsubscribed chan string 141 gotHangSubscriptionReq chan struct{} 142 unblockHangSubscription chan struct{} 143 } 144 145 func (s *notificationTestService) Echo(i int) int { 146 return i 147 } 148 149 func (s *notificationTestService) Unsubscribe(subid string) { 150 if s.unsubscribed != nil { 151 s.unsubscribed <- subid 152 } 153 } 154 155 func (s *notificationTestService) SomeSubscription(ctx context.Context, n, val int) (*Subscription, error) { 156 notifier, supported := NotifierFromContext(ctx) 157 if !supported { 158 return nil, ErrNotificationsUnsupported 159 } 160 161 // By explicitly creating an subscription we make sure that the subscription id is send 162 // back to the client before the first subscription.Notify is called. Otherwise the 163 // events might be send before the response for the *_subscribe method. 164 subscription := notifier.CreateSubscription() 165 go func() { 166 for i := 0; i < n; i++ { 167 if err := notifier.Notify(subscription.ID, val+i); err != nil { 168 return 169 } 170 } 171 select { 172 case <-notifier.Closed(): 173 case <-subscription.Err(): 174 } 175 if s.unsubscribed != nil { 176 s.unsubscribed <- string(subscription.ID) 177 } 178 }() 179 return subscription, nil 180 } 181 182 // HangSubscription blocks on s.unblockHangSubscription before sending anything. 183 func (s *notificationTestService) HangSubscription(ctx context.Context, val int) (*Subscription, error) { 184 notifier, supported := NotifierFromContext(ctx) 185 if !supported { 186 return nil, ErrNotificationsUnsupported 187 } 188 s.gotHangSubscriptionReq <- struct{}{} 189 <-s.unblockHangSubscription 190 subscription := notifier.CreateSubscription() 191 192 go func() { 193 notifier.Notify(subscription.ID, val) 194 }() 195 return subscription, nil 196 }