tstest/integration: misc cleanups

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2021-05-03 14:22:18 -07:00
parent 3237e140c4
commit 68fb51b833

View File

@ -31,6 +31,7 @@
"go4.org/mem" "go4.org/mem"
"tailscale.com/derp" "tailscale.com/derp"
"tailscale.com/derp/derphttp" "tailscale.com/derp/derphttp"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/stun/stuntest" "tailscale.com/net/stun/stuntest"
"tailscale.com/safesocket" "tailscale.com/safesocket"
"tailscale.com/smallzstd" "tailscale.com/smallzstd"
@ -73,11 +74,8 @@ func TestIntegration(t *testing.T) {
n1.AwaitListening(t) n1.AwaitListening(t)
json, err := n1.Tailscale("status", "--json").CombinedOutput() st := n1.MustStatus(t)
if err != nil { t.Logf("Status: %s", st.BackendState)
t.Fatalf("running tailscale status: %v, %s", err, json)
}
t.Logf("Status: %s", json)
if err := tstest.WaitFor(20*time.Second, func() error { if err := tstest.WaitFor(20*time.Second, func() error {
const sub = `Program starting: ` const sub = `Program starting: `
@ -123,8 +121,8 @@ func TestIntegration(t *testing.T) {
} }
t.Logf("number of HTTP logcatcher requests: %v", env.LogCatcher.numRequests()) t.Logf("number of HTTP logcatcher requests: %v", env.LogCatcher.numRequests())
if err, ok := mainError.Load().(error); ok { if err := env.TrafficTrap.Err(); err != nil {
t.Error(err) t.Errorf("traffic trap: %v", err)
t.Logf("logs: %s", env.LogCatcher.logsString()) t.Logf("logs: %s", env.LogCatcher.logsString())
} }
} }
@ -159,11 +157,8 @@ type testEnv struct {
Control *testcontrol.Server Control *testcontrol.Server
ControlServer *httptest.Server ControlServer *httptest.Server
// CatchBadTrafficServer is an HTTP server that panics the process TrafficTrap *trafficTrap
// if it receives any traffic. We point the HTTP_PROXY to this, TrafficTrapServer *httptest.Server
// so any accidental traffic leaving tailscaled goes here and fails
// the test. (localhost traffic bypasses HTTP_PROXY)
CatchBadTrafficServer *httptest.Server
derpShutdown func() derpShutdown func()
} }
@ -173,29 +168,28 @@ type testEnv struct {
// //
// Call Close to shut everything down. // Call Close to shut everything down.
func newTestEnv(t testing.TB, bins *testBinaries) *testEnv { func newTestEnv(t testing.TB, bins *testBinaries) *testEnv {
derpMap, derpShutdown := runDERPAndStun(t, logger.Discard)
derpMap, derpShutdown := runDERPAndStun(t, t.Logf)
logc := new(logCatcher) logc := new(logCatcher)
control := &testcontrol.Server{ control := &testcontrol.Server{
DERPMap: derpMap, DERPMap: derpMap,
} }
trafficTrap := new(trafficTrap)
e := &testEnv{ e := &testEnv{
Binaries: bins, Binaries: bins,
LogCatcher: logc, LogCatcher: logc,
LogCatcherServer: httptest.NewServer(logc), LogCatcherServer: httptest.NewServer(logc),
Control: control, Control: control,
ControlServer: httptest.NewServer(control), ControlServer: httptest.NewServer(control),
TrafficTrap: trafficTrap,
TrafficTrapServer: httptest.NewServer(trafficTrap),
derpShutdown: derpShutdown, derpShutdown: derpShutdown,
} }
e.CatchBadTrafficServer = httptest.NewServer(http.HandlerFunc(e.catchUnexpectedTraffic))
return e return e
} }
func (e *testEnv) Close() error { func (e *testEnv) Close() error {
e.LogCatcherServer.Close() e.LogCatcherServer.Close()
e.CatchBadTrafficServer.Close() e.TrafficTrapServer.Close()
e.ControlServer.Close() e.ControlServer.Close()
e.derpShutdown() e.derpShutdown()
return nil return nil
@ -234,8 +228,8 @@ func (n *testNode) StartDaemon(t testing.TB) *exec.Cmd {
) )
cmd.Env = append(os.Environ(), cmd.Env = append(os.Environ(),
"TS_LOG_TARGET="+n.env.LogCatcherServer.URL, "TS_LOG_TARGET="+n.env.LogCatcherServer.URL,
"HTTP_PROXY="+n.env.CatchBadTrafficServer.URL, "HTTP_PROXY="+n.env.TrafficTrapServer.URL,
"HTTPS_PROXY="+n.env.CatchBadTrafficServer.URL, "HTTPS_PROXY="+n.env.TrafficTrapServer.URL,
) )
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
t.Fatalf("starting tailscaled: %v", err) t.Fatalf("starting tailscaled: %v", err)
@ -267,6 +261,19 @@ func (n *testNode) Tailscale(arg ...string) *exec.Cmd {
return cmd return cmd
} }
func (n *testNode) MustStatus(tb testing.TB) *ipnstate.Status {
tb.Helper()
out, err := n.Tailscale("status", "--json").CombinedOutput()
if err != nil {
tb.Fatalf("getting status: %v, %s", err, out)
}
st := new(ipnstate.Status)
if err := json.Unmarshal(out, st); err != nil {
tb.Fatalf("parsing status json: %v, from: %s", err, out)
}
return st
}
func exe() string { func exe() string {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
return ".exe" return ".exe"
@ -376,15 +383,31 @@ type Entry struct {
w.WriteHeader(200) // must have no content, but not a 204 w.WriteHeader(200) // must have no content, but not a 204
} }
// catchUnexpectedTraffic is an HTTP proxy handler to note whether any // trafficTrap is an HTTP proxy handler to note whether any
// HTTP traffic tries to leave localhost from tailscaled. We don't // HTTP traffic tries to leave localhost from tailscaled. We don't
// expect any, so any request triggers a failure. // expect any, so any request triggers a failure.
func (e *testEnv) catchUnexpectedTraffic(w http.ResponseWriter, r *http.Request) { type trafficTrap struct {
atomicErr atomic.Value // of error
}
func (tt *trafficTrap) Err() error {
if err, ok := tt.atomicErr.Load().(error); ok {
return err
}
return nil
}
func (tt *trafficTrap) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var got bytes.Buffer var got bytes.Buffer
r.Write(&got) r.Write(&got)
err := fmt.Errorf("unexpected HTTP proxy via proxy: %s", got.Bytes()) err := fmt.Errorf("unexpected HTTP proxy via proxy: %s", got.Bytes())
mainError.Store(err) mainError.Store(err)
if tt.Err() == nil {
// Best effort at remembering the first request.
tt.atomicErr.Store(err)
}
log.Printf("Error: %v", err) log.Printf("Error: %v", err)
w.WriteHeader(403)
} }
func runDERPAndStun(t testing.TB, logf logger.Logf) (derpMap *tailcfg.DERPMap, cleanup func()) { func runDERPAndStun(t testing.TB, logf logger.Logf) (derpMap *tailcfg.DERPMap, cleanup func()) {