github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/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/ShyftNetwork/go-empyrean/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 288 peersToSkip := &sync.Map{} 289 290 // set searchTimeOut to low value so the test is quicker 291 defer func(t time.Duration) { 292 searchTimeout = t 293 }(searchTimeout) 294 searchTimeout = 250 * time.Millisecond 295 296 ctx, cancel := context.WithCancel(context.Background()) 297 defer cancel() 298 299 // start the fetcher 300 go fetcher.run(ctx, peersToSkip) 301 302 // call the fetch function with an active context 303 rctx := context.Background() 304 fetcher.Request(rctx, 0) 305 306 // after 100ms the first request should be initiated 307 time.Sleep(100 * time.Millisecond) 308 309 select { 310 case <-requester.requestC: 311 default: 312 t.Fatalf("fetch did not initiate request") 313 } 314 315 // after another 100ms no new request should be initiated, because search timeout is 250ms 316 time.Sleep(100 * time.Millisecond) 317 318 select { 319 case <-requester.requestC: 320 t.Fatalf("unexpected request from fetcher") 321 default: 322 } 323 324 // after another 300ms search timeout is over, there should be a new request 325 time.Sleep(300 * time.Millisecond) 326 327 select { 328 case <-requester.requestC: 329 default: 330 t.Fatalf("fetch did not retry request") 331 } 332 } 333 334 // TestFetcherFactory creates a FetcherFactory and checks if the factory really creates and starts 335 // a Fetcher when it return a fetch function. We test the fetching functionality just by checking if 336 // a request is initiated when the fetch function is called 337 func TestFetcherFactory(t *testing.T) { 338 requester := newMockRequester(100 * time.Millisecond) 339 addr := make([]byte, 32) 340 fetcherFactory := NewFetcherFactory(requester.doRequest, false) 341 342 peersToSkip := &sync.Map{} 343 344 fetcher := fetcherFactory.New(context.Background(), addr, peersToSkip) 345 346 fetcher.Request(context.Background(), 0) 347 348 // check if the created fetchFunction really starts a fetcher and initiates a request 349 select { 350 case <-requester.requestC: 351 case <-time.After(200 * time.Millisecond): 352 t.Fatalf("fetch timeout") 353 } 354 355 } 356 357 func TestFetcherRequestQuitRetriesRequest(t *testing.T) { 358 requester := newMockRequester() 359 addr := make([]byte, 32) 360 fetcher := NewFetcher(addr, requester.doRequest, true) 361 362 // make sure searchTimeout is long so it is sure the request is not retried because of timeout 363 defer func(t time.Duration) { 364 searchTimeout = t 365 }(searchTimeout) 366 searchTimeout = 10 * time.Second 367 368 peersToSkip := &sync.Map{} 369 370 ctx, cancel := context.WithCancel(context.Background()) 371 defer cancel() 372 373 go fetcher.run(ctx, peersToSkip) 374 375 rctx := context.Background() 376 fetcher.Request(rctx, 0) 377 378 select { 379 case <-requester.requestC: 380 case <-time.After(200 * time.Millisecond): 381 t.Fatalf("request is not initiated") 382 } 383 384 close(requester.quitC) 385 386 select { 387 case <-requester.requestC: 388 case <-time.After(200 * time.Millisecond): 389 t.Fatalf("request is not initiated after failed request") 390 } 391 } 392 393 // TestRequestSkipPeer checks if PeerSkip function will skip provided peer 394 // and not skip unknown one. 395 func TestRequestSkipPeer(t *testing.T) { 396 addr := make([]byte, 32) 397 peers := []enode.ID{ 398 enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8"), 399 enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9"), 400 } 401 402 peersToSkip := new(sync.Map) 403 peersToSkip.Store(peers[0].String(), time.Now()) 404 r := NewRequest(addr, false, peersToSkip) 405 406 if !r.SkipPeer(peers[0].String()) { 407 t.Errorf("peer not skipped") 408 } 409 410 if r.SkipPeer(peers[1].String()) { 411 t.Errorf("peer skipped") 412 } 413 } 414 415 // TestRequestSkipPeerExpired checks if a peer to skip is not skipped 416 // after RequestTimeout has passed. 417 func TestRequestSkipPeerExpired(t *testing.T) { 418 addr := make([]byte, 32) 419 peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") 420 421 // set RequestTimeout to a low value and reset it after the test 422 defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) 423 RequestTimeout = 250 * time.Millisecond 424 425 peersToSkip := new(sync.Map) 426 peersToSkip.Store(peer.String(), time.Now()) 427 r := NewRequest(addr, false, peersToSkip) 428 429 if !r.SkipPeer(peer.String()) { 430 t.Errorf("peer not skipped") 431 } 432 433 time.Sleep(500 * time.Millisecond) 434 435 if r.SkipPeer(peer.String()) { 436 t.Errorf("peer skipped") 437 } 438 } 439 440 // TestRequestSkipPeerPermanent checks if a peer to skip is not skipped 441 // after RequestTimeout is not skipped if it is set for a permanent skipping 442 // by value to peersToSkip map is not time.Duration. 443 func TestRequestSkipPeerPermanent(t *testing.T) { 444 addr := make([]byte, 32) 445 peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") 446 447 // set RequestTimeout to a low value and reset it after the test 448 defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) 449 RequestTimeout = 250 * time.Millisecond 450 451 peersToSkip := new(sync.Map) 452 peersToSkip.Store(peer.String(), true) 453 r := NewRequest(addr, false, peersToSkip) 454 455 if !r.SkipPeer(peer.String()) { 456 t.Errorf("peer not skipped") 457 } 458 459 time.Sleep(500 * time.Millisecond) 460 461 if !r.SkipPeer(peer.String()) { 462 t.Errorf("peer not skipped") 463 } 464 } 465 466 func TestFetcherMaxHopCount(t *testing.T) { 467 requester := newMockRequester() 468 addr := make([]byte, 32) 469 fetcher := NewFetcher(addr, requester.doRequest, true) 470 471 ctx, cancel := context.WithCancel(context.Background()) 472 defer cancel() 473 474 peersToSkip := &sync.Map{} 475 476 go fetcher.run(ctx, peersToSkip) 477 478 rctx := context.Background() 479 fetcher.Request(rctx, maxHopCount) 480 481 // if hopCount is already at max no request should be initiated 482 select { 483 case <-requester.requestC: 484 t.Fatalf("cancelled fetcher initiated request") 485 case <-time.After(200 * time.Millisecond): 486 } 487 }