Skip to content

Commit eba8cd7

Browse files
authored
chore: consolidate various randomPort() implementations (#12362)
Consolidates our existing randomPort() implementations to package testutil
1 parent 4f87ba4 commit eba8cd7

File tree

6 files changed

+52
-42
lines changed

6 files changed

+52
-42
lines changed

agent/agent_test.go

+1-16
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"errors"
99
"fmt"
1010
"io"
11-
"math/rand"
1211
"net"
1312
"net/http"
1413
"net/http/httptest"
@@ -838,7 +837,7 @@ func TestAgent_TCPRemoteForwarding(t *testing.T) {
838837
var ll net.Listener
839838
var err error
840839
for {
841-
randomPort = pickRandomPort()
840+
randomPort = testutil.RandomPortNoListen(t)
842841
addr := net.TCPAddrFromAddrPort(netip.AddrPortFrom(localhost, randomPort))
843842
ll, err = sshClient.ListenTCP(addr)
844843
if err != nil {
@@ -2666,20 +2665,6 @@ func (s *syncWriter) Write(p []byte) (int, error) {
26662665
return s.w.Write(p)
26672666
}
26682667

2669-
// pickRandomPort picks a random port number for the ephemeral range. We do this entirely randomly
2670-
// instead of opening a listener and closing it to find a port that is likely to be free, since
2671-
// sometimes the OS reallocates the port very quickly.
2672-
func pickRandomPort() uint16 {
2673-
const (
2674-
// Overlap of windows, linux in https://en.wikipedia.org/wiki/Ephemeral_port
2675-
min = 49152
2676-
max = 60999
2677-
)
2678-
n := max - min
2679-
x := rand.Intn(n) //nolint: gosec
2680-
return uint16(min + x)
2681-
}
2682-
26832668
// echoOnce accepts a single connection, reads 4 bytes and echos them back
26842669
func echoOnce(t *testing.T, ll net.Listener) {
26852670
t.Helper()

cli/server_test.go

+2-11
Original file line numberDiff line numberDiff line change
@@ -937,22 +937,13 @@ func TestServer(t *testing.T) {
937937
t.Run("Prometheus", func(t *testing.T) {
938938
t.Parallel()
939939

940-
randomPort := func(t *testing.T) int {
941-
random, err := net.Listen("tcp", "127.0.0.1:0")
942-
require.NoError(t, err)
943-
_ = random.Close()
944-
tcpAddr, valid := random.Addr().(*net.TCPAddr)
945-
require.True(t, valid)
946-
return tcpAddr.Port
947-
}
948-
949940
t.Run("DBMetricsDisabled", func(t *testing.T) {
950941
t.Parallel()
951942

952943
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
953944
defer cancel()
954945

955-
randPort := randomPort(t)
946+
randPort := testutil.RandomPort(t)
956947
inv, cfg := clitest.New(t,
957948
"server",
958949
"--in-memory",
@@ -1008,7 +999,7 @@ func TestServer(t *testing.T) {
1008999
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
10091000
defer cancel()
10101001

1011-
randPort := randomPort(t)
1002+
randPort := testutil.RandomPort(t)
10121003
inv, cfg := clitest.New(t,
10131004
"server",
10141005
"--in-memory",

enterprise/cli/provisionerdaemons_test.go

+1-12
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bufio"
55
"context"
66
"fmt"
7-
"net"
87
"net/http"
98
"strings"
109
"testing"
@@ -170,7 +169,7 @@ func TestProvisionerDaemon_SessionToken(t *testing.T) {
170169
t.Run("PrometheusEnabled", func(t *testing.T) {
171170
t.Parallel()
172171

173-
prometheusPort := randomPort(t)
172+
prometheusPort := testutil.RandomPort(t)
174173

175174
// Configure CLI client
176175
client, admin := coderdenttest.New(t, &coderdenttest.Options{
@@ -242,13 +241,3 @@ func TestProvisionerDaemon_SessionToken(t *testing.T) {
242241
require.True(t, hasPromHTTP, "Prometheus HTTP metrics are missing")
243242
})
244243
}
245-
246-
// randomPort is a helper function to find a free random port, for instance to spawn Prometheus endpoint.
247-
func randomPort(t *testing.T) int {
248-
random, err := net.Listen("tcp", "127.0.0.1:0")
249-
require.NoError(t, err)
250-
_ = random.Close()
251-
tcpAddr, valid := random.Addr().(*net.TCPAddr)
252-
require.True(t, valid)
253-
return tcpAddr.Port
254-
}

enterprise/cli/proxyserver_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func Test_Headers(t *testing.T) {
6363
func TestWorkspaceProxy_Server_PrometheusEnabled(t *testing.T) {
6464
t.Parallel()
6565

66-
prometheusPort := randomPort(t)
66+
prometheusPort := testutil.RandomPort(t)
6767

6868
var wg sync.WaitGroup
6969
wg.Add(1)
@@ -96,7 +96,7 @@ func TestWorkspaceProxy_Server_PrometheusEnabled(t *testing.T) {
9696
"--primary-access-url", srv.URL,
9797
"--proxy-session-token", "test-token",
9898
"--access-url", "http://foobar:3001",
99-
"--http-address", fmt.Sprintf("127.0.0.1:%d", randomPort(t)),
99+
"--http-address", fmt.Sprintf("127.0.0.1:%d", testutil.RandomPort(t)),
100100
"--prometheus-enable",
101101
"--prometheus-address", fmt.Sprintf("127.0.0.1:%d", prometheusPort),
102102
)

enterprise/cli/server_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func TestServer(t *testing.T) {
2222
var root cli.RootCmd
2323
cmd, err := root.Command(root.EnterpriseSubcommands())
2424
require.NoError(t, err)
25-
port := randomPort(t)
25+
port := testutil.RandomPort(t)
2626
inv, _ := clitest.NewWithCommand(t, cmd,
2727
"server",
2828
"--in-memory",

testutil/port.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package testutil
2+
3+
import (
4+
"math/rand"
5+
"net"
6+
"sync"
7+
"testing"
8+
"time"
9+
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
var (
14+
// nolint:gosec // not used for cryptography
15+
rnd = rand.New(rand.NewSource(time.Now().Unix()))
16+
rndMu sync.Mutex
17+
)
18+
19+
// RandomPort is a helper function to find a free random port.
20+
// Note that the OS may reallocate the port very quickly, so
21+
// this is not _guaranteed_.
22+
func RandomPort(t *testing.T) int {
23+
random, err := net.Listen("tcp", "127.0.0.1:0")
24+
require.NoError(t, err, "failed to listen on localhost")
25+
_ = random.Close()
26+
tcpAddr, valid := random.Addr().(*net.TCPAddr)
27+
require.True(t, valid, "random port address is not a *net.TCPAddr?!")
28+
return tcpAddr.Port
29+
}
30+
31+
// RandomPortNoListen returns a random port in the ephemeral port range.
32+
// Does not attempt to listen and close to find a port as the OS may
33+
// reallocate the port very quickly.
34+
func RandomPortNoListen(*testing.T) uint16 {
35+
const (
36+
// Overlap of windows, linux in https://en.wikipedia.org/wiki/Ephemeral_port
37+
min = 49152
38+
max = 60999
39+
)
40+
n := max - min
41+
rndMu.Lock()
42+
x := rnd.Intn(n)
43+
rndMu.Unlock()
44+
return uint16(min + x)
45+
}

0 commit comments

Comments
 (0)