github.com/simplechain-org/go-simplechain@v1.0.6/rpc/testservice_test.go (about) 1 // Copyright 2019 The go-simplechain Authors 2 // This file is part of the go-simplechain library. 3 // 4 // The go-simplechain 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-simplechain 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-simplechain 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 func (s *testService) NoArgsRets() {} 67 68 func (s *testService) Echo(str string, i int, args *echoArgs) echoResult { 69 return echoResult{str, i, args} 70 } 71 72 func (s *testService) EchoWithCtx(ctx context.Context, str string, i int, args *echoArgs) echoResult { 73 return echoResult{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 //lint:ignore ST1008 returns error first on purpose. 85 func (s *testService) InvalidRets1() (error, string) { 86 return nil, "" 87 } 88 89 func (s *testService) InvalidRets2() (string, string) { 90 return "", "" 91 } 92 93 func (s *testService) InvalidRets3() (string, string, error) { 94 return "", "", nil 95 } 96 97 func (s *testService) CallMeBack(ctx context.Context, method string, args []interface{}) (interface{}, error) { 98 c, ok := ClientFromContext(ctx) 99 if !ok { 100 return nil, errors.New("no client") 101 } 102 var result interface{} 103 err := c.Call(&result, method, args...) 104 return result, err 105 } 106 107 func (s *testService) CallMeBackLater(ctx context.Context, method string, args []interface{}) error { 108 c, ok := ClientFromContext(ctx) 109 if !ok { 110 return errors.New("no client") 111 } 112 go func() { 113 <-ctx.Done() 114 var result interface{} 115 c.Call(&result, method, args...) 116 }() 117 return nil 118 } 119 120 func (s *testService) Subscription(ctx context.Context) (*Subscription, error) { 121 return nil, nil 122 } 123 124 type notificationTestService struct { 125 unsubscribed chan string 126 gotHangSubscriptionReq chan struct{} 127 unblockHangSubscription chan struct{} 128 } 129 130 func (s *notificationTestService) Echo(i int) int { 131 return i 132 } 133 134 func (s *notificationTestService) Unsubscribe(subid string) { 135 if s.unsubscribed != nil { 136 s.unsubscribed <- subid 137 } 138 } 139 140 func (s *notificationTestService) SomeSubscription(ctx context.Context, n, val int) (*Subscription, error) { 141 notifier, supported := NotifierFromContext(ctx) 142 if !supported { 143 return nil, ErrNotificationsUnsupported 144 } 145 146 // By explicitly creating an subscription we make sure that the subscription id is send 147 // back to the client before the first subscription.Notify is called. Otherwise the 148 // events might be send before the response for the *_subscribe method. 149 subscription := notifier.CreateSubscription() 150 go func() { 151 for i := 0; i < n; i++ { 152 if err := notifier.Notify(subscription.ID, val+i); err != nil { 153 return 154 } 155 } 156 select { 157 case <-notifier.Closed(): 158 case <-subscription.Err(): 159 } 160 if s.unsubscribed != nil { 161 s.unsubscribed <- string(subscription.ID) 162 } 163 }() 164 return subscription, nil 165 } 166 167 // HangSubscription blocks on s.unblockHangSubscription before sending anything. 168 func (s *notificationTestService) HangSubscription(ctx context.Context, val int) (*Subscription, error) { 169 notifier, supported := NotifierFromContext(ctx) 170 if !supported { 171 return nil, ErrNotificationsUnsupported 172 } 173 s.gotHangSubscriptionReq <- struct{}{} 174 <-s.unblockHangSubscription 175 subscription := notifier.CreateSubscription() 176 177 go func() { 178 notifier.Notify(subscription.ID, val) 179 }() 180 return subscription, nil 181 }