decred.org/dcrdex@v1.0.5/tatanka/tatanka_test.go (about) 1 package tatanka 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "fmt" 8 "testing" 9 "time" 10 11 "decred.org/dcrdex/dex" 12 "decred.org/dcrdex/dex/encode" 13 "decred.org/dcrdex/dex/msgjson" 14 "decred.org/dcrdex/tatanka/mj" 15 "decred.org/dcrdex/tatanka/tanka" 16 "github.com/decred/dcrd/dcrec/secp256k1/v4" 17 ) 18 19 type tSender struct { 20 id tanka.PeerID 21 disconnected bool 22 responseErr error 23 responses []*msgjson.Message 24 recvd []*msgjson.Message 25 sendErr error 26 } 27 28 func tNewSender(peerID tanka.PeerID) *tSender { 29 return &tSender{id: peerID} 30 } 31 32 func (s *tSender) queueResponse(resp *msgjson.Message) { 33 s.responses = append(s.responses, resp) 34 } 35 36 func (s *tSender) received() *msgjson.Message { 37 if len(s.recvd) == 0 { 38 return nil 39 } 40 msg := s.recvd[0] 41 s.recvd = s.recvd[1:] 42 return msg 43 } 44 45 func (s *tSender) Send(msg *msgjson.Message) error { 46 s.recvd = append(s.recvd, msg) 47 return s.sendErr 48 } 49 func (s *tSender) SendRaw(rawMsg []byte) error { 50 msg, err := msgjson.DecodeMessage(rawMsg) 51 if err != nil { 52 return fmt.Errorf("tSender DecodeMessage error: %w", err) 53 } 54 s.recvd = append(s.recvd, msg) 55 return s.sendErr 56 } 57 func (s *tSender) Request(msg *msgjson.Message, respHandler func(*msgjson.Message)) error { 58 return s.RequestRaw(0, nil, respHandler) 59 } 60 func (s *tSender) RequestRaw(msgID uint64, rawMsg []byte, respHandler func(*msgjson.Message)) error { 61 if s.responseErr != nil { 62 return s.responseErr 63 } 64 if len(s.responses) == 0 { 65 return errors.New("not test responses queued") 66 } 67 resp := s.responses[0] 68 s.responses = s.responses[1:] 69 go respHandler(resp) // goroutine to simulate Sender impls 70 return nil 71 } 72 func (s *tSender) SetPeerID(tanka.PeerID) {} 73 74 func (s *tSender) PeerID() tanka.PeerID { 75 return s.id 76 } 77 func (s *tSender) Disconnect() { 78 s.disconnected = true 79 } 80 81 func tNewTatanka(id byte) (*Tatanka, func()) { 82 priv, _ := secp256k1.GeneratePrivateKey() 83 var peerID tanka.PeerID 84 peerID[tanka.PeerIDLength-1] = id 85 86 ctx, cancel := context.WithCancel(context.Background()) 87 88 srv := &Tatanka{ 89 ctx: ctx, 90 net: dex.Simnet, 91 log: dex.StdOutLogger("T", dex.LevelTrace), 92 // db: db, 93 priv: priv, 94 id: peerID, 95 // chains: chains, 96 tatankas: make(map[tanka.PeerID]*remoteTatanka), 97 clients: make(map[tanka.PeerID]*client), 98 remoteClients: make(map[tanka.PeerID]map[tanka.PeerID]struct{}), 99 topics: make(map[tanka.Topic]*Topic), 100 recentRelays: make(map[[32]byte]time.Time), 101 clientJobs: make(chan *clientJob, 128), 102 } 103 104 go srv.runRemoteClientsLoop(ctx) 105 106 return srv, cancel 107 } 108 109 func tNewPeer(id byte) (*peer, *tSender) { 110 var peerID tanka.PeerID 111 peerID[tanka.PeerIDLength-1] = id 112 p := &tanka.Peer{ID: peerID} 113 s := tNewSender(peerID) 114 return &peer{Peer: p, Sender: s, rrs: make(map[tanka.PeerID]*mj.RemoteReputation)}, s 115 } 116 117 func tNewRemoteTatanka(id byte) (*remoteTatanka, *tSender) { 118 p, s := tNewPeer(id) 119 return &remoteTatanka{peer: p}, s 120 } 121 122 func tNewClient(id byte) (*client, *tSender) { 123 p, s := tNewPeer(id) 124 return &client{peer: p}, s 125 } 126 127 func TestTankagrams(t *testing.T) { 128 srv, shutdown := tNewTatanka(0) 129 defer shutdown() 130 131 tt, tts := tNewRemoteTatanka(1) 132 srv.tatankas[tt.ID] = tt 133 134 c0, c0s := tNewClient(2) 135 srv.clients[c0.ID] = c0 136 137 c1, c1s := tNewClient(3) 138 srv.clients[c1.ID] = c1 139 140 gram := &mj.Tankagram{ 141 From: c0.ID, 142 To: c1.ID, 143 } 144 msg := mj.MustRequest(mj.RouteTankagram, gram) 145 var r mj.TankagramResult 146 checkResponse := func(expResult mj.TankagramResultType) { 147 t.Helper() 148 if msgErr := srv.handleTankagram(c0, msg); msgErr != nil { 149 t.Fatalf("Initial handleTankagram error: %v", msgErr) 150 } 151 respMsg := c0s.received() 152 if respMsg == nil { 153 t.Fatalf("No response received") 154 } 155 156 respMsg.UnmarshalResult(&r) 157 if r.Result != expResult { 158 t.Fatalf("Expected result %q, got %q", expResult, r.Result) 159 } 160 } 161 162 // tankagram to locally connected client success 163 responseB := dex.Bytes(encode.RandomBytes(10)) 164 resp := mj.MustResponse(msg.ID, responseB, nil) 165 c1s.queueResponse(resp) 166 checkResponse(mj.TRTTransmitted) 167 if !bytes.Equal(r.Response, responseB) { 168 t.Fatalf("wrong response") 169 } 170 171 // Bad response from client. 172 resp, _ = msgjson.NewResponse(msg.ID, "zz", nil) 173 c1s.queueResponse(resp) 174 checkResponse(mj.TRTErrBadClient) 175 176 // Client not responsive locally, but is remotely. 177 c1s.responseErr = errors.New("test error") 178 resp, _ = msgjson.NewResponse(msg.ID, &mj.TankagramResult{Result: mj.TRTTransmitted, Response: responseB}, nil) 179 tts.queueResponse(resp) 180 srv.remoteClients[c1.ID] = map[tanka.PeerID]struct{}{tt.ID: {}} 181 checkResponse(mj.TRTTransmitted) 182 if !bytes.Equal(r.Response, responseB) { 183 t.Fatalf("wrong response") 184 } 185 c1s.responseErr = nil 186 187 // Client not known locally, and is erroneous remotely. 188 delete(srv.clients, c1.ID) 189 resp, _ = msgjson.NewResponse(msg.ID, &mj.TankagramResult{Result: mj.TRTErrBadClient}, nil) 190 tts.queueResponse(resp) 191 checkResponse(mj.TRTErrBadClient) 192 193 // Client not known locally or remotely 194 delete(srv.remoteClients, c1.ID) 195 checkResponse(mj.TRTNoPath) 196 197 // Now we're the remote. 198 199 // We know the client and transmit the relayed tankagram successfully. 200 srv.clients[c1.ID] = c1 201 resp, _ = msgjson.NewResponse(msg.ID, responseB, nil) 202 c1s.queueResponse(resp) 203 msg, _ = msgjson.NewRequest(mj.NewMessageID(), mj.RouteRelayTankagram, gram) 204 srv.handleRelayedTankagram(tt, msg) 205 respMsg := tts.received() 206 if respMsg == nil { 207 t.Fatalf("No response received") 208 } 209 respMsg.UnmarshalResult(&r) 210 if r.Result != mj.TRTTransmitted { 211 t.Fatalf("Expected result %q, got %q", mj.TRTTransmitted, r.Result) 212 } 213 }