Files
sing-android/TEST_PLAN.md
Sing Dev 1106f61cf0 Add CommandReceiver for adb control, fix tailscale routing
- CommandReceiver: exported broadcast receiver for adb CLI control
  - start/stop/status/set_config commands
  - Usage: adb shell am broadcast -a com.sing.vpn.CMD -n com.sing.vpn/.CommandReceiver --es cmd start
- SingConfig: add controlplane.tailscale.com → direct route rule
  to prevent tailnet control traffic from going through proxy
2026-04-02 15:31:15 +08:00

11 KiB

Android UI Redesign — Test Plan

Environment Setup

# Create emulator (API 34, x86_64 for faster emulation)
sdkmanager "system-images;android-34;google_apis;x86_64"
avdmanager create avd -n sing-test -k "system-images;android-34;google_apis;x86_64" -d pixel_6

# Start emulator
emulator -avd sing-test -no-snapshot-load

# Build + install (from android/ dir)
./gradlew installDebug
adb shell am start -n com.sing.vpn/.MainActivity

Test Suites

1. UI Navigation

# Test Steps Expected
1.1 Splash → Overview Cold start app Splash icon on dark bg, transitions to Overview tab
1.2 Bottom nav tabs Tap Overview → Nodes → Config Each screen renders, no blank screens
1.3 Tab state preservation Scroll down in Config → switch to Nodes → back to Config Scroll position preserved
1.4 Deep nav: Connections Config → Active Connections ConnectionsScreen opens, back arrow returns to Config
1.5 Deep nav: Logs Config → Logs LogsScreen opens, shows "No logs yet"
1.6 Deep nav: Rules Config → Proxy domains EditRulesScreen opens, can type text, back saves
1.7 Overview → Connections Connected → "View all →" link Opens ConnectionsScreen
1.8 System back button Open Logs → press system back Returns to Config, not exit
1.9 Rapid tab switching Tap tabs quickly 10 times No crash, no blank screen
1.10 Theme consistency All screens Dark background (#0D0D0D), correct text hierarchy, purple accents

2. Node Management

# Test Steps Expected
2.1 Empty state First launch / delete all nodes Empty list, header shows "0 nodes"
2.2 Import URI Nodes → "+" → Paste URI → paste vless://... Node added, list refreshes, count updates
2.3 Import subscription Nodes → "+" → Subscription → paste URL Nodes fetched, count updates, toast shows count
2.4 Import JSON Nodes → "+" → JSON → paste sing-box config Nodes parsed correctly
2.5 Import empty text Nodes → "+" → Paste URI → leave empty → Import No crash, no action
2.6 Filter fake nodes Import sub with "剩余流量" / "套餐到期" entries Fake metadata nodes filtered out
2.7 Select node (tap) Tap node row Green dot moves to tapped node, previous deactivated
2.8 Long press → sheet Long press node Bottom sheet: Set Active, Test Latency, Delete
2.9 Delete node Long press → Delete Node removed, list refreshes, helper restarts
2.10 Speed test (button) Tap refresh icon in header Delay values appear with color coding
2.11 Delay colors After speed test Green <300ms, yellow 300-600ms, red >600ms, "timeout" for -1
2.12 Tailscale tab hidden Tailscale disabled in Config Only "Proxy" chip, no "Tailscale"
2.13 Tailscale tab visible Enable Tailscale in Config → Nodes tab "Tailscale" chip appears, tap shows peers
2.14 Node persistence Add nodes → kill app → reopen Nodes still in list

3. VPN Connection

# Test Steps Expected
3.1 First connect Overview → Connect VPN permission dialog → approve → "Online" + green dot
3.2 Connection details Connected state Node name, server IP:port, protocol label, uptime visible
3.3 Protocol label Various node types "VLESS + Reality", "TROJAN + TLS", "SS" etc.
3.4 Uptime counter Stay connected 10s Timer ticks: 00:00:01 → 00:00:10, format HH:MM:SS
3.5 Traffic stats Browse via proxy Upload/download totals + rates update every ~2s
3.6 Recent connections Browse a few sites Up to 5 recent connections show host + chain
3.7 Disconnect Tap Disconnect (red outlined button) Status → "Offline", details disappear, centered message
3.8 Reconnect Disconnect → Connect again No permission prompt second time, reconnects cleanly
3.9 Hot switch node Connected → Nodes → select different node VPN stays up, node switches (ACTION_SWITCH, no disconnect flash)
3.10 Notification Connect VPN Foreground notification "Sing is active" in status bar
3.11 Auto-connect Enable in Config → kill app → reopen VPN starts automatically on launch
3.12 Disconnected state UI Not connected Centered "Not connected", selected node name, purple Connect button

4. Proxy Functionality

Requires: A valid proxy node configured and selected.

# Test Steps Expected
4.1 HTTP browsing Browser → http://www.baidu.com Page loads (direct)
4.2 HTTPS browsing Browser → https://www.google.com Page loads (via proxy)
4.3 DNS resolution Browser → google.com DNS resolves, no NXDOMAIN
4.4 CN direct routing Browse www.baidu.com → check Connections chain = "direct"
4.5 Foreign proxy routing Browse youtube.com → check Connections chain = "proxy"
4.6 Ads block Enable Block Ads → visit ad-heavy site Ad domains show "block" chain in Connections
4.7 Global mode Config → set Global proxy → browse baidu.com chain = "proxy" (not direct)
4.8 Direct mode Config → set Direct → browse google.com chain = "direct"
4.9 Custom proxy keyword Add "openai" to proxy domains → browse openai.com Routes via proxy
4.10 Custom direct keyword Add "google" to direct domains → browse google.com Routes direct
4.11 Custom block keyword Add "ads" to block domains Matching domains blocked

5. Config Persistence

# Test Steps Expected
5.1 Routing mode Set "Global proxy" → navigate to Nodes → back Still "Global proxy"
5.2 Routing mode (restart) Set "Global proxy" → kill app → reopen Still "Global proxy"
5.3 DNS servers Change remote DNS to 1.1.1.1 → restart Still 1.1.1.1
5.4 Toggle persistence Enable Auto-connect → restart Toggle still on
5.5 Custom rules Add "openai" to proxy domains → back → reopen rules Text persisted
5.6 Tailscale auth key Enter auth key → navigate away → return Key still there
5.7 Process death Change settings → swipe app from recents → reopen All settings intact
5.8 Auto-connect + boot Enable auto-connect → reboot device VPN starts after boot (BootReceiver)

6. Connections Monitor

# Test Steps Expected
6.1 Active list Connect → browse → Connections List with host, chain, rule, traffic per connection
6.2 Stats bar Open Connections while connected "N active", total upload/download
6.3 Real-time update Keep Connections open, browse more New connections appear, traffic values change
6.4 Not connected Disconnect → open Connections "VPN not connected" centered text
6.5 Traffic reset Disconnect Overview traffic resets to zero

7. Logs

# Test Steps Expected
7.1 Log streaming Connect VPN → Config → Logs Monospace log text appears, auto-scrolls to bottom
7.2 Horizontal scroll Long log lines Can scroll horizontally to see full lines
7.3 Clear logs Tap Clear button Text resets to "No logs yet"
7.4 Logs after clear Clear → browse a site New logs appear from cleared offset
7.5 File truncation Restart VPN (causes log reset) Logs handle gracefully, no duplicate content
7.6 Long session Leave logs open 5 min Buffer capped at 50K chars, no OOM
7.7 No log file Open logs before first VPN connect Shows "No logs yet", no crash

8. Edge Cases

# Test Steps Expected
8.1 No node selected Delete all nodes → tap Connect Graceful failure, VPN doesn't start, error logged
8.2 Invalid node Add node with wrong host/port → Connect Error in logs, VPN stops, app doesn't crash
8.3 Screen rotation Rotate device while connected State preserved, UI re-renders correctly
8.4 Background resume Connect → press home → wait 5min → reopen Still connected, stats resume polling
8.5 Kill process Connect → force stop → reopen App reconnects to VPN state (isRunning check)
8.6 Empty import Import with blank text → tap Import No crash, no action (button returns early)
8.7 Double tap connect Tap Connect rapidly twice Only one VPN session starts (isRunning guard)
8.8 Clash API unavailable Connect before Clash API ready Traffic stats silently fail, show "--"
8.9 Helper process dead Speed test when helper not running Auto-restarts helper, retries up to 5 times
8.10 100+ nodes Import large subscription List scrolls smoothly (LazyColumn), no jank

9. Performance

# Test Steps Expected
9.1 Cold start Launch from scratch Splash → Overview < 2s
9.2 Tab switching Tap between tabs Instant, no visible delay
9.3 Scroll smoothness 50+ nodes in list, scroll 60fps, no dropped frames
9.4 Traffic polling Connected 10 min, monitor CPU No ANR, no battery drain spike from 2s polling
9.5 Log polling Logs open 5 min No ANR from 1s poll + 50KB buffer
9.6 Connections list 100+ active connections LazyColumn renders smoothly
9.7 Memory stability Use app 30 min (profiler) No memory leak from polling coroutines

Automated Tests

# Run existing UI automation tests
./gradlew connectedAndroidTest

# Run from command line (after emulator boot)
adb shell am instrument -w com.sing.vpn.test/androidx.test.runner.AndroidJUnitRunner

Priority for Automation

  1. Node import (URI parsing, subscription fetch) — pure logic, unit testable
  2. Config persistence — write prefs → kill → read prefs
  3. VPN connect/disconnect lifecycle — UiAutomator
  4. Navigation flow — Compose testing framework
  5. Edge cases (empty state, invalid node) — Compose testing

Quick Smoke Test (5 minutes)

Run these 10 steps after every build:

  1. Install & launch — splash → Overview, dark theme, bottom nav with 3 tabs
  2. Import node — Nodes → "+" → Paste URI → paste a vless:// URI → verify it appears in list
  3. Select node — tap the imported node → green dot activates
  4. Connect — Overview → Connect → approve VPN → verify "Online", uptime ticking
  5. Check traffic — open browser, load a page → verify upload/download stats updating
  6. Check connections — "View all →" → verify connections list populating
  7. Check logs — Config → Logs → verify log output streaming in monospace
  8. Change setting — Config → toggle Block Ads → go to Nodes → back to Config → toggle still on
  9. Disconnect — Overview → Disconnect → verify "Offline" state, traffic resets to zero
  10. Kill & reopen — swipe app from recents → reopen → verify node selected, settings intact