Skip to content

Commit

Permalink
Generate different ports for each integration test net. (#356)
Browse files Browse the repository at this point in the history
* Generate different ports for each integration test net.

* Fix issue with client port.

* Fix test that failed after port changes:

- client needed to be regenerated
- contract binding object needs to be re-bound using new client.
  • Loading branch information
LuisPH3 authored Nov 28, 2024
1 parent 8623f6a commit 74f97ac
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 22 deletions.
25 changes: 15 additions & 10 deletions tests/block_header_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,21 @@ func testBlockHeadersOnNetwork(t *testing.T, net *IntegrationTestNet) {
}
counterAddress := receipt.ContractAddress

client, err := net.GetClient()
require.NoError(err)
defer client.Close()

originalHeaders, err := net.GetHeaders()
require.NoError(err)
originalHashes := []common.Hash{}
for _, header := range originalHeaders {
originalHashes = append(originalHashes, header.Hash())
}

runTests := func() {
runTests := func(t *testing.T) {
headers, err := net.GetHeaders()
require.NoError(err)

client, err := net.GetClient()
require.NoError(err)
defer client.Close()

t.Run("CompareHeaderHashes", func(t *testing.T) {
testHeaders_CompareHeaderHashes(t, originalHashes, headers)
})
Expand Down Expand Up @@ -159,15 +159,17 @@ func testBlockHeadersOnNetwork(t *testing.T, net *IntegrationTestNet) {
})

t.Run("CounterStateIsVerifiable", func(t *testing.T) {
testHeaders_CounterStateIsVerifiable(t, headers, client, counter, counterAddress)
testHeaders_CounterStateIsVerifiable(t, headers, client, counterAddress)
})
}

runTests()
t.Run("BeforeRestart", runTests)

require.NoError(net.Restart())
runTests()
t.Run("AfterRestart", runTests)

require.NoError(net.RestartWithExportImport())
runTests()
t.Run("AfterImport", runTests)
}

func testHeaders_CompareHeaderHashes(t *testing.T, hashes []common.Hash, newHeaders []*types.Header) {
Expand Down Expand Up @@ -587,10 +589,13 @@ func testHeaders_CounterStateIsVerifiable(
t *testing.T,
headers []*types.Header,
client *ethclient.Client,
counter *counter_event_emitter.CounterEventEmitter,
counterAddress common.Address,
) {
require := require.New(t)

counter, err := counter_event_emitter.NewCounterEventEmitter(counterAddress, client)
require.NoError(err, "failed to instantiate contract")

fromLogs := 0
for i, header := range headers {

Expand Down
83 changes: 71 additions & 12 deletions tests/integration_test_net.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import (
"encoding/json"
"errors"
"fmt"
"math"
"math/big"
"math/rand/v2"
"net"
"os"
"path/filepath"
"syscall"
Expand Down Expand Up @@ -55,9 +58,32 @@ import (
// integration test networks can also be used for automated integration and
// regression tests for client code.
type IntegrationTestNet struct {
directory string
done <-chan struct{}
validator Account
directory string
done <-chan struct{}
validator Account
httpClientPort int
}

func isPortFree(host string, port int) bool {
address := fmt.Sprintf("%s:%d", host, port)
listener, err := net.Listen("tcp", address)
if err != nil {
return false
}
listener.Close()
return true
}

func getFreePort() (int, error) {
var port int
retries := 10
for i := 0; i < retries; i++ {
port = 1023 + (rand.Int()%math.MaxUint16 - 1023)
if isPortFree("127.0.0.1", port) {
return port, nil
}
}
return 0, fmt.Errorf("failed to find a free port after %d retries (last %d)", retries, port)
}

// StartIntegrationTestNet starts a single-node test network for integration tests.
Expand Down Expand Up @@ -197,29 +223,62 @@ func (n *IntegrationTestNet) start() error {
if n.done != nil {
return errors.New("network already started")
}

// find free ports for the http-client, ws-client, and network interfaces
var err error
n.httpClientPort, err = getFreePort()
if err != nil {
return err
}
wsPort, err := getFreePort()
if err != nil {
return err
}
netPort, err := getFreePort()
if err != nil {
return err
}

done := make(chan struct{})
go func() {
defer close(done)
originalArgs := os.Args
defer func() { os.Args = originalArgs }()

// start the fakenet sonic node
// equivalent to running `sonicd ...` but in this local process
os.Args = []string{
"sonicd",

// data storage options
"--datadir", n.stateDir(),
"--datadir.minfreedisk", "0",

// fake network options
"--fakenet", "1/1",
"--http",
"--http.addr", "0.0.0.0",
"--http.port", "18545",

// http-client option
"--http", "--http.addr", "127.0.0.1", "--http.port", fmt.Sprint(n.httpClientPort),
"--http.api", "admin,eth,web3,net,txpool,ftm,trace,debug",
"--ws",
"--ws.addr", "0.0.0.0",
"--ws.port", "18546",

// websocket-client options
"--ws", "--ws.addr", "127.0.0.1", "--ws.port", fmt.Sprint(wsPort),
"--ws.api", "admin,eth,ftm",
"--datadir.minfreedisk", "0",

// net options
"--port", fmt.Sprint(netPort),
"--nat", "none",
"--nodiscover",

// database memory usage options
"--statedb.livecache", "1",
"--statedb.archivecache", "1",
}
sonicd.Run()

err := sonicd.Run()
if err != nil {
panic(fmt.Sprint("Failed to start the fake network:", err))
}
}()

n.done = done
Expand Down Expand Up @@ -411,7 +470,7 @@ func (n *IntegrationTestNet) GetTransactOptions(account *Account) (*bind.Transac
// GetClient provides raw access to a fresh connection to the network.
// The resulting client must be closed after use.
func (n *IntegrationTestNet) GetClient() (*ethclient.Client, error) {
return ethclient.Dial("http://localhost:18545")
return ethclient.Dial(fmt.Sprintf("http://localhost:%d", n.httpClientPort))
}

// RestartWithExportImport stops the network, exports the genesis file, cleans the
Expand Down

0 comments on commit 74f97ac

Please sign in to comment.