github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/whisper/whisperv2/peer_test.go (about) 1 // Copyright 2015 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package whisperv2 18 19 import ( 20 "testing" 21 "time" 22 23 "github.com/SmartMeshFoundation/Spectrum/p2p" 24 "github.com/SmartMeshFoundation/Spectrum/p2p/discover" 25 ) 26 27 type testPeer struct { 28 client *Whisper 29 stream *p2p.MsgPipeRW 30 termed chan struct{} 31 } 32 33 func startTestPeer() *testPeer { 34 // Create a simulated P2P remote peer and data streams to it 35 remote := p2p.NewPeer(discover.NodeID{}, "", nil) 36 tester, tested := p2p.MsgPipe() 37 38 // Create a whisper client and connect with it to the tester peer 39 client := New() 40 client.Start(nil) 41 42 termed := make(chan struct{}) 43 go func() { 44 defer client.Stop() 45 defer close(termed) 46 defer tested.Close() 47 48 client.handlePeer(remote, tested) 49 }() 50 51 return &testPeer{ 52 client: client, 53 stream: tester, 54 termed: termed, 55 } 56 } 57 58 func startTestPeerInited() (*testPeer, error) { 59 peer := startTestPeer() 60 61 if err := p2p.ExpectMsg(peer.stream, statusCode, []uint64{protocolVersion}); err != nil { 62 peer.stream.Close() 63 return nil, err 64 } 65 if err := p2p.SendItems(peer.stream, statusCode, protocolVersion); err != nil { 66 peer.stream.Close() 67 return nil, err 68 } 69 return peer, nil 70 } 71 72 func TestPeerStatusMessage(t *testing.T) { 73 tester := startTestPeer() 74 75 // Wait for the handshake status message and check it 76 if err := p2p.ExpectMsg(tester.stream, statusCode, []uint64{protocolVersion}); err != nil { 77 t.Fatalf("status message mismatch: %v", err) 78 } 79 // Terminate the node 80 tester.stream.Close() 81 82 select { 83 case <-tester.termed: 84 case <-time.After(time.Second): 85 t.Fatalf("local close timed out") 86 } 87 } 88 89 func TestPeerHandshakeFail(t *testing.T) { 90 tester := startTestPeer() 91 92 // Wait for and check the handshake 93 if err := p2p.ExpectMsg(tester.stream, statusCode, []uint64{protocolVersion}); err != nil { 94 t.Fatalf("status message mismatch: %v", err) 95 } 96 // Send an invalid handshake status and verify disconnect 97 if err := p2p.SendItems(tester.stream, messagesCode); err != nil { 98 t.Fatalf("failed to send malformed status: %v", err) 99 } 100 select { 101 case <-tester.termed: 102 case <-time.After(time.Second): 103 t.Fatalf("remote close timed out") 104 } 105 } 106 107 func TestPeerHandshakeSuccess(t *testing.T) { 108 tester := startTestPeer() 109 110 // Wait for and check the handshake 111 if err := p2p.ExpectMsg(tester.stream, statusCode, []uint64{protocolVersion}); err != nil { 112 t.Fatalf("status message mismatch: %v", err) 113 } 114 // Send a valid handshake status and make sure connection stays live 115 if err := p2p.SendItems(tester.stream, statusCode, protocolVersion); err != nil { 116 t.Fatalf("failed to send status: %v", err) 117 } 118 select { 119 case <-tester.termed: 120 t.Fatalf("valid handshake disconnected") 121 122 case <-time.After(100 * time.Millisecond): 123 } 124 // Clean up the test 125 tester.stream.Close() 126 127 select { 128 case <-tester.termed: 129 case <-time.After(time.Second): 130 t.Fatalf("local close timed out") 131 } 132 } 133 134 func TestPeerSend(t *testing.T) { 135 // Start a tester and execute the handshake 136 tester, err := startTestPeerInited() 137 if err != nil { 138 t.Fatalf("failed to start initialized peer: %v", err) 139 } 140 defer tester.stream.Close() 141 142 // Construct a message and inject into the tester 143 message := NewMessage([]byte("peer broadcast test message")) 144 envelope, err := message.Wrap(DefaultPoW, Options{ 145 TTL: DefaultTTL, 146 }) 147 if err != nil { 148 t.Fatalf("failed to wrap message: %v", err) 149 } 150 if err := tester.client.Send(envelope); err != nil { 151 t.Fatalf("failed to send message: %v", err) 152 } 153 // Check that the message is eventually forwarded 154 payload := []interface{}{envelope} 155 if err := p2p.ExpectMsg(tester.stream, messagesCode, payload); err != nil { 156 t.Fatalf("message mismatch: %v", err) 157 } 158 // Make sure that even with a re-insert, an empty batch is received 159 if err := tester.client.Send(envelope); err != nil { 160 t.Fatalf("failed to send message: %v", err) 161 } 162 if err := p2p.ExpectMsg(tester.stream, messagesCode, []interface{}{}); err != nil { 163 t.Fatalf("message mismatch: %v", err) 164 } 165 } 166 167 func TestPeerDeliver(t *testing.T) { 168 // Start a tester and execute the handshake 169 tester, err := startTestPeerInited() 170 if err != nil { 171 t.Fatalf("failed to start initialized peer: %v", err) 172 } 173 defer tester.stream.Close() 174 175 // Watch for all inbound messages 176 arrived := make(chan struct{}, 1) 177 tester.client.Watch(Filter{ 178 Fn: func(message *Message) { 179 arrived <- struct{}{} 180 }, 181 }) 182 // Construct a message and deliver it to the tester peer 183 message := NewMessage([]byte("peer broadcast test message")) 184 envelope, err := message.Wrap(DefaultPoW, Options{ 185 TTL: DefaultTTL, 186 }) 187 if err != nil { 188 t.Fatalf("failed to wrap message: %v", err) 189 } 190 if err := p2p.Send(tester.stream, messagesCode, []*Envelope{envelope}); err != nil { 191 t.Fatalf("failed to transfer message: %v", err) 192 } 193 // Check that the message is delivered upstream 194 select { 195 case <-arrived: 196 case <-time.After(time.Second): 197 t.Fatalf("message delivery timeout") 198 } 199 // Check that a resend is not delivered 200 if err := p2p.Send(tester.stream, messagesCode, []*Envelope{envelope}); err != nil { 201 t.Fatalf("failed to transfer message: %v", err) 202 } 203 select { 204 case <-time.After(2 * transmissionCycle): 205 case <-arrived: 206 t.Fatalf("repeating message arrived") 207 } 208 } 209 210 func TestPeerMessageExpiration(t *testing.T) { 211 // Start a tester and execute the handshake 212 tester, err := startTestPeerInited() 213 if err != nil { 214 t.Fatalf("failed to start initialized peer: %v", err) 215 } 216 defer tester.stream.Close() 217 218 // Fetch the peer instance for later inspection 219 tester.client.peerMu.RLock() 220 if peers := len(tester.client.peers); peers != 1 { 221 t.Fatalf("peer pool size mismatch: have %v, want %v", peers, 1) 222 } 223 var peer *peer 224 for peer = range tester.client.peers { 225 break 226 } 227 tester.client.peerMu.RUnlock() 228 229 // Construct a message and pass it through the tester 230 message := NewMessage([]byte("peer test message")) 231 envelope, err := message.Wrap(DefaultPoW, Options{ 232 TTL: time.Second, 233 }) 234 if err != nil { 235 t.Fatalf("failed to wrap message: %v", err) 236 } 237 if err := tester.client.Send(envelope); err != nil { 238 t.Fatalf("failed to send message: %v", err) 239 } 240 payload := []interface{}{envelope} 241 if err := p2p.ExpectMsg(tester.stream, messagesCode, payload); err != nil { 242 // A premature empty message may have been broadcast, check the next too 243 if err := p2p.ExpectMsg(tester.stream, messagesCode, payload); err != nil { 244 t.Fatalf("message mismatch: %v", err) 245 } 246 } 247 // Check that the message is inside the cache 248 if !peer.known.Has(envelope.Hash()) { 249 t.Fatalf("message not found in cache") 250 } 251 // Discard messages until expiration and check cache again 252 exp := time.Now().Add(time.Second + 2*expirationCycle + 100*time.Millisecond) 253 for time.Now().Before(exp) { 254 if err := p2p.ExpectMsg(tester.stream, messagesCode, []interface{}{}); err != nil { 255 t.Fatalf("message mismatch: %v", err) 256 } 257 } 258 if peer.known.Has(envelope.Hash()) { 259 t.Fatalf("message not expired from cache") 260 } 261 }