github.com/letterj/go-ethereum@v1.8.22-0.20190204142846-520024dfd689/swarm/network/fetcher_test.go (about) 1 // Copyright 2018 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 network 18 19 import ( 20 "context" 21 "sync" 22 "testing" 23 "time" 24 25 "github.com/ethereum/go-ethereum/p2p/enode" 26 ) 27 28 var requestedPeerID = enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") 29 var sourcePeerID = enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9") 30 31 // mockRequester pushes every request to the requestC channel when its doRequest function is called 32 type mockRequester struct { 33 // requests []Request 34 requestC chan *Request // when a request is coming it is pushed to requestC 35 waitTimes []time.Duration // with waitTimes[i] you can define how much to wait on the ith request (optional) 36 count int //counts the number of requests 37 quitC chan struct{} 38 } 39 40 func newMockRequester(waitTimes ...time.Duration) *mockRequester { 41 return &mockRequester{ 42 requestC: make(chan *Request), 43 waitTimes: waitTimes, 44 quitC: make(chan struct{}), 45 } 46 } 47 48 func (m *mockRequester) doRequest(ctx context.Context, request *Request) (*enode.ID, chan struct{}, error) { 49 waitTime := time.Duration(0) 50 if m.count < len(m.waitTimes) { 51 waitTime = m.waitTimes[m.count] 52 m.count++ 53 } 54 time.Sleep(waitTime) 55 m.requestC <- request 56 57 // if there is a Source in the request use that, if not use the global requestedPeerId 58 source := request.Source 59 if source == nil { 60 source = &requestedPeerID 61 } 62 return source, m.quitC, nil 63 } 64 65 // TestFetcherSingleRequest creates a Fetcher using mockRequester, and run it with a sample set of peers to skip. 66 // mockRequester pushes a Request on a channel every time the request function is called. Using 67 // this channel we test if calling Fetcher.Request calls the request function, and whether it uses 68 // the correct peers to skip which we provided for the fetcher.run function. 69 func TestFetcherSingleRequest(t *testing.T) { 70 requester := newMockRequester() 71 addr := make([]byte, 32) 72 fetcher := NewFetcher(addr, requester.doRequest, true) 73 74 peers := []string{"a", "b", "c", "d"} 75 peersToSkip := &sync.Map{} 76 for _, p := range peers { 77 peersToSkip.Store(p, time.Now()) 78 } 79 80 ctx, cancel := context.WithCancel(context.Background()) 81 defer cancel() 82 83 go fetcher.run(ctx, peersToSkip) 84 85 rctx := context.Background() 86 fetcher.Request(rctx, 0) 87 88 select { 89 case request := <-requester.requestC: 90 // request should contain all peers from peersToSkip provided to the fetcher 91 for _, p := range peers { 92 if _, ok := request.peersToSkip.Load(p); !ok { 93 t.Fatalf("request.peersToSkip misses peer") 94 } 95 } 96 97 // source peer should be also added to peersToSkip eventually 98 time.Sleep(100 * time.Millisecond) 99 if _, ok := request.peersToSkip.Load(requestedPeerID.String()); !ok { 100 t.Fatalf("request.peersToSkip does not contain peer returned by the request function") 101 } 102 103 // hopCount in the forwarded request should be incremented 104 if request.HopCount != 1 { 105 t.Fatalf("Expected request.HopCount 1 got %v", request.HopCount) 106 } 107 108 // fetch should trigger a request, if it doesn't happen in time, test should fail 109 case <-time.After(200 * time.Millisecond): 110 t.Fatalf("fetch timeout") 111 } 112 } 113 114 // TestCancelStopsFetcher tests that a cancelled fetcher does not initiate further requests even if its fetch function is called 115 func TestFetcherCancelStopsFetcher(t *testing.T) { 116 requester := newMockRequester() 117 addr := make([]byte, 32) 118 fetcher := NewFetcher(addr, requester.doRequest, true) 119 120 peersToSkip := &sync.Map{} 121 122 ctx, cancel := context.WithCancel(context.Background()) 123 124 // we start the fetcher, and then we immediately cancel the context 125 go fetcher.run(ctx, peersToSkip) 126 cancel() 127 128 rctx, rcancel := context.WithTimeout(ctx, 100*time.Millisecond) 129 defer rcancel() 130 // we call Request with an active context 131 fetcher.Request(rctx, 0) 132 133 // fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening 134 select { 135 case <-requester.requestC: 136 t.Fatalf("cancelled fetcher initiated request") 137 case <-time.After(200 * time.Millisecond): 138 } 139 } 140 141 // TestFetchCancelStopsRequest tests that calling a Request function with a cancelled context does not initiate a request 142 func TestFetcherCancelStopsRequest(t *testing.T) { 143 requester := newMockRequester(100 * time.Millisecond) 144 addr := make([]byte, 32) 145 fetcher := NewFetcher(addr, requester.doRequest, true) 146 147 peersToSkip := &sync.Map{} 148 149 ctx, cancel := context.WithCancel(context.Background()) 150 defer cancel() 151 152 // we start the fetcher with an active context 153 go fetcher.run(ctx, peersToSkip) 154 155 rctx, rcancel := context.WithCancel(context.Background()) 156 rcancel() 157 158 // we call Request with a cancelled context 159 fetcher.Request(rctx, 0) 160 161 // fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening 162 select { 163 case <-requester.requestC: 164 t.Fatalf("cancelled fetch function initiated request") 165 case <-time.After(200 * time.Millisecond): 166 } 167 168 // if there is another Request with active context, there should be a request, because the fetcher itself is not cancelled 169 rctx = context.Background() 170 fetcher.Request(rctx, 0) 171 172 select { 173 case <-requester.requestC: 174 case <-time.After(200 * time.Millisecond): 175 t.Fatalf("expected request") 176 } 177 } 178 179 // TestOfferUsesSource tests Fetcher Offer behavior. 180 // In this case there should be 1 (and only one) request initiated from the source peer, and the 181 // source nodeid should appear in the peersToSkip map. 182 func TestFetcherOfferUsesSource(t *testing.T) { 183 requester := newMockRequester(100 * time.Millisecond) 184 addr := make([]byte, 32) 185 fetcher := NewFetcher(addr, requester.doRequest, true) 186 187 peersToSkip := &sync.Map{} 188 189 ctx, cancel := context.WithCancel(context.Background()) 190 defer cancel() 191 192 // start the fetcher 193 go fetcher.run(ctx, peersToSkip) 194 195 rctx := context.Background() 196 // call the Offer function with the source peer 197 fetcher.Offer(rctx, &sourcePeerID) 198 199 // fetcher should not initiate request 200 select { 201 case <-requester.requestC: 202 t.Fatalf("fetcher initiated request") 203 case <-time.After(200 * time.Millisecond): 204 } 205 206 // call Request after the Offer 207 rctx = context.Background() 208 fetcher.Request(rctx, 0) 209 210 // there should be exactly 1 request coming from fetcher 211 var request *Request 212 select { 213 case request = <-requester.requestC: 214 if *request.Source != sourcePeerID { 215 t.Fatalf("Expected source id %v got %v", sourcePeerID, request.Source) 216 } 217 case <-time.After(200 * time.Millisecond): 218 t.Fatalf("fetcher did not initiate request") 219 } 220 221 select { 222 case <-requester.requestC: 223 t.Fatalf("Fetcher number of requests expected 1 got 2") 224 case <-time.After(200 * time.Millisecond): 225 } 226 227 // source peer should be added to peersToSkip eventually 228 time.Sleep(100 * time.Millisecond) 229 if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok { 230 t.Fatalf("SourcePeerId not added to peersToSkip") 231 } 232 } 233 234 func TestFetcherOfferAfterRequestUsesSourceFromContext(t *testing.T) { 235 requester := newMockRequester(100 * time.Millisecond) 236 addr := make([]byte, 32) 237 fetcher := NewFetcher(addr, requester.doRequest, true) 238 239 peersToSkip := &sync.Map{} 240 241 ctx, cancel := context.WithCancel(context.Background()) 242 defer cancel() 243 244 // start the fetcher 245 go fetcher.run(ctx, peersToSkip) 246 247 // call Request first 248 rctx := context.Background() 249 fetcher.Request(rctx, 0) 250 251 // there should be a request coming from fetcher 252 var request *Request 253 select { 254 case request = <-requester.requestC: 255 if request.Source != nil { 256 t.Fatalf("Incorrect source peer id, expected nil got %v", request.Source) 257 } 258 case <-time.After(200 * time.Millisecond): 259 t.Fatalf("fetcher did not initiate request") 260 } 261 262 // after the Request call Offer 263 fetcher.Offer(context.Background(), &sourcePeerID) 264 265 // there should be a request coming from fetcher 266 select { 267 case request = <-requester.requestC: 268 if *request.Source != sourcePeerID { 269 t.Fatalf("Incorrect source peer id, expected %v got %v", sourcePeerID, request.Source) 270 } 271 case <-time.After(200 * time.Millisecond): 272 t.Fatalf("fetcher did not initiate request") 273 } 274 275 // source peer should be added to peersToSkip eventually 276 time.Sleep(100 * time.Millisecond) 277 if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok { 278 t.Fatalf("SourcePeerId not added to peersToSkip") 279 } 280 } 281 282 // TestFetcherRetryOnTimeout tests that fetch retries after searchTimeOut has passed 283 func TestFetcherRetryOnTimeout(t *testing.T) { 284 requester := newMockRequester() 285 addr := make([]byte, 32) 286 fetcher := NewFetcher(addr, requester.doRequest, true) 287 // set searchTimeOut to low value so the test is quicker 288 fetcher.searchTimeout = 250 * time.Millisecond 289 290 peersToSkip := &sync.Map{} 291 292 ctx, cancel := context.WithCancel(context.Background()) 293 defer cancel() 294 295 // start the fetcher 296 go fetcher.run(ctx, peersToSkip) 297 298 // call the fetch function with an active context 299 rctx := context.Background() 300 fetcher.Request(rctx, 0) 301 302 // after 100ms the first request should be initiated 303 time.Sleep(100 * time.Millisecond) 304 305 select { 306 case <-requester.requestC: 307 default: 308 t.Fatalf("fetch did not initiate request") 309 } 310 311 // after another 100ms no new request should be initiated, because search timeout is 250ms 312 time.Sleep(100 * time.Millisecond) 313 314 select { 315 case <-requester.requestC: 316 t.Fatalf("unexpected request from fetcher") 317 default: 318 } 319 320 // after another 300ms search timeout is over, there should be a new request 321 time.Sleep(300 * time.Millisecond) 322 323 select { 324 case <-requester.requestC: 325 default: 326 t.Fatalf("fetch did not retry request") 327 } 328 } 329 330 // TestFetcherFactory creates a FetcherFactory and checks if the factory really creates and starts 331 // a Fetcher when it return a fetch function. We test the fetching functionality just by checking if 332 // a request is initiated when the fetch function is called 333 func TestFetcherFactory(t *testing.T) { 334 requester := newMockRequester(100 * time.Millisecond) 335 addr := make([]byte, 32) 336 fetcherFactory := NewFetcherFactory(requester.doRequest, false) 337 338 peersToSkip := &sync.Map{} 339 340 fetcher := fetcherFactory.New(context.Background(), addr, peersToSkip) 341 342 fetcher.Request(context.Background(), 0) 343 344 // check if the created fetchFunction really starts a fetcher and initiates a request 345 select { 346 case <-requester.requestC: 347 case <-time.After(200 * time.Millisecond): 348 t.Fatalf("fetch timeout") 349 } 350 351 } 352 353 func TestFetcherRequestQuitRetriesRequest(t *testing.T) { 354 requester := newMockRequester() 355 addr := make([]byte, 32) 356 fetcher := NewFetcher(addr, requester.doRequest, true) 357 358 // make sure the searchTimeout is long so it is sure the request is not 359 // retried because of timeout 360 fetcher.searchTimeout = 10 * time.Second 361 362 peersToSkip := &sync.Map{} 363 364 ctx, cancel := context.WithCancel(context.Background()) 365 defer cancel() 366 367 go fetcher.run(ctx, peersToSkip) 368 369 rctx := context.Background() 370 fetcher.Request(rctx, 0) 371 372 select { 373 case <-requester.requestC: 374 case <-time.After(200 * time.Millisecond): 375 t.Fatalf("request is not initiated") 376 } 377 378 close(requester.quitC) 379 380 select { 381 case <-requester.requestC: 382 case <-time.After(200 * time.Millisecond): 383 t.Fatalf("request is not initiated after failed request") 384 } 385 } 386 387 // TestRequestSkipPeer checks if PeerSkip function will skip provided peer 388 // and not skip unknown one. 389 func TestRequestSkipPeer(t *testing.T) { 390 addr := make([]byte, 32) 391 peers := []enode.ID{ 392 enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8"), 393 enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9"), 394 } 395 396 peersToSkip := new(sync.Map) 397 peersToSkip.Store(peers[0].String(), time.Now()) 398 r := NewRequest(addr, false, peersToSkip) 399 400 if !r.SkipPeer(peers[0].String()) { 401 t.Errorf("peer not skipped") 402 } 403 404 if r.SkipPeer(peers[1].String()) { 405 t.Errorf("peer skipped") 406 } 407 } 408 409 // TestRequestSkipPeerExpired checks if a peer to skip is not skipped 410 // after RequestTimeout has passed. 411 func TestRequestSkipPeerExpired(t *testing.T) { 412 addr := make([]byte, 32) 413 peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") 414 415 // set RequestTimeout to a low value and reset it after the test 416 defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) 417 RequestTimeout = 250 * time.Millisecond 418 419 peersToSkip := new(sync.Map) 420 peersToSkip.Store(peer.String(), time.Now()) 421 r := NewRequest(addr, false, peersToSkip) 422 423 if !r.SkipPeer(peer.String()) { 424 t.Errorf("peer not skipped") 425 } 426 427 time.Sleep(500 * time.Millisecond) 428 429 if r.SkipPeer(peer.String()) { 430 t.Errorf("peer skipped") 431 } 432 } 433 434 // TestRequestSkipPeerPermanent checks if a peer to skip is not skipped 435 // after RequestTimeout is not skipped if it is set for a permanent skipping 436 // by value to peersToSkip map is not time.Duration. 437 func TestRequestSkipPeerPermanent(t *testing.T) { 438 addr := make([]byte, 32) 439 peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") 440 441 // set RequestTimeout to a low value and reset it after the test 442 defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) 443 RequestTimeout = 250 * time.Millisecond 444 445 peersToSkip := new(sync.Map) 446 peersToSkip.Store(peer.String(), true) 447 r := NewRequest(addr, false, peersToSkip) 448 449 if !r.SkipPeer(peer.String()) { 450 t.Errorf("peer not skipped") 451 } 452 453 time.Sleep(500 * time.Millisecond) 454 455 if !r.SkipPeer(peer.String()) { 456 t.Errorf("peer not skipped") 457 } 458 } 459 460 func TestFetcherMaxHopCount(t *testing.T) { 461 requester := newMockRequester() 462 addr := make([]byte, 32) 463 fetcher := NewFetcher(addr, requester.doRequest, true) 464 465 ctx, cancel := context.WithCancel(context.Background()) 466 defer cancel() 467 468 peersToSkip := &sync.Map{} 469 470 go fetcher.run(ctx, peersToSkip) 471 472 rctx := context.Background() 473 fetcher.Request(rctx, maxHopCount) 474 475 // if hopCount is already at max no request should be initiated 476 select { 477 case <-requester.requestC: 478 t.Fatalf("cancelled fetcher initiated request") 479 case <-time.After(200 * time.Millisecond): 480 } 481 }