Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit50575e1

Browse files
authored
fix: use fake local network for port-forward tests (#11119)
Fixes#10979Testing code that listens on a specific port has created a long battle with flakes. Previous attempts to deal with this include opening a listener on a port chosen by the OS, then closing the listener, noting the port and starting the test with that port.This still flakes, notably in macOS which has a proclivity to reuse ports quickly.Instead of fighting with the chaos that is an OS networking stack, this PR fakes the host networking in tests.I've taken a small step here, only faking out the Listen() calls that port-forward makes, but I think over time we should be transitioning all networking the CLI does to an abstract interface so we can fake it. This allows us to run in parallel without flakes andpresents an opportunity to test error paths as well.
1 parent37f6b38 commit50575e1

File tree

4 files changed

+191
-106
lines changed

4 files changed

+191
-106
lines changed

‎cli/clibase/cmd.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ type Invocation struct {
189189
Stderr io.Writer
190190
Stdin io.Reader
191191
Logger slog.Logger
192+
NetNet
192193

193194
// testing
194195
signalNotifyContextfunc(parent context.Context,signals...os.Signal) (ctx context.Context,stop context.CancelFunc)
@@ -203,6 +204,7 @@ func (inv *Invocation) WithOS() *Invocation {
203204
i.Stdin=os.Stdin
204205
i.Args=os.Args[1:]
205206
i.Environ=ParseEnviron(os.Environ(),"")
207+
i.Net=osNet{}
206208
})
207209
}
208210

‎cli/clibase/net.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package clibase
2+
3+
import (
4+
"net"
5+
"strconv"
6+
7+
"github.com/pion/udp"
8+
"golang.org/x/xerrors"
9+
)
10+
11+
// Net abstracts CLI commands interacting with the operating system networking.
12+
//
13+
// At present, it covers opening local listening sockets, since doing this
14+
// in testing is a challenge without flakes, since it's hard to pick a port we
15+
// know a priori will be free.
16+
typeNetinterface {
17+
// Listen has the same semantics as `net.Listen` but also supports `udp`
18+
Listen(network,addressstring) (net.Listener,error)
19+
}
20+
21+
// osNet is an implementation that call the real OS for networking.
22+
typeosNetstruct{}
23+
24+
func (osNet)Listen(network,addressstring) (net.Listener,error) {
25+
switchnetwork {
26+
case"tcp","tcp4","tcp6","unix","unixpacket":
27+
returnnet.Listen(network,address)
28+
case"udp":
29+
host,port,err:=net.SplitHostPort(address)
30+
iferr!=nil {
31+
returnnil,xerrors.Errorf("split %q: %w",address,err)
32+
}
33+
34+
varportIntint
35+
portInt,err=strconv.Atoi(port)
36+
iferr!=nil {
37+
returnnil,xerrors.Errorf("parse port %v from %q as int: %w",port,address,err)
38+
}
39+
40+
// Use pion here so that we get a stream-style net.Conn listener, instead
41+
// of a packet-oriented connection that can read and write to multiple
42+
// addresses.
43+
returnudp.Listen(network,&net.UDPAddr{
44+
IP:net.ParseIP(host),
45+
Port:portInt,
46+
})
47+
default:
48+
returnnil,xerrors.Errorf("unknown listen network %q",network)
49+
}
50+
}

‎cli/portforward.go

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"sync"
1313
"syscall"
1414

15-
"github.com/pion/udp"
1615
"golang.org/x/xerrors"
1716

1817
"cdr.dev/slog"
@@ -121,6 +120,7 @@ func (r *RootCmd) portForward() *clibase.Cmd {
121120
wg=new(sync.WaitGroup)
122121
listeners=make([]net.Listener,len(specs))
123122
closeAllListeners=func() {
123+
logger.Debug(ctx,"closing all listeners")
124124
for_,l:=rangelisteners {
125125
ifl==nil {
126126
continue
@@ -134,6 +134,7 @@ func (r *RootCmd) portForward() *clibase.Cmd {
134134
fori,spec:=rangespecs {
135135
l,err:=listenAndPortForward(ctx,inv,conn,wg,spec,logger)
136136
iferr!=nil {
137+
logger.Error(ctx,"failed to listen",slog.F("spec",spec),slog.Error(err))
137138
returnerr
138139
}
139140
listeners[i]=l
@@ -151,8 +152,10 @@ func (r *RootCmd) portForward() *clibase.Cmd {
151152

152153
select {
153154
case<-ctx.Done():
155+
logger.Debug(ctx,"command context expired waiting for signal",slog.Error(ctx.Err()))
154156
closeErr=ctx.Err()
155-
case<-sigs:
157+
casesig:=<-sigs:
158+
logger.Debug(ctx,"received signal",slog.F("signal",sig))
156159
_,_=fmt.Fprintln(inv.Stderr,"\nReceived signal, closing all listeners and active connections")
157160
}
158161

@@ -161,6 +164,7 @@ func (r *RootCmd) portForward() *clibase.Cmd {
161164
}()
162165

163166
conn.AwaitReachable(ctx)
167+
logger.Debug(ctx,"read to accept connections to forward")
164168
_,_=fmt.Fprintln(inv.Stderr,"Ready!")
165169
wg.Wait()
166170
returncloseErr
@@ -198,33 +202,7 @@ func listenAndPortForward(
198202
logger=logger.With(slog.F("network",spec.listenNetwork),slog.F("address",spec.listenAddress))
199203
_,_=fmt.Fprintf(inv.Stderr,"Forwarding '%v://%v' locally to '%v://%v' in the workspace\n",spec.listenNetwork,spec.listenAddress,spec.dialNetwork,spec.dialAddress)
200204

201-
var (
202-
l net.Listener
203-
errerror
204-
)
205-
switchspec.listenNetwork {
206-
case"tcp":
207-
l,err=net.Listen(spec.listenNetwork,spec.listenAddress)
208-
case"udp":
209-
varhost,portstring
210-
host,port,err=net.SplitHostPort(spec.listenAddress)
211-
iferr!=nil {
212-
returnnil,xerrors.Errorf("split %q: %w",spec.listenAddress,err)
213-
}
214-
215-
varportIntint
216-
portInt,err=strconv.Atoi(port)
217-
iferr!=nil {
218-
returnnil,xerrors.Errorf("parse port %v from %q as int: %w",port,spec.listenAddress,err)
219-
}
220-
221-
l,err=udp.Listen(spec.listenNetwork,&net.UDPAddr{
222-
IP:net.ParseIP(host),
223-
Port:portInt,
224-
})
225-
default:
226-
returnnil,xerrors.Errorf("unknown listen network %q",spec.listenNetwork)
227-
}
205+
l,err:=inv.Net.Listen(spec.listenNetwork,spec.listenAddress)
228206
iferr!=nil {
229207
returnnil,xerrors.Errorf("listen '%v://%v': %w",spec.listenNetwork,spec.listenAddress,err)
230208
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp