swarm: prevent forever running retrieve request loops
This commit is contained in:
		
				
					committed by
					
						
						Janos Guljas
					
				
			
			
				
	
			
			
			
						parent
						
							d3441ebb56
						
					
				
				
					commit
					3f7acbbeb9
				
			@@ -33,7 +33,7 @@ type mockRequester struct {
 | 
			
		||||
	// requests []Request
 | 
			
		||||
	requestC  chan *Request   // when a request is coming it is pushed to requestC
 | 
			
		||||
	waitTimes []time.Duration // with waitTimes[i] you can define how much to wait on the ith request (optional)
 | 
			
		||||
	ctr       int             //counts the number of requests
 | 
			
		||||
	count     int             //counts the number of requests
 | 
			
		||||
	quitC     chan struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -47,9 +47,9 @@ func newMockRequester(waitTimes ...time.Duration) *mockRequester {
 | 
			
		||||
 | 
			
		||||
func (m *mockRequester) doRequest(ctx context.Context, request *Request) (*enode.ID, chan struct{}, error) {
 | 
			
		||||
	waitTime := time.Duration(0)
 | 
			
		||||
	if m.ctr < len(m.waitTimes) {
 | 
			
		||||
		waitTime = m.waitTimes[m.ctr]
 | 
			
		||||
		m.ctr++
 | 
			
		||||
	if m.count < len(m.waitTimes) {
 | 
			
		||||
		waitTime = m.waitTimes[m.count]
 | 
			
		||||
		m.count++
 | 
			
		||||
	}
 | 
			
		||||
	time.Sleep(waitTime)
 | 
			
		||||
	m.requestC <- request
 | 
			
		||||
@@ -83,7 +83,7 @@ func TestFetcherSingleRequest(t *testing.T) {
 | 
			
		||||
	go fetcher.run(ctx, peersToSkip)
 | 
			
		||||
 | 
			
		||||
	rctx := context.Background()
 | 
			
		||||
	fetcher.Request(rctx)
 | 
			
		||||
	fetcher.Request(rctx, 0)
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case request := <-requester.requestC:
 | 
			
		||||
@@ -100,6 +100,11 @@ func TestFetcherSingleRequest(t *testing.T) {
 | 
			
		||||
			t.Fatalf("request.peersToSkip does not contain peer returned by the request function")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// hopCount in the forwarded request should be incremented
 | 
			
		||||
		if request.HopCount != 1 {
 | 
			
		||||
			t.Fatalf("Expected request.HopCount 1 got %v", request.HopCount)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// fetch should trigger a request, if it doesn't happen in time, test should fail
 | 
			
		||||
	case <-time.After(200 * time.Millisecond):
 | 
			
		||||
		t.Fatalf("fetch timeout")
 | 
			
		||||
@@ -123,7 +128,7 @@ func TestFetcherCancelStopsFetcher(t *testing.T) {
 | 
			
		||||
	rctx, rcancel := context.WithTimeout(ctx, 100*time.Millisecond)
 | 
			
		||||
	defer rcancel()
 | 
			
		||||
	// we call Request with an active context
 | 
			
		||||
	fetcher.Request(rctx)
 | 
			
		||||
	fetcher.Request(rctx, 0)
 | 
			
		||||
 | 
			
		||||
	// fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening
 | 
			
		||||
	select {
 | 
			
		||||
@@ -151,7 +156,7 @@ func TestFetcherCancelStopsRequest(t *testing.T) {
 | 
			
		||||
	rcancel()
 | 
			
		||||
 | 
			
		||||
	// we call Request with a cancelled context
 | 
			
		||||
	fetcher.Request(rctx)
 | 
			
		||||
	fetcher.Request(rctx, 0)
 | 
			
		||||
 | 
			
		||||
	// fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening
 | 
			
		||||
	select {
 | 
			
		||||
@@ -162,7 +167,7 @@ func TestFetcherCancelStopsRequest(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	// if there is another Request with active context, there should be a request, because the fetcher itself is not cancelled
 | 
			
		||||
	rctx = context.Background()
 | 
			
		||||
	fetcher.Request(rctx)
 | 
			
		||||
	fetcher.Request(rctx, 0)
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-requester.requestC:
 | 
			
		||||
@@ -200,7 +205,7 @@ func TestFetcherOfferUsesSource(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	// call Request after the Offer
 | 
			
		||||
	rctx = context.Background()
 | 
			
		||||
	fetcher.Request(rctx)
 | 
			
		||||
	fetcher.Request(rctx, 0)
 | 
			
		||||
 | 
			
		||||
	// there should be exactly 1 request coming from fetcher
 | 
			
		||||
	var request *Request
 | 
			
		||||
@@ -241,7 +246,7 @@ func TestFetcherOfferAfterRequestUsesSourceFromContext(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	// call Request first
 | 
			
		||||
	rctx := context.Background()
 | 
			
		||||
	fetcher.Request(rctx)
 | 
			
		||||
	fetcher.Request(rctx, 0)
 | 
			
		||||
 | 
			
		||||
	// there should be a request coming from fetcher
 | 
			
		||||
	var request *Request
 | 
			
		||||
@@ -296,7 +301,7 @@ func TestFetcherRetryOnTimeout(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	// call the fetch function with an active context
 | 
			
		||||
	rctx := context.Background()
 | 
			
		||||
	fetcher.Request(rctx)
 | 
			
		||||
	fetcher.Request(rctx, 0)
 | 
			
		||||
 | 
			
		||||
	// after 100ms the first request should be initiated
 | 
			
		||||
	time.Sleep(100 * time.Millisecond)
 | 
			
		||||
@@ -338,7 +343,7 @@ func TestFetcherFactory(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	fetcher := fetcherFactory.New(context.Background(), addr, peersToSkip)
 | 
			
		||||
 | 
			
		||||
	fetcher.Request(context.Background())
 | 
			
		||||
	fetcher.Request(context.Background(), 0)
 | 
			
		||||
 | 
			
		||||
	// check if the created fetchFunction really starts a fetcher and initiates a request
 | 
			
		||||
	select {
 | 
			
		||||
@@ -368,7 +373,7 @@ func TestFetcherRequestQuitRetriesRequest(t *testing.T) {
 | 
			
		||||
	go fetcher.run(ctx, peersToSkip)
 | 
			
		||||
 | 
			
		||||
	rctx := context.Background()
 | 
			
		||||
	fetcher.Request(rctx)
 | 
			
		||||
	fetcher.Request(rctx, 0)
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-requester.requestC:
 | 
			
		||||
@@ -457,3 +462,26 @@ func TestRequestSkipPeerPermanent(t *testing.T) {
 | 
			
		||||
		t.Errorf("peer not skipped")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestFetcherMaxHopCount(t *testing.T) {
 | 
			
		||||
	requester := newMockRequester()
 | 
			
		||||
	addr := make([]byte, 32)
 | 
			
		||||
	fetcher := NewFetcher(addr, requester.doRequest, true)
 | 
			
		||||
 | 
			
		||||
	ctx, cancel := context.WithCancel(context.Background())
 | 
			
		||||
	defer cancel()
 | 
			
		||||
 | 
			
		||||
	peersToSkip := &sync.Map{}
 | 
			
		||||
 | 
			
		||||
	go fetcher.run(ctx, peersToSkip)
 | 
			
		||||
 | 
			
		||||
	rctx := context.Background()
 | 
			
		||||
	fetcher.Request(rctx, maxHopCount)
 | 
			
		||||
 | 
			
		||||
	// if hopCount is already at max no request should be initiated
 | 
			
		||||
	select {
 | 
			
		||||
	case <-requester.requestC:
 | 
			
		||||
		t.Fatalf("cancelled fetcher initiated request")
 | 
			
		||||
	case <-time.After(200 * time.Millisecond):
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user