omarchy-send/internal/tailscale/tailscale_test.go
28allday 2c058031fd Add remote-peer support over Tailscale and unicast probing
Multicast only finds peers on the same LAN. Reach off-LAN boxes by probing
them directly over unicast (works over any routable address; Tailscale is the
easy, secure choice):

- discovery.Probe: unicast POST /register (https->http fallback) with a two-way
  handshake, so send and receive both work; offline peers age out.
- internal/tailscale: Peers() shells `tailscale status --json` for online peers.
- config.KnownPeers: persisted manual remotes.
- main.go: watchRemotes goroutine probes knownPeers ∪ tailscale peers every 10s,
  in both the normal TUI path and quick-send.
- TUI: `+` on Devices opens an add-remote modal (host/IP/Tailscale name).
- install.sh: interactive local/remote install prompt; remote mode locks port
  53317 to the Tailscale interface (ufw), with container/userspace-networking
  detection. README documents remote devices.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 21:47:52 +01:00

46 lines
1.1 KiB
Go

package tailscale
import (
"reflect"
"sort"
"testing"
)
func TestParsePeersOnlineIPv4Only(t *testing.T) {
data := []byte(`{
"Peer": {
"key1": {"TailscaleIPs": ["100.64.0.1", "fd7a:115c::1"], "Online": true},
"key2": {"TailscaleIPs": ["100.64.0.2"], "Online": false},
"key3": {"TailscaleIPs": ["fd7a:115c::3"], "Online": true},
"key4": {"TailscaleIPs": ["100.64.0.4"], "Online": true}
}
}`)
got := parsePeers(data)
sort.Strings(got)
want := []string{"100.64.0.1", "100.64.0.4"} // online + has IPv4; offline and v6-only excluded
if !reflect.DeepEqual(got, want) {
t.Errorf("parsePeers = %v, want %v", got, want)
}
}
func TestParsePeersBadJSON(t *testing.T) {
if got := parsePeers([]byte("not json")); got != nil {
t.Errorf("bad JSON should yield nil, got %v", got)
}
}
func TestIsIPv4(t *testing.T) {
cases := map[string]bool{
"100.64.0.1": true,
"1.2.3.4": true,
"fd7a:115c::1": false,
"1.2.3": false,
"": false,
"abc": false,
}
for in, want := range cases {
if got := isIPv4(in); got != want {
t.Errorf("isIPv4(%q) = %v, want %v", in, got, want)
}
}
}