github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/network/fetcher_test.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:43</date> 10 //</624450113661571072> 11 12 13 package network 14 15 import ( 16 "context" 17 "sync" 18 "testing" 19 "time" 20 21 "github.com/ethereum/go-ethereum/p2p/enode" 22 ) 23 24 var requestedPeerID = enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") 25 var sourcePeerID = enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9") 26 27 //mockrequester在调用其dorequest函数时将每个请求推送到requestc通道 28 type mockRequester struct { 29 //请求[]请求 30 requestC chan *Request //当一个请求到来时,它被推送到请求C 31 waitTimes []time.Duration //使用waittimes[i]可以定义在第i个请求上等待的时间(可选) 32 count int //统计请求数 33 quitC chan struct{} 34 } 35 36 func newMockRequester(waitTimes ...time.Duration) *mockRequester { 37 return &mockRequester{ 38 requestC: make(chan *Request), 39 waitTimes: waitTimes, 40 quitC: make(chan struct{}), 41 } 42 } 43 44 func (m *mockRequester) doRequest(ctx context.Context, request *Request) (*enode.ID, chan struct{}, error) { 45 waitTime := time.Duration(0) 46 if m.count < len(m.waitTimes) { 47 waitTime = m.waitTimes[m.count] 48 m.count++ 49 } 50 time.Sleep(waitTime) 51 m.requestC <- request 52 53 //如果请求中存在源,请使用该源,如果不使用全局requestedpeerid 54 source := request.Source 55 if source == nil { 56 source = &requestedPeerID 57 } 58 return source, m.quitC, nil 59 } 60 61 //testwithersinglerequest使用mockrequester创建一个取数器,并使用一组要跳过的对等方来运行它。 62 //mockrequester每次调用请求函数时都在通道上推送请求。使用 63 //这个通道我们测试调用fetcher.request是否调用request函数,以及它是否使用 64 //我们为fetcher.run函数提供的要跳过的正确对等点。 65 func TestFetcherSingleRequest(t *testing.T) { 66 requester := newMockRequester() 67 addr := make([]byte, 32) 68 fetcher := NewFetcher(addr, requester.doRequest, true) 69 70 peers := []string{"a", "b", "c", "d"} 71 peersToSkip := &sync.Map{} 72 for _, p := range peers { 73 peersToSkip.Store(p, time.Now()) 74 } 75 76 ctx, cancel := context.WithCancel(context.Background()) 77 defer cancel() 78 79 go fetcher.run(ctx, peersToSkip) 80 81 rctx := context.Background() 82 fetcher.Request(rctx, 0) 83 84 select { 85 case request := <-requester.requestC: 86 //请求应包含从PeersToSkip提供给获取程序的所有对等方 87 for _, p := range peers { 88 if _, ok := request.peersToSkip.Load(p); !ok { 89 t.Fatalf("request.peersToSkip misses peer") 90 } 91 } 92 93 //源对等端最终也应添加到对等端跳过 94 time.Sleep(100 * time.Millisecond) 95 if _, ok := request.peersToSkip.Load(requestedPeerID.String()); !ok { 96 t.Fatalf("request.peersToSkip does not contain peer returned by the request function") 97 } 98 99 //转发请求中的跃点计数应递增 100 if request.HopCount != 1 { 101 t.Fatalf("Expected request.HopCount 1 got %v", request.HopCount) 102 } 103 104 //fetch应该触发一个请求,如果它没有及时发生,测试应该失败。 105 case <-time.After(200 * time.Millisecond): 106 t.Fatalf("fetch timeout") 107 } 108 } 109 110 //testCancelStopsFetcher测试已取消的获取程序即使调用了其获取函数,也不会启动进一步的请求。 111 func TestFetcherCancelStopsFetcher(t *testing.T) { 112 requester := newMockRequester() 113 addr := make([]byte, 32) 114 fetcher := NewFetcher(addr, requester.doRequest, true) 115 116 peersToSkip := &sync.Map{} 117 118 ctx, cancel := context.WithCancel(context.Background()) 119 120 //我们启动提取程序,然后立即取消上下文 121 go fetcher.run(ctx, peersToSkip) 122 cancel() 123 124 rctx, rcancel := context.WithTimeout(ctx, 100*time.Millisecond) 125 defer rcancel() 126 //我们使用活动上下文调用请求 127 fetcher.Request(rctx, 0) 128 129 //回取器不应该启动请求,我们只能通过等待一点并确保没有发生请求来进行检查。 130 select { 131 case <-requester.requestC: 132 t.Fatalf("cancelled fetcher initiated request") 133 case <-time.After(200 * time.Millisecond): 134 } 135 } 136 137 //TestFetchCancelStopsRequest测试使用已取消的上下文调用请求函数不会启动请求 138 func TestFetcherCancelStopsRequest(t *testing.T) { 139 requester := newMockRequester(100 * time.Millisecond) 140 addr := make([]byte, 32) 141 fetcher := NewFetcher(addr, requester.doRequest, true) 142 143 peersToSkip := &sync.Map{} 144 145 ctx, cancel := context.WithCancel(context.Background()) 146 defer cancel() 147 148 //我们使用活动上下文启动提取程序 149 go fetcher.run(ctx, peersToSkip) 150 151 rctx, rcancel := context.WithCancel(context.Background()) 152 rcancel() 153 154 //我们用取消的上下文调用请求 155 fetcher.Request(rctx, 0) 156 157 //回取器不应该启动请求,我们只能通过等待一点并确保没有发生请求来进行检查。 158 select { 159 case <-requester.requestC: 160 t.Fatalf("cancelled fetch function initiated request") 161 case <-time.After(200 * time.Millisecond): 162 } 163 164 //如果有另一个具有活动上下文的请求,则应该有一个请求,因为提取程序本身没有被取消。 165 rctx = context.Background() 166 fetcher.Request(rctx, 0) 167 168 select { 169 case <-requester.requestC: 170 case <-time.After(200 * time.Millisecond): 171 t.Fatalf("expected request") 172 } 173 } 174 175 //TestOfferUsesSource测试获取器提供行为。 176 //在这种情况下,应该有1个(并且只有一个)来自源对等端的请求,并且 177 //源节点ID应出现在PeerStoskip映射中。 178 func TestFetcherOfferUsesSource(t *testing.T) { 179 requester := newMockRequester(100 * time.Millisecond) 180 addr := make([]byte, 32) 181 fetcher := NewFetcher(addr, requester.doRequest, true) 182 183 peersToSkip := &sync.Map{} 184 185 ctx, cancel := context.WithCancel(context.Background()) 186 defer cancel() 187 188 //启动取纸器 189 go fetcher.run(ctx, peersToSkip) 190 191 rctx := context.Background() 192 //使用源对等调用offer函数 193 fetcher.Offer(rctx, &sourcePeerID) 194 195 //提取程序不应启动请求 196 select { 197 case <-requester.requestC: 198 t.Fatalf("fetcher initiated request") 199 case <-time.After(200 * time.Millisecond): 200 } 201 202 //报价后的呼叫请求 203 rctx = context.Background() 204 fetcher.Request(rctx, 0) 205 206 //从取数器中应该正好有一个请求 207 var request *Request 208 select { 209 case request = <-requester.requestC: 210 if *request.Source != sourcePeerID { 211 t.Fatalf("Expected source id %v got %v", sourcePeerID, request.Source) 212 } 213 case <-time.After(200 * time.Millisecond): 214 t.Fatalf("fetcher did not initiate request") 215 } 216 217 select { 218 case <-requester.requestC: 219 t.Fatalf("Fetcher number of requests expected 1 got 2") 220 case <-time.After(200 * time.Millisecond): 221 } 222 223 //源对等端最终应添加到对等端跳过 224 time.Sleep(100 * time.Millisecond) 225 if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok { 226 t.Fatalf("SourcePeerId not added to peersToSkip") 227 } 228 } 229 230 func TestFetcherOfferAfterRequestUsesSourceFromContext(t *testing.T) { 231 requester := newMockRequester(100 * time.Millisecond) 232 addr := make([]byte, 32) 233 fetcher := NewFetcher(addr, requester.doRequest, true) 234 235 peersToSkip := &sync.Map{} 236 237 ctx, cancel := context.WithCancel(context.Background()) 238 defer cancel() 239 240 //启动取纸器 241 go fetcher.run(ctx, peersToSkip) 242 243 //先呼叫请求 244 rctx := context.Background() 245 fetcher.Request(rctx, 0) 246 247 //应该有一个来自回迁者的请求 248 var request *Request 249 select { 250 case request = <-requester.requestC: 251 if request.Source != nil { 252 t.Fatalf("Incorrect source peer id, expected nil got %v", request.Source) 253 } 254 case <-time.After(200 * time.Millisecond): 255 t.Fatalf("fetcher did not initiate request") 256 } 257 258 //请求后呼叫提供 259 fetcher.Offer(context.Background(), &sourcePeerID) 260 261 //应该有一个来自回迁者的请求 262 select { 263 case request = <-requester.requestC: 264 if *request.Source != sourcePeerID { 265 t.Fatalf("Incorrect source peer id, expected %v got %v", sourcePeerID, request.Source) 266 } 267 case <-time.After(200 * time.Millisecond): 268 t.Fatalf("fetcher did not initiate request") 269 } 270 271 //源对等端最终应添加到对等端跳过 272 time.Sleep(100 * time.Millisecond) 273 if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok { 274 t.Fatalf("SourcePeerId not added to peersToSkip") 275 } 276 } 277 278 //TestFetcherRetryOnTimeout测试在SearchTimeout通过后获取重试 279 func TestFetcherRetryOnTimeout(t *testing.T) { 280 requester := newMockRequester() 281 addr := make([]byte, 32) 282 fetcher := NewFetcher(addr, requester.doRequest, true) 283 //将SearchTimeout设置为低值,以便测试更快 284 fetcher.searchTimeout = 250 * time.Millisecond 285 286 peersToSkip := &sync.Map{} 287 288 ctx, cancel := context.WithCancel(context.Background()) 289 defer cancel() 290 291 //启动取纸器 292 go fetcher.run(ctx, peersToSkip) 293 294 //使用活动上下文调用fetch函数 295 rctx := context.Background() 296 fetcher.Request(rctx, 0) 297 298 //100毫秒后,应启动第一个请求 299 time.Sleep(100 * time.Millisecond) 300 301 select { 302 case <-requester.requestC: 303 default: 304 t.Fatalf("fetch did not initiate request") 305 } 306 307 //再过100毫秒后,不应启动新的请求,因为搜索超时为250毫秒。 308 time.Sleep(100 * time.Millisecond) 309 310 select { 311 case <-requester.requestC: 312 t.Fatalf("unexpected request from fetcher") 313 default: 314 } 315 316 //在另一个300ms搜索超时结束后,应该有一个新的请求 317 time.Sleep(300 * time.Millisecond) 318 319 select { 320 case <-requester.requestC: 321 default: 322 t.Fatalf("fetch did not retry request") 323 } 324 } 325 326 //TestFetcherFactory创建一个FetcherFactory并检查工厂是否真正创建并启动 327 //回迁函数时的回迁函数。我们只需检查 328 //调用FETCH函数时启动请求 329 func TestFetcherFactory(t *testing.T) { 330 requester := newMockRequester(100 * time.Millisecond) 331 addr := make([]byte, 32) 332 fetcherFactory := NewFetcherFactory(requester.doRequest, false) 333 334 peersToSkip := &sync.Map{} 335 336 fetcher := fetcherFactory.New(context.Background(), addr, peersToSkip) 337 338 fetcher.Request(context.Background(), 0) 339 340 //检查创建的fetchFunction是否真的启动了一个fetcher并启动了一个请求 341 select { 342 case <-requester.requestC: 343 case <-time.After(200 * time.Millisecond): 344 t.Fatalf("fetch timeout") 345 } 346 347 } 348 349 func TestFetcherRequestQuitRetriesRequest(t *testing.T) { 350 requester := newMockRequester() 351 addr := make([]byte, 32) 352 fetcher := NewFetcher(addr, requester.doRequest, true) 353 354 //确保SearchTimeout很长,以确保请求不是 355 //由于超时而重试 356 fetcher.searchTimeout = 10 * time.Second 357 358 peersToSkip := &sync.Map{} 359 360 ctx, cancel := context.WithCancel(context.Background()) 361 defer cancel() 362 363 go fetcher.run(ctx, peersToSkip) 364 365 rctx := context.Background() 366 fetcher.Request(rctx, 0) 367 368 select { 369 case <-requester.requestC: 370 case <-time.After(200 * time.Millisecond): 371 t.Fatalf("request is not initiated") 372 } 373 374 close(requester.quitC) 375 376 select { 377 case <-requester.requestC: 378 case <-time.After(200 * time.Millisecond): 379 t.Fatalf("request is not initiated after failed request") 380 } 381 } 382 383 //testRequestSkipper检查peerSkip函数是否将跳过提供的peer 384 //不要跳过未知的。 385 func TestRequestSkipPeer(t *testing.T) { 386 addr := make([]byte, 32) 387 peers := []enode.ID{ 388 enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8"), 389 enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9"), 390 } 391 392 peersToSkip := new(sync.Map) 393 peersToSkip.Store(peers[0].String(), time.Now()) 394 r := NewRequest(addr, false, peersToSkip) 395 396 if !r.SkipPeer(peers[0].String()) { 397 t.Errorf("peer not skipped") 398 } 399 400 if r.SkipPeer(peers[1].String()) { 401 t.Errorf("peer skipped") 402 } 403 } 404 405 //testRequestSkipperExpired检查是否未跳过要跳过的对等机 406 //请求超时之后。 407 func TestRequestSkipPeerExpired(t *testing.T) { 408 addr := make([]byte, 32) 409 peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") 410 411 //将requestTimeout设置为低值,并在测试后重置它 412 defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) 413 RequestTimeout = 250 * time.Millisecond 414 415 peersToSkip := new(sync.Map) 416 peersToSkip.Store(peer.String(), time.Now()) 417 r := NewRequest(addr, false, peersToSkip) 418 419 if !r.SkipPeer(peer.String()) { 420 t.Errorf("peer not skipped") 421 } 422 423 time.Sleep(500 * time.Millisecond) 424 425 if r.SkipPeer(peer.String()) { 426 t.Errorf("peer skipped") 427 } 428 } 429 430 //testRequestSkipperPermanent检查是否跳过要跳过的对等机 431 //如果设置为永久跳过,则不会跳过请求超时之后 432 //按值到PeersToSkip映射不是Time.Duration。 433 func TestRequestSkipPeerPermanent(t *testing.T) { 434 addr := make([]byte, 32) 435 peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") 436 437 //将requestTimeout设置为低值,并在测试后重置它 438 defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) 439 RequestTimeout = 250 * time.Millisecond 440 441 peersToSkip := new(sync.Map) 442 peersToSkip.Store(peer.String(), true) 443 r := NewRequest(addr, false, peersToSkip) 444 445 if !r.SkipPeer(peer.String()) { 446 t.Errorf("peer not skipped") 447 } 448 449 time.Sleep(500 * time.Millisecond) 450 451 if !r.SkipPeer(peer.String()) { 452 t.Errorf("peer not skipped") 453 } 454 } 455 456 func TestFetcherMaxHopCount(t *testing.T) { 457 requester := newMockRequester() 458 addr := make([]byte, 32) 459 fetcher := NewFetcher(addr, requester.doRequest, true) 460 461 ctx, cancel := context.WithCancel(context.Background()) 462 defer cancel() 463 464 peersToSkip := &sync.Map{} 465 466 go fetcher.run(ctx, peersToSkip) 467 468 rctx := context.Background() 469 fetcher.Request(rctx, maxHopCount) 470 471 //如果HopCount已达到最大值,则不应启动任何请求。 472 select { 473 case <-requester.requestC: 474 t.Fatalf("cancelled fetcher initiated request") 475 case <-time.After(200 * time.Millisecond): 476 } 477 } 478