github.com/luckypickle/go-ethereum-vet@v1.14.2/les/freeclient_test.go (about)

     1  // Copyright 2017 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 light implements on-demand retrieval capable state and chain objects
    18  // for the Ethereum Light Client.
    19  package les
    20  
    21  import (
    22  	"fmt"
    23  	"math/rand"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/luckypickle/go-ethereum-vet/common/mclock"
    28  	"github.com/luckypickle/go-ethereum-vet/ethdb"
    29  )
    30  
    31  func TestFreeClientPoolL10C100(t *testing.T) {
    32  	testFreeClientPool(t, 10, 100)
    33  }
    34  
    35  func TestFreeClientPoolL40C200(t *testing.T) {
    36  	testFreeClientPool(t, 40, 200)
    37  }
    38  
    39  func TestFreeClientPoolL100C300(t *testing.T) {
    40  	testFreeClientPool(t, 100, 300)
    41  }
    42  
    43  const testFreeClientPoolTicks = 500000
    44  
    45  func testFreeClientPool(t *testing.T, connLimit, clientCount int) {
    46  	var (
    47  		clock     mclock.Simulated
    48  		db        = ethdb.NewMemDatabase()
    49  		pool      = newFreeClientPool(db, connLimit, 10000, &clock)
    50  		connected = make([]bool, clientCount)
    51  		connTicks = make([]int, clientCount)
    52  		disconnCh = make(chan int, clientCount)
    53  	)
    54  	peerId := func(i int) string {
    55  		return fmt.Sprintf("test peer #%d", i)
    56  	}
    57  	disconnFn := func(i int) func() {
    58  		return func() {
    59  			disconnCh <- i
    60  		}
    61  	}
    62  
    63  	// pool should accept new peers up to its connected limit
    64  	for i := 0; i < connLimit; i++ {
    65  		if pool.connect(peerId(i), disconnFn(i)) {
    66  			connected[i] = true
    67  		} else {
    68  			t.Fatalf("Test peer #%d rejected", i)
    69  		}
    70  	}
    71  	// since all accepted peers are new and should not be kicked out, the next one should be rejected
    72  	if pool.connect(peerId(connLimit), disconnFn(connLimit)) {
    73  		connected[connLimit] = true
    74  		t.Fatalf("Peer accepted over connected limit")
    75  	}
    76  
    77  	// randomly connect and disconnect peers, expect to have a similar total connection time at the end
    78  	for tickCounter := 0; tickCounter < testFreeClientPoolTicks; tickCounter++ {
    79  		clock.Run(1 * time.Second)
    80  
    81  		i := rand.Intn(clientCount)
    82  		if connected[i] {
    83  			pool.disconnect(peerId(i))
    84  			connected[i] = false
    85  			connTicks[i] += tickCounter
    86  		} else {
    87  			if pool.connect(peerId(i), disconnFn(i)) {
    88  				connected[i] = true
    89  				connTicks[i] -= tickCounter
    90  			}
    91  		}
    92  	pollDisconnects:
    93  		for {
    94  			select {
    95  			case i := <-disconnCh:
    96  				pool.disconnect(peerId(i))
    97  				if connected[i] {
    98  					connTicks[i] += tickCounter
    99  					connected[i] = false
   100  				}
   101  			default:
   102  				break pollDisconnects
   103  			}
   104  		}
   105  	}
   106  
   107  	expTicks := testFreeClientPoolTicks * connLimit / clientCount
   108  	expMin := expTicks - expTicks/10
   109  	expMax := expTicks + expTicks/10
   110  
   111  	// check if the total connected time of peers are all in the expected range
   112  	for i, c := range connected {
   113  		if c {
   114  			connTicks[i] += testFreeClientPoolTicks
   115  		}
   116  		if connTicks[i] < expMin || connTicks[i] > expMax {
   117  			t.Errorf("Total connected time of test node #%d (%d) outside expected range (%d to %d)", i, connTicks[i], expMin, expMax)
   118  		}
   119  	}
   120  
   121  	// a previously unknown peer should be accepted now
   122  	if !pool.connect("newPeer", func() {}) {
   123  		t.Fatalf("Previously unknown peer rejected")
   124  	}
   125  
   126  	// close and restart pool
   127  	pool.stop()
   128  	pool = newFreeClientPool(db, connLimit, 10000, &clock)
   129  
   130  	// try connecting all known peers (connLimit should be filled up)
   131  	for i := 0; i < clientCount; i++ {
   132  		pool.connect(peerId(i), func() {})
   133  	}
   134  	// expect pool to remember known nodes and kick out one of them to accept a new one
   135  	if !pool.connect("newPeer2", func() {}) {
   136  		t.Errorf("Previously unknown peer rejected after restarting pool")
   137  	}
   138  	pool.stop()
   139  }