|
|
@@ -11,12 +11,14 @@ import (
|
|
|
"net"
|
|
|
"net/http"
|
|
|
"net/http/httptest"
|
|
|
+ "strings"
|
|
|
"sync"
|
|
|
"testing"
|
|
|
"time"
|
|
|
|
|
|
"tailscale.com/derp"
|
|
|
"tailscale.com/net/netmon"
|
|
|
+ "tailscale.com/net/netx"
|
|
|
"tailscale.com/types/key"
|
|
|
)
|
|
|
|
|
|
@@ -298,6 +300,7 @@ func TestBreakWatcherConnRecv(t *testing.T) {
|
|
|
defer cancel()
|
|
|
|
|
|
watcherChan := make(chan int, 1)
|
|
|
+ errChan := make(chan error, 1)
|
|
|
|
|
|
// Start the watcher thread (which connects to the watched server)
|
|
|
wg.Add(1) // To avoid using t.Logf after the test ends. See https://golang.org/issue/40343
|
|
|
@@ -311,8 +314,11 @@ func TestBreakWatcherConnRecv(t *testing.T) {
|
|
|
watcherChan <- peers
|
|
|
}
|
|
|
remove := func(m derp.PeerGoneMessage) { t.Logf("remove: %v", m.Peer.ShortString()); peers-- }
|
|
|
+ notifyErr := func(err error) {
|
|
|
+ errChan <- err
|
|
|
+ }
|
|
|
|
|
|
- watcher1.RunWatchConnectionLoop(ctx, serverPrivateKey1.Public(), t.Logf, add, remove)
|
|
|
+ watcher1.RunWatchConnectionLoop(ctx, serverPrivateKey1.Public(), t.Logf, add, remove, notifyErr)
|
|
|
}()
|
|
|
|
|
|
timer := time.NewTimer(5 * time.Second)
|
|
|
@@ -326,6 +332,10 @@ func TestBreakWatcherConnRecv(t *testing.T) {
|
|
|
if peers != 1 {
|
|
|
t.Fatal("wrong number of peers added during watcher connection")
|
|
|
}
|
|
|
+ case err := <-errChan:
|
|
|
+ if !strings.Contains(err.Error(), "use of closed network connection") {
|
|
|
+ t.Fatalf("expected notifyError connection error to contain 'use of closed network connection', got %v", err)
|
|
|
+ }
|
|
|
case <-timer.C:
|
|
|
t.Fatalf("watcher did not process the peer update")
|
|
|
}
|
|
|
@@ -369,6 +379,7 @@ func TestBreakWatcherConn(t *testing.T) {
|
|
|
|
|
|
watcherChan := make(chan int, 1)
|
|
|
breakerChan := make(chan bool, 1)
|
|
|
+ errorChan := make(chan error, 1)
|
|
|
|
|
|
// Start the watcher thread (which connects to the watched server)
|
|
|
wg.Add(1) // To avoid using t.Logf after the test ends. See https://golang.org/issue/40343
|
|
|
@@ -384,8 +395,11 @@ func TestBreakWatcherConn(t *testing.T) {
|
|
|
<-breakerChan
|
|
|
}
|
|
|
remove := func(m derp.PeerGoneMessage) { t.Logf("remove: %v", m.Peer.ShortString()); peers-- }
|
|
|
+ notifyError := func(err error) {
|
|
|
+ errorChan <- err
|
|
|
+ }
|
|
|
|
|
|
- watcher1.RunWatchConnectionLoop(ctx, serverPrivateKey1.Public(), t.Logf, add, remove)
|
|
|
+ watcher1.RunWatchConnectionLoop(ctx, serverPrivateKey1.Public(), t.Logf, add, remove, notifyError)
|
|
|
}()
|
|
|
|
|
|
timer := time.NewTimer(5 * time.Second)
|
|
|
@@ -399,6 +413,10 @@ func TestBreakWatcherConn(t *testing.T) {
|
|
|
if peers != 1 {
|
|
|
t.Fatal("wrong number of peers added during watcher connection")
|
|
|
}
|
|
|
+ case err := <-errorChan:
|
|
|
+ if !strings.Contains(err.Error(), "use of closed network connection") {
|
|
|
+ t.Fatalf("expected notifyError connection error to contain 'use of closed network connection', got %v", err)
|
|
|
+ }
|
|
|
case <-timer.C:
|
|
|
t.Fatalf("watcher did not process the peer update")
|
|
|
}
|
|
|
@@ -414,6 +432,7 @@ func TestBreakWatcherConn(t *testing.T) {
|
|
|
|
|
|
func noopAdd(derp.PeerPresentMessage) {}
|
|
|
func noopRemove(derp.PeerGoneMessage) {}
|
|
|
+func noopNotifyError(error) {}
|
|
|
|
|
|
func TestRunWatchConnectionLoopServeConnect(t *testing.T) {
|
|
|
defer func() { testHookWatchLookConnectResult = nil }()
|
|
|
@@ -441,7 +460,7 @@ func TestRunWatchConnectionLoopServeConnect(t *testing.T) {
|
|
|
}
|
|
|
return false
|
|
|
}
|
|
|
- watcher.RunWatchConnectionLoop(ctx, pub, t.Logf, noopAdd, noopRemove)
|
|
|
+ watcher.RunWatchConnectionLoop(ctx, pub, t.Logf, noopAdd, noopRemove, noopNotifyError)
|
|
|
|
|
|
// Test connecting to the server with a zero value for ignoreServerKey,
|
|
|
// so we should always connect.
|
|
|
@@ -455,7 +474,7 @@ func TestRunWatchConnectionLoopServeConnect(t *testing.T) {
|
|
|
}
|
|
|
return false
|
|
|
}
|
|
|
- watcher.RunWatchConnectionLoop(ctx, key.NodePublic{}, t.Logf, noopAdd, noopRemove)
|
|
|
+ watcher.RunWatchConnectionLoop(ctx, key.NodePublic{}, t.Logf, noopAdd, noopRemove, noopNotifyError)
|
|
|
}
|
|
|
|
|
|
// verify that the LocalAddr method doesn't acquire the mutex.
|
|
|
@@ -491,3 +510,49 @@ func TestProbe(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func TestNotifyError(t *testing.T) {
|
|
|
+ defer func() { testHookWatchLookConnectResult = nil }()
|
|
|
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ priv := key.NewNode()
|
|
|
+ serverURL, s := newTestServer(t, priv)
|
|
|
+ defer s.Close()
|
|
|
+
|
|
|
+ pub := priv.Public()
|
|
|
+
|
|
|
+ // Test early error notification when c.connect fails.
|
|
|
+ watcher := newWatcherClient(t, priv, serverURL)
|
|
|
+ watcher.SetURLDialer(netx.DialFunc(func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
|
+ t.Helper()
|
|
|
+ return nil, fmt.Errorf("test error: %s", addr)
|
|
|
+ }))
|
|
|
+ defer watcher.Close()
|
|
|
+
|
|
|
+ testHookWatchLookConnectResult = func(err error, wasSelfConnect bool) bool {
|
|
|
+ t.Helper()
|
|
|
+ if err == nil {
|
|
|
+ t.Fatal("expected error connecting to server, got nil")
|
|
|
+ }
|
|
|
+ if wasSelfConnect {
|
|
|
+ t.Error("wanted normal connect; got self connect")
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ errChan := make(chan error, 1)
|
|
|
+ notifyError := func(err error) {
|
|
|
+ errChan <- err
|
|
|
+ }
|
|
|
+ watcher.RunWatchConnectionLoop(ctx, pub, t.Logf, noopAdd, noopRemove, notifyError)
|
|
|
+
|
|
|
+ select {
|
|
|
+ case err := <-errChan:
|
|
|
+ if !strings.Contains(err.Error(), "test") {
|
|
|
+ t.Errorf("expected test error, got %v", err)
|
|
|
+ }
|
|
|
+ case <-ctx.Done():
|
|
|
+ t.Fatalf("context done before receiving error: %v", ctx.Err())
|
|
|
+ }
|
|
|
+}
|