github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/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/FusionFoundation/efsn/p2p/discover" 26 ) 27 28 var requestedPeerID = discover.MustHexID("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439") 29 var sourcePeerID = discover.MustHexID("2dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439") 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 ctr 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) (*discover.NodeID, chan struct{}, error) { 49 waitTime := time.Duration(0) 50 if m.ctr < len(m.waitTimes) { 51 waitTime = m.waitTimes[m.ctr] 52 m.ctr++ 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) 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 // fetch should trigger a request, if it doesn't happen in time, test should fail 104 case <-time.After(200 * time.Millisecond): 105 t.Fatalf("fetch timeout") 106 } 107 } 108 109 // TestCancelStopsFetcher tests that a cancelled fetcher does not initiate further requests even if its fetch function is called 110 func TestFetcherCancelStopsFetcher(t *testing.T) { 111 requester := newMockRequester() 112 addr := make([]byte, 32) 113 fetcher := NewFetcher(addr, requester.doRequest, true) 114 115 peersToSkip := &sync.Map{} 116 117 ctx, cancel := context.WithCancel(context.Background()) 118 119 // we start the fetcher, and then we immediately cancel the context 120 go fetcher.run(ctx, peersToSkip) 121 cancel() 122 123 rctx, rcancel := context.WithTimeout(ctx, 100*time.Millisecond) 124 defer rcancel() 125 // we call Request with an active context 126 fetcher.Request(rctx) 127 128 // fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening 129 select { 130 case <-requester.requestC: 131 t.Fatalf("cancelled fetcher initiated request") 132 case <-time.After(200 * time.Millisecond): 133 } 134 } 135 136 // TestFetchCancelStopsRequest tests that calling a Request function with a cancelled context does not initiate a request 137 func TestFetcherCancelStopsRequest(t *testing.T) { 138 requester := newMockRequester(100 * time.Millisecond) 139 addr := make([]byte, 32) 140 fetcher := NewFetcher(addr, requester.doRequest, true) 141 142 peersToSkip := &sync.Map{} 143 144 ctx, cancel := context.WithCancel(context.Background()) 145 defer cancel() 146 147 // we start the fetcher with an active context 148 go fetcher.run(ctx, peersToSkip) 149 150 rctx, rcancel := context.WithCancel(context.Background()) 151 rcancel() 152 153 // we call Request with a cancelled context 154 fetcher.Request(rctx) 155 156 // fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening 157 select { 158 case <-requester.requestC: 159 t.Fatalf("cancelled fetch function initiated request") 160 case <-time.After(200 * time.Millisecond): 161 } 162 163 // if there is another Request with active context, there should be a request, because the fetcher itself is not cancelled 164 rctx = context.Background() 165 fetcher.Request(rctx) 166 167 select { 168 case <-requester.requestC: 169 case <-time.After(200 * time.Millisecond): 170 t.Fatalf("expected request") 171 } 172 } 173 174 // TestOfferUsesSource tests Fetcher Offer behavior. 175 // In this case there should be 1 (and only one) request initiated from the source peer, and the 176 // source nodeid should appear in the peersToSkip map. 177 func TestFetcherOfferUsesSource(t *testing.T) { 178 requester := newMockRequester(100 * time.Millisecond) 179 addr := make([]byte, 32) 180 fetcher := NewFetcher(addr, requester.doRequest, true) 181 182 peersToSkip := &sync.Map{} 183 184 ctx, cancel := context.WithCancel(context.Background()) 185 defer cancel() 186 187 // start the fetcher 188 go fetcher.run(ctx, peersToSkip) 189 190 rctx := context.Background() 191 // call the Offer function with the source peer 192 fetcher.Offer(rctx, &sourcePeerID) 193 194 // fetcher should not initiate request 195 select { 196 case <-requester.requestC: 197 t.Fatalf("fetcher initiated request") 198 case <-time.After(200 * time.Millisecond): 199 } 200 201 // call Request after the Offer 202 rctx = context.Background() 203 fetcher.Request(rctx) 204 205 // there should be exactly 1 request coming from fetcher 206 var request *Request 207 select { 208 case request = <-requester.requestC: 209 if *request.Source != sourcePeerID { 210 t.Fatalf("Expected source id %v got %v", sourcePeerID, request.Source) 211 } 212 case <-time.After(200 * time.Millisecond): 213 t.Fatalf("fetcher did not initiate request") 214 } 215 216 select { 217 case <-requester.requestC: 218 t.Fatalf("Fetcher number of requests expected 1 got 2") 219 case <-time.After(200 * time.Millisecond): 220 } 221 222 // source peer should be added to peersToSkip eventually 223 time.Sleep(100 * time.Millisecond) 224 if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok { 225 t.Fatalf("SourcePeerId not added to peersToSkip") 226 } 227 } 228 229 func TestFetcherOfferAfterRequestUsesSourceFromContext(t *testing.T) { 230 requester := newMockRequester(100 * time.Millisecond) 231 addr := make([]byte, 32) 232 fetcher := NewFetcher(addr, requester.doRequest, true) 233 234 peersToSkip := &sync.Map{} 235 236 ctx, cancel := context.WithCancel(context.Background()) 237 defer cancel() 238 239 // start the fetcher 240 go fetcher.run(ctx, peersToSkip) 241 242 // call Request first 243 rctx := context.Background() 244 fetcher.Request(rctx) 245 246 // there should be a request coming from fetcher 247 var request *Request 248 select { 249 case request = <-requester.requestC: 250 if request.Source != nil { 251 t.Fatalf("Incorrect source peer id, expected nil got %v", request.Source) 252 } 253 case <-time.After(200 * time.Millisecond): 254 t.Fatalf("fetcher did not initiate request") 255 } 256 257 // after the Request call Offer 258 fetcher.Offer(context.Background(), &sourcePeerID) 259 260 // there should be a request coming from fetcher 261 select { 262 case request = <-requester.requestC: 263 if *request.Source != sourcePeerID { 264 t.Fatalf("Incorrect source peer id, expected %v got %v", sourcePeerID, request.Source) 265 } 266 case <-time.After(200 * time.Millisecond): 267 t.Fatalf("fetcher did not initiate request") 268 } 269 270 // source peer should be added to peersToSkip eventually 271 time.Sleep(100 * time.Millisecond) 272 if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok { 273 t.Fatalf("SourcePeerId not added to peersToSkip") 274 } 275 } 276 277 // TestFetcherRetryOnTimeout tests that fetch retries after searchTimeOut has passed 278 func TestFetcherRetryOnTimeout(t *testing.T) { 279 requester := newMockRequester() 280 addr := make([]byte, 32) 281 fetcher := NewFetcher(addr, requester.doRequest, true) 282 283 peersToSkip := &sync.Map{} 284 285 // set searchTimeOut to low value so the test is quicker 286 defer func(t time.Duration) { 287 searchTimeout = t 288 }(searchTimeout) 289 searchTimeout = 250 * time.Millisecond 290 291 ctx, cancel := context.WithCancel(context.Background()) 292 defer cancel() 293 294 // start the fetcher 295 go fetcher.run(ctx, peersToSkip) 296 297 // call the fetch function with an active context 298 rctx := context.Background() 299 fetcher.Request(rctx) 300 301 // after 100ms the first request should be initiated 302 time.Sleep(100 * time.Millisecond) 303 304 select { 305 case <-requester.requestC: 306 default: 307 t.Fatalf("fetch did not initiate request") 308 } 309 310 // after another 100ms no new request should be initiated, because search timeout is 250ms 311 time.Sleep(100 * time.Millisecond) 312 313 select { 314 case <-requester.requestC: 315 t.Fatalf("unexpected request from fetcher") 316 default: 317 } 318 319 // after another 300ms search timeout is over, there should be a new request 320 time.Sleep(300 * time.Millisecond) 321 322 select { 323 case <-requester.requestC: 324 default: 325 t.Fatalf("fetch did not retry request") 326 } 327 } 328 329 // TestFetcherFactory creates a FetcherFactory and checks if the factory really creates and starts 330 // a Fetcher when it return a fetch function. We test the fetching functionality just by checking if 331 // a request is initiated when the fetch function is called 332 func TestFetcherFactory(t *testing.T) { 333 requester := newMockRequester(100 * time.Millisecond) 334 addr := make([]byte, 32) 335 fetcherFactory := NewFetcherFactory(requester.doRequest, false) 336 337 peersToSkip := &sync.Map{} 338 339 fetcher := fetcherFactory.New(context.Background(), addr, peersToSkip) 340 341 fetcher.Request(context.Background()) 342 343 // check if the created fetchFunction really starts a fetcher and initiates a request 344 select { 345 case <-requester.requestC: 346 case <-time.After(200 * time.Millisecond): 347 t.Fatalf("fetch timeout") 348 } 349 350 } 351 352 func TestFetcherRequestQuitRetriesRequest(t *testing.T) { 353 requester := newMockRequester() 354 addr := make([]byte, 32) 355 fetcher := NewFetcher(addr, requester.doRequest, true) 356 357 // make sure searchTimeout is long so it is sure the request is not retried because of timeout 358 defer func(t time.Duration) { 359 searchTimeout = t 360 }(searchTimeout) 361 searchTimeout = 10 * time.Second 362 363 peersToSkip := &sync.Map{} 364 365 ctx, cancel := context.WithCancel(context.Background()) 366 defer cancel() 367 368 go fetcher.run(ctx, peersToSkip) 369 370 rctx := context.Background() 371 fetcher.Request(rctx) 372 373 select { 374 case <-requester.requestC: 375 case <-time.After(200 * time.Millisecond): 376 t.Fatalf("request is not initiated") 377 } 378 379 close(requester.quitC) 380 381 select { 382 case <-requester.requestC: 383 case <-time.After(200 * time.Millisecond): 384 t.Fatalf("request is not initiated after failed request") 385 } 386 } 387 388 // TestRequestSkipPeer checks if PeerSkip function will skip provided peer 389 // and not skip unknown one. 390 func TestRequestSkipPeer(t *testing.T) { 391 addr := make([]byte, 32) 392 peers := []discover.NodeID{ 393 discover.MustHexID("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 394 discover.MustHexID("2dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 395 } 396 397 peersToSkip := new(sync.Map) 398 peersToSkip.Store(peers[0].String(), time.Now()) 399 r := NewRequest(addr, false, peersToSkip) 400 401 if !r.SkipPeer(peers[0].String()) { 402 t.Errorf("peer not skipped") 403 } 404 405 if r.SkipPeer(peers[1].String()) { 406 t.Errorf("peer skipped") 407 } 408 } 409 410 // TestRequestSkipPeerExpired checks if a peer to skip is not skipped 411 // after RequestTimeout has passed. 412 func TestRequestSkipPeerExpired(t *testing.T) { 413 addr := make([]byte, 32) 414 peer := discover.MustHexID("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439") 415 416 // set RequestTimeout to a low value and reset it after the test 417 defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) 418 RequestTimeout = 250 * time.Millisecond 419 420 peersToSkip := new(sync.Map) 421 peersToSkip.Store(peer.String(), time.Now()) 422 r := NewRequest(addr, false, peersToSkip) 423 424 if !r.SkipPeer(peer.String()) { 425 t.Errorf("peer not skipped") 426 } 427 428 time.Sleep(500 * time.Millisecond) 429 430 if r.SkipPeer(peer.String()) { 431 t.Errorf("peer skipped") 432 } 433 } 434 435 // TestRequestSkipPeerPermanent checks if a peer to skip is not skipped 436 // after RequestTimeout is not skipped if it is set for a permanent skipping 437 // by value to peersToSkip map is not time.Duration. 438 func TestRequestSkipPeerPermanent(t *testing.T) { 439 addr := make([]byte, 32) 440 peer := discover.MustHexID("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439") 441 442 // set RequestTimeout to a low value and reset it after the test 443 defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) 444 RequestTimeout = 250 * time.Millisecond 445 446 peersToSkip := new(sync.Map) 447 peersToSkip.Store(peer.String(), true) 448 r := NewRequest(addr, false, peersToSkip) 449 450 if !r.SkipPeer(peer.String()) { 451 t.Errorf("peer not skipped") 452 } 453 454 time.Sleep(500 * time.Millisecond) 455 456 if !r.SkipPeer(peer.String()) { 457 t.Errorf("peer not skipped") 458 } 459 }