first commit
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
package remotecontrol
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// withIfaceLister swaps the package ifaceLister for the duration of a test.
|
||||
func withIfaceLister(t *testing.T, fn func() ([]ifaceInfo, error)) {
|
||||
t.Helper()
|
||||
orig := ifaceLister
|
||||
ifaceLister = fn
|
||||
t.Cleanup(func() { ifaceLister = orig })
|
||||
}
|
||||
|
||||
// ipnets wraps IPs as *net.IPNet addresses for an ifaceInfo.
|
||||
func ipnets(ips ...string) []net.Addr {
|
||||
out := make([]net.Addr, 0, len(ips))
|
||||
for _, s := range ips {
|
||||
out = append(out, &net.IPNet{IP: net.ParseIP(s)})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestDetectRoutableIPPicksRoutableV4(t *testing.T) {
|
||||
withIfaceLister(t, func() ([]ifaceInfo, error) {
|
||||
return []ifaceInfo{{
|
||||
flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast,
|
||||
addrs: ipnets("fe80::1", "127.0.0.1", "169.254.1.5", "192.168.1.42", "10.0.0.9"),
|
||||
}}, nil
|
||||
})
|
||||
ip, err := DetectRoutableIP()
|
||||
if err != nil {
|
||||
t.Fatalf("DetectRoutableIP: %v", err)
|
||||
}
|
||||
if ip != "192.168.1.42" {
|
||||
t.Fatalf("ip = %q, want 192.168.1.42 (first private v4)", ip)
|
||||
}
|
||||
}
|
||||
|
||||
// A VPN utun tunnel (point-to-point) whose address sorts before Wi-Fi must be
|
||||
// skipped so the QR URL points at the LAN address the phone can reach — the
|
||||
// white-screen bug this replaces.
|
||||
func TestDetectRoutableIPSkipsVPNPointToPoint(t *testing.T) {
|
||||
withIfaceLister(t, func() ([]ifaceInfo, error) {
|
||||
return []ifaceInfo{
|
||||
{ // loopback
|
||||
flags: net.FlagUp | net.FlagLoopback,
|
||||
addrs: ipnets("127.0.0.1"),
|
||||
},
|
||||
{ // VPN tunnel — routable but unreachable from the LAN
|
||||
flags: net.FlagUp | net.FlagPointToPoint | net.FlagMulticast,
|
||||
addrs: ipnets("172.31.201.147"),
|
||||
},
|
||||
{ // Wi-Fi
|
||||
flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast,
|
||||
addrs: ipnets("192.168.3.54"),
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
ip, err := DetectRoutableIP()
|
||||
if err != nil {
|
||||
t.Fatalf("DetectRoutableIP: %v", err)
|
||||
}
|
||||
if ip != "192.168.3.54" {
|
||||
t.Fatalf("ip = %q, want 192.168.3.54 (Wi-Fi, VPN skipped)", ip)
|
||||
}
|
||||
}
|
||||
|
||||
// A down interface must not be chosen even if it carries a private address.
|
||||
func TestDetectRoutableIPSkipsDownInterface(t *testing.T) {
|
||||
withIfaceLister(t, func() ([]ifaceInfo, error) {
|
||||
return []ifaceInfo{
|
||||
{ // down: skipped despite the private address
|
||||
flags: net.FlagBroadcast | net.FlagMulticast,
|
||||
addrs: ipnets("192.168.9.9"),
|
||||
},
|
||||
{ // up
|
||||
flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast,
|
||||
addrs: ipnets("10.1.2.3"),
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
ip, err := DetectRoutableIP()
|
||||
if err != nil {
|
||||
t.Fatalf("DetectRoutableIP: %v", err)
|
||||
}
|
||||
if ip != "10.1.2.3" {
|
||||
t.Fatalf("ip = %q, want 10.1.2.3 (down iface skipped)", ip)
|
||||
}
|
||||
}
|
||||
|
||||
// With no private address, a routable public address is used as a fallback.
|
||||
func TestDetectRoutableIPFallsBackToPublic(t *testing.T) {
|
||||
withIfaceLister(t, func() ([]ifaceInfo, error) {
|
||||
return []ifaceInfo{{
|
||||
flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast,
|
||||
addrs: ipnets("203.0.113.7"),
|
||||
}}, nil
|
||||
})
|
||||
ip, err := DetectRoutableIP()
|
||||
if err != nil {
|
||||
t.Fatalf("DetectRoutableIP: %v", err)
|
||||
}
|
||||
if ip != "203.0.113.7" {
|
||||
t.Fatalf("ip = %q, want 203.0.113.7 (public fallback)", ip)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectRoutableIPSkipsLoopbackAndLinkLocal(t *testing.T) {
|
||||
withIfaceLister(t, func() ([]ifaceInfo, error) {
|
||||
return []ifaceInfo{{
|
||||
flags: net.FlagUp | net.FlagMulticast,
|
||||
addrs: ipnets("127.0.0.1", "169.254.1.5"),
|
||||
}}, nil
|
||||
})
|
||||
if _, err := DetectRoutableIP(); err != ErrNoLAN {
|
||||
t.Fatalf("err = %v, want ErrNoLAN", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectRoutableIPNoInterfaces(t *testing.T) {
|
||||
withIfaceLister(t, func() ([]ifaceInfo, error) {
|
||||
return nil, nil
|
||||
})
|
||||
if _, err := DetectRoutableIP(); err != ErrNoLAN {
|
||||
t.Fatalf("err = %v, want ErrNoLAN", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListenFreePortAutoAssign(t *testing.T) {
|
||||
ln, port, err := ListenFreePort("127.0.0.1", 0)
|
||||
if err != nil {
|
||||
t.Fatalf("ListenFreePort: %v", err)
|
||||
}
|
||||
defer ln.Close()
|
||||
if port <= 0 {
|
||||
t.Fatalf("port = %d, want > 0", port)
|
||||
}
|
||||
if got := ln.Addr().(*net.TCPAddr).Port; got != port {
|
||||
t.Fatalf("listener port %d != returned %d", got, port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListenFreePortFallsBackWhenOccupied(t *testing.T) {
|
||||
// Occupy a port, then ask ListenFreePort for that same port; it must fall
|
||||
// back to a different, free one instead of failing.
|
||||
occupied, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("occupy: %v", err)
|
||||
}
|
||||
defer occupied.Close()
|
||||
busyPort := occupied.Addr().(*net.TCPAddr).Port
|
||||
|
||||
ln, port, err := ListenFreePort("127.0.0.1", busyPort)
|
||||
if err != nil {
|
||||
t.Fatalf("ListenFreePort: %v", err)
|
||||
}
|
||||
defer ln.Close()
|
||||
if port == busyPort {
|
||||
t.Fatalf("port = %d, expected fallback away from occupied %d", port, busyPort)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListenFreePortUsesRequestedWhenFree(t *testing.T) {
|
||||
// Find a free port, release it, then request it explicitly.
|
||||
probe, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("probe: %v", err)
|
||||
}
|
||||
want := probe.Addr().(*net.TCPAddr).Port
|
||||
probe.Close()
|
||||
|
||||
ln, port, err := ListenFreePort("127.0.0.1", want)
|
||||
if err != nil {
|
||||
t.Fatalf("ListenFreePort: %v", err)
|
||||
}
|
||||
defer ln.Close()
|
||||
if port != want {
|
||||
t.Fatalf("port = %d, want requested %d", port, want)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user