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 }