diff --git a/Makefile b/Makefile index f2387d1..f93c41d 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ test: go test -race ./... test-e2e: - go test -mod=readonly --failfast -timeout=25m -v $(PACKAGES_E2E) -count=1 --parallel 12 --tags=e2e + go test -mod=readonly -failfast -timeout=15m -v $(PACKAGES_E2E) -count=1 --parallel 12 --tags=e2e build-docker: $(DOCKER) build --tag babylonlabs-io/vigilante -f Dockerfile \ diff --git a/e2etest/container/container.go b/e2etest/container/container.go index 0fd5106..0b37dbf 100644 --- a/e2etest/container/container.go +++ b/e2etest/container/container.go @@ -5,9 +5,8 @@ import ( "context" "fmt" bbn "github.com/babylonlabs-io/babylon/types" + "github.com/babylonlabs-io/vigilante/testutil" "github.com/btcsuite/btcd/btcec/v2" - "github.com/cometbft/cometbft/libs/rand" - "net" "regexp" "strconv" "testing" @@ -16,7 +15,6 @@ import ( "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" "github.com/stretchr/testify/require" - mrand "math/rand/v2" ) const ( @@ -168,7 +166,7 @@ func (m *Manager) RunBitcoindResource( }, func(config *docker.HostConfig) { config.PortBindings = map[docker.Port][]docker.PortBinding{ - "18443/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, // only expose what we need + "18443/tcp": {{HostIP: "", HostPort: strconv.Itoa(testutil.AllocateUniquePort(t))}}, // only expose what we need } config.PublishAllPorts = false // because in dockerfile they already expose them }, @@ -220,8 +218,8 @@ func (m *Manager) RunBabylondResource( }, func(config *docker.HostConfig) { config.PortBindings = map[docker.Port][]docker.PortBinding{ - "9090/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, - "26657/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, + "9090/tcp": {{HostIP: "", HostPort: strconv.Itoa(testutil.AllocateUniquePort(t))}}, + "26657/tcp": {{HostIP: "", HostPort: strconv.Itoa(testutil.AllocateUniquePort(t))}}, } }, noRestart, @@ -252,38 +250,3 @@ func noRestart(config *docker.HostConfig) { Name: "no", } } - -// randomAvailablePort tries to find an available TCP port on the localhost -// by testing multiple random ports within a specified range. -func randomAvailablePort(t *testing.T) int { - randPort := func(base, spread int) int { - return base + mrand.IntN(spread) - } - - // Base port and spread range for port selection - const ( - basePort = 20000 - portRange = 20000 - ) - - // Seed the random number generator to ensure randomness - rand.Seed(time.Now().UnixNano()) - - // Try up to 10 times to find an available port - for i := 0; i < 10; i++ { - port := randPort(basePort, portRange) - listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) - if err != nil { - continue - } - if err := listener.Close(); err != nil { - continue - } - - return port - } - - // If no available port was found, fail the test - t.Fatalf("failed to find an available port in range %d-%d", basePort, basePort+portRange) - return 0 -} diff --git a/e2etest/reporter_e2e_test.go b/e2etest/reporter_e2e_test.go index 8c74cf8..37b87bd 100644 --- a/e2etest/reporter_e2e_test.go +++ b/e2etest/reporter_e2e_test.go @@ -54,7 +54,7 @@ func (tm *TestManager) GenerateAndSubmitBlockNBlockStartingFromDepth(t *testing. } func TestReporter_BoostrapUnderFrequentBTCHeaders(t *testing.T) { - t.Parallel() + //t.Parallel() // todo(lazar): this test when run in parallel is very flaky, investigate why // no need to much mature outputs, we are not going to submit transactions in this test numMatureOutputs := uint32(150) diff --git a/testutil/port.go b/testutil/port.go new file mode 100644 index 0000000..19ad7f7 --- /dev/null +++ b/testutil/port.go @@ -0,0 +1,61 @@ +package testutil + +import ( + "fmt" + mrand "math/rand/v2" + "net" + "sync" + "testing" +) + +// Track allocated ports, protected by a mutex +var ( + allocatedPorts = make(map[int]struct{}) + portMutex sync.Mutex +) + +// AllocateUniquePort tries to find an available TCP port on the localhost +// by testing multiple random ports within a specified range. +func AllocateUniquePort(t *testing.T) int { + randPort := func(base, spread int) int { + return base + mrand.IntN(spread) + } + + // Base port and spread range for port selection + const ( + basePort = 20000 + portRange = 30000 + ) + + // Try up to 10 times to find an available port + for i := 0; i < 10; i++ { + port := randPort(basePort, portRange) + + // Lock the mutex to check and modify the shared map + portMutex.Lock() + if _, exists := allocatedPorts[port]; exists { + // Port already allocated, try another one + portMutex.Unlock() + continue + } + + listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) + if err != nil { + portMutex.Unlock() + continue + } + + allocatedPorts[port] = struct{}{} + portMutex.Unlock() + + if err := listener.Close(); err != nil { + continue + } + + return port + } + + // If no available port was found, fail the test + t.Fatalf("failed to find an available port in range %d-%d", basePort, basePort+portRange) + return 0 +}