package device import ( "os" "path/filepath" "runtime" "strings" "testing" ) func TestConnectWirelessReadiness(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("fake ADB uses a POSIX shell") } for _, tc := range []struct { name, initial, after string wantOK, wantDisconnect bool }{ {"offline reconnects", "offline", "device", true, true}, {"still offline is not success", "offline", "offline", false, true}, {"online transport is preserved", "device", "device", true, false}, } { t.Run(tc.name, func(t *testing.T) { dir := t.TempDir() state := filepath.Join(dir, "state") calls := filepath.Join(dir, "calls") bin := filepath.Join(dir, "adb") t.Setenv("FAKE_ADB_STATE", state) t.Setenv("FAKE_ADB_CALLS", calls) t.Setenv("FAKE_ADB_AFTER", tc.after) if err := os.WriteFile(state, []byte(tc.initial), 0600); err != nil { t.Fatal(err) } script := `#!/bin/sh printf '%s\n' "$*" >> "$FAKE_ADB_CALLS" if [ "$1" != -P ] || [ "$2" != 17891 ]; then exit 42; fi shift 2 case "$1" in devices) printf 'List of devices attached\n' state=$(cat "$FAKE_ADB_STATE") if [ "$state" != missing ]; then printf '192.0.2.1:5555 %s model:TestPhone\n' "$state"; fi ;; disconnect) printf missing > "$FAKE_ADB_STATE" ;; connect) printf '%s' "$FAKE_ADB_AFTER" > "$FAKE_ADB_STATE"; printf 'connected to 192.0.2.1:5555\n' ;; -s) printf 'Physical size: 1080x2400\n' ;; esac ` if err := os.WriteFile(bin, []byte(script), 0700); err != nil { t.Fatal(err) } previous := adbPathOverride SetAdbPath(bin) defer SetAdbPath(previous) service := &Service{} result := service.ConnectWireless(ConnectRequest{HostPort: "192.0.2.1:5555"}) if result.OK != tc.wantOK { t.Fatalf("got %+v, want OK=%v", result, tc.wantOK) } data, err := os.ReadFile(calls) if err != nil { t.Fatal(err) } history := string(data) if strings.Contains(history, "kill-server") { t.Fatal("reconnect restarted the shared daemon") } disconnected := strings.Contains(history, "disconnect 192.0.2.1:5555\n") if disconnected != tc.wantDisconnect { t.Fatalf("wrong cleanup behavior: %s", history) } if tc.wantOK && service.GetActiveDevice().ID != "192.0.2.1:5555" { t.Fatal("connected target was not selected") } }) } } func TestADBCommandDoesNotInheritSharedServer(t *testing.T) { t.Setenv("ADB_SERVER_SOCKET", "tcp:example.invalid:5037") t.Setenv("ANDROID_ADB_SERVER_PORT", "5037") command := (&adbClient{bin: "adb"}).command("-s", "phone", "shell", "echo", "ok") got := strings.Join(command.Args, " ") if !strings.Contains(got, "-P 17891 -s phone shell echo ok") { t.Fatalf("ADB request escaped the application server: %s", got) } for _, entry := range command.Env { if strings.HasPrefix(entry, "ADB_SERVER_SOCKET=") || strings.HasPrefix(entry, "ANDROID_ADB_SERVER_PORT=") { t.Fatalf("shared-server override was inherited: %s", entry) } } } func TestRejectInvalidPhoneAddresses(t *testing.T) { for _, address := range []string{"192.688.0.108:39623", "192.168.0.108:0", "192.168.0.108:65536", "192.168.0.108:abc", "192.168.0.108"} { if err := validateHostPort(address); err == nil { t.Errorf("invalid address accepted: %s", address) } } for _, address := range []string{"192.168.0.108:40315", "phone.local:5555", "[::1]:5555"} { if err := validateHostPort(address); err != nil { t.Errorf("valid address rejected: %s: %v", address, err) } } }