77 "github.com/cli/cli/v2/internal/codespaces/api"
88 "github.com/cli/cli/v2/internal/codespaces/connection"
99 "github.com/microsoft/dev-tunnels/go/tunnels"
10+ "github.com/stretchr/testify/assert"
11+ "github.com/stretchr/testify/require"
12+ "golang.org/x/sync/errgroup"
1013)
1114
1215func TestNewPortForwarder (t * testing.T ) {
@@ -31,26 +34,16 @@ func TestNewPortForwarder(t *testing.T) {
3134
3235 // Create the mock HTTP client
3336 httpClient , err := connection .NewMockHttpClient ()
34- if err != nil {
35- t .Fatalf ("NewHttpClient returned an error: %v" , err )
36- }
37+ require .NoError (t , err )
3738
3839 // Call the function being tested
3940 conn , err := connection .NewCodespaceConnection (ctx , codespace , httpClient )
40- if err != nil {
41- t .Fatalf ("NewCodespaceConnection returned an error: %v" , err )
42- }
41+ require .NoError (t , err )
4342
4443 // Create the new port forwarder
4544 portForwarder , err := NewPortForwarder (ctx , conn )
46- if err != nil {
47- t .Fatalf ("NewPortForwarder returned an error: %v" , err )
48- }
49-
50- // Check that the port forwarder was created successfully
51- if portForwarder == nil {
52- t .Fatal ("NewPortForwarder returned nil" )
53- }
45+ require .NoError (t , err )
46+ require .NotNil (t , portForwarder )
5447}
5548
5649func TestAccessControlEntriesToVisibility (t * testing.T ) {
@@ -96,9 +89,7 @@ func TestAccessControlEntriesToVisibility(t *testing.T) {
9689 for _ , test := range tests {
9790 t .Run (test .name , func (t * testing.T ) {
9891 visibility := AccessControlEntriesToVisibility (test .accessControlEntries )
99- if visibility != test .expected {
100- t .Errorf ("expected %q, got %q" , test .expected , visibility )
101- }
92+ assert .Equal (t , test .expected , visibility )
10293 })
10394 }
10495}
@@ -131,9 +122,7 @@ func TestIsInternalPort(t *testing.T) {
131122 for _ , test := range tests {
132123 t .Run (test .name , func (t * testing.T ) {
133124 isInternal := IsInternalPort (test .port )
134- if isInternal != test .expected {
135- t .Errorf ("expected %v, got %v" , test .expected , isInternal )
136- }
125+ assert .Equal (t , test .expected , isInternal )
137126 })
138127 }
139128}
@@ -163,39 +152,70 @@ func TestForwardPortDefaultsToHTTPProtocol(t *testing.T) {
163152 httpClient , err := connection .NewMockHttpClient (
164153 connection .WithSpecificPorts (tunnelPorts ),
165154 )
166- if err != nil {
167- t .Fatalf ("NewMockHttpClient returned an error: %v" , err )
168- }
155+ require .NoError (t , err )
169156
170157 connection , err := connection .NewCodespaceConnection (t .Context (), codespace , httpClient )
171- if err != nil {
172- t .Fatalf ("NewCodespaceConnection returned an error: %v" , err )
173- }
158+ require .NoError (t , err )
174159
175160 fwd , err := NewPortForwarder (t .Context (), connection )
176- if err != nil {
177- t .Fatalf ("NewPortForwarder returned an error: %v" , err )
178- }
161+ require .NoError (t , err )
179162
180163 // When we forward a port without an existing one to use for a protocol, it should default to HTTP.
181- if err : = fwd .ForwardPort (t .Context (), ForwardPortOpts {
164+ err = fwd .ForwardPort (t .Context (), ForwardPortOpts {
182165 Port : 1337 ,
183- }); err != nil {
184- t .Fatalf ("ForwardPort returned an error: %v" , err )
185- }
166+ })
167+ require .NoError (t , err )
186168
187169 ports , err := fwd .ListPorts (t .Context ())
188- if err != nil {
189- t .Fatalf ("ListPorts returned an error: %v" , err )
190- }
170+ require .NoError (t , err )
171+ require .Len (t , ports , 1 )
172+ assert .Equal (t , string (tunnels .TunnelProtocolHttp ), ports [0 ].Protocol )
173+ }
191174
192- if len (ports ) != 1 {
193- t .Fatalf ("expected 1 port, got %d" , len (ports ))
175+ func TestConcurrentForwardPortDoesNotRace (t * testing.T ) {
176+ codespace := & api.Codespace {
177+ Name : "codespace-name" ,
178+ State : api .CodespaceStateAvailable ,
179+ Connection : api.CodespaceConnection {
180+ TunnelProperties : api.TunnelProperties {
181+ ConnectAccessToken : "tunnel access-token" ,
182+ ManagePortsAccessToken : "manage-ports-token" ,
183+ ServiceUri : "http://global.rel.tunnels.api.visualstudio.com/" ,
184+ TunnelId : "tunnel-id" ,
185+ ClusterId : "usw2" ,
186+ Domain : "domain.com" ,
187+ },
188+ },
189+ RuntimeConstraints : api.RuntimeConstraints {
190+ AllowedPortPrivacySettings : []string {"public" , "private" },
191+ },
194192 }
195193
196- if ports [0 ].Protocol != string (tunnels .TunnelProtocolHttp ) {
197- t .Fatalf ("expected port protocol to be http, got %s" , ports [0 ].Protocol )
194+ tunnelPorts := map [int ]tunnels.TunnelPort {}
195+
196+ httpClient , err := connection .NewMockHttpClient (
197+ connection .WithSpecificPorts (tunnelPorts ),
198+ )
199+ require .NoError (t , err )
200+
201+ conn , err := connection .NewCodespaceConnection (t .Context (), codespace , httpClient )
202+ require .NoError (t , err )
203+
204+ // Forward multiple ports concurrently from the same connection,
205+ // mirroring what ForwardPorts does in ports.go.
206+ group , ctx := errgroup .WithContext (t .Context ())
207+ for port := 3000 ; port < 3010 ; port ++ {
208+ fwd , err := NewPortForwarder (ctx , conn )
209+ require .NoError (t , err )
210+
211+ group .Go (func () error {
212+ return fwd .ForwardPort (ctx , ForwardPortOpts {
213+ Port : port ,
214+ })
215+ })
198216 }
217+
218+ require .NoError (t , group .Wait ())
199219}
200220
201221func TestForwardPortRespectsProtocolOfExistingTunneledPorts (t * testing.T ) {
@@ -230,38 +250,23 @@ func TestForwardPortRespectsProtocolOfExistingTunneledPorts(t *testing.T) {
230250 httpClient , err := connection .NewMockHttpClient (
231251 connection .WithSpecificPorts (tunnelPorts ),
232252 )
233- if err != nil {
234- t .Fatalf ("NewMockHttpClient returned an error: %v" , err )
235- }
253+ require .NoError (t , err )
236254
237255 connection , err := connection .NewCodespaceConnection (t .Context (), codespace , httpClient )
238- if err != nil {
239- t .Fatalf ("NewCodespaceConnection returned an error: %v" , err )
240- }
256+ require .NoError (t , err )
241257
242258 fwd , err := NewPortForwarder (t .Context (), connection )
243- if err != nil {
244- t .Fatalf ("NewPortForwarder returned an error: %v" , err )
245- }
259+ require .NoError (t , err )
246260
247261 // When we forward a port, it would typically default to HTTP, to which the mock server would respond with a 400,
248262 // but it should respect the existing port's protocol and forward it as HTTPS.
249- if err : = fwd .ForwardPort (t .Context (), ForwardPortOpts {
263+ err = fwd .ForwardPort (t .Context (), ForwardPortOpts {
250264 Port : 1337 ,
251- }); err != nil {
252- t .Fatalf ("ForwardPort returned an error: %v" , err )
253- }
265+ })
266+ require .NoError (t , err )
254267
255268 ports , err := fwd .ListPorts (t .Context ())
256- if err != nil {
257- t .Fatalf ("ListPorts returned an error: %v" , err )
258- }
259-
260- if len (ports ) != 1 {
261- t .Fatalf ("expected 1 port, got %d" , len (ports ))
262- }
263-
264- if ports [0 ].Protocol != string (tunnels .TunnelProtocolHttps ) {
265- t .Fatalf ("expected port protocol to be https, got %s" , ports [0 ].Protocol )
266- }
269+ require .NoError (t , err )
270+ require .Len (t , ports , 1 )
271+ assert .Equal (t , string (tunnels .TunnelProtocolHttps ), ports [0 ].Protocol )
267272}
0 commit comments