Files
cli/sunbeam-net/tests/docker-compose.yml
Sienna Meridian Satterwhite bea8a308da test(net): add integration test harness against Headscale
Spins up Headscale 0.23 (with embedded DERP) plus two Tailscale peers
in docker compose, generates pre-auth keys, and runs three integration
tests behind the `integration` feature:

- test_register_and_receive_netmap: full TS2021 → register → first
  netmap fetch
- test_proxy_listener_accepts: starts the daemon and waits for it to
  reach the Running state
- test_daemon_lifecycle: full lifecycle including DERP connect, then
  clean shutdown via the DaemonHandle

Run with `sunbeam-net/tests/run.sh` (handles compose up/down + auth
key provisioning) or manually via cargo nextest with the env vars
SUNBEAM_NET_TEST_AUTH_KEY and SUNBEAM_NET_TEST_COORD_URL set.
2026-04-07 13:42:46 +01:00

95 lines
3.1 KiB
YAML

# Integration test stack for sunbeam-net VPN client.
# Spins up Headscale (coordination + embedded DERP) and two Tailscale
# peers so we can test the full TS2021 → WireGuard → DERP pipeline.
#
# Usage:
# docker compose -f sunbeam-net/tests/docker-compose.yml up -d
# docker compose -f sunbeam-net/tests/docker-compose.yml exec headscale \
# headscale preauthkeys create --user test --reusable --expiration 1h
# # Copy the key, then:
# SUNBEAM_NET_TEST_AUTH_KEY=<key> \
# SUNBEAM_NET_TEST_COORD_URL=http://localhost:8080 \
# cargo test -p sunbeam-net --features integration --test integration
# docker compose -f sunbeam-net/tests/docker-compose.yml down
services:
# ── Headscale (coordination server + embedded DERP relay) ───────────
headscale:
image: headscale/headscale:0.23
command: serve
ports:
- "8080:8080" # control plane (TS2021 Noise + HTTP API)
- "3478:3478/udp" # STUN
- "9090:9090" # metrics
volumes:
- ./config/headscale.yaml:/etc/headscale/config.yaml:ro
- headscale-data:/var/lib/headscale
healthcheck:
test: ["CMD", "headscale", "nodes", "list"]
interval: 5s
timeout: 5s
retries: 15
# ── Tailscale peer A (validates that Headscale is working) ──────────
# This peer registers with Headscale and stays online so our Rust
# client can discover it in the netmap and attempt WireGuard tunnels.
peer-a:
image: tailscale/tailscale:stable
hostname: peer-a
depends_on:
headscale:
condition: service_healthy
environment:
TS_AUTHKEY: "${PEER_A_AUTH_KEY}"
TS_STATE_DIR: /var/lib/tailscale
TS_EXTRA_ARGS: --login-server=http://headscale:8080
cap_add:
- NET_ADMIN
- NET_RAW
volumes:
- peer-a-state:/var/lib/tailscale
# Tailscale doesn't have a great healthcheck, but it registers fast
healthcheck:
test: ["CMD", "tailscale", "status", "--json"]
interval: 5s
timeout: 5s
retries: 20
# ── Tailscale peer B (second peer for relay/direct tests) ───────────
peer-b:
image: tailscale/tailscale:stable
hostname: peer-b
depends_on:
headscale:
condition: service_healthy
environment:
TS_AUTHKEY: "${PEER_B_AUTH_KEY}"
TS_STATE_DIR: /var/lib/tailscale
TS_EXTRA_ARGS: --login-server=http://headscale:8080
cap_add:
- NET_ADMIN
- NET_RAW
volumes:
- peer-b-state:/var/lib/tailscale
healthcheck:
test: ["CMD", "tailscale", "status", "--json"]
interval: 5s
timeout: 5s
retries: 20
# ── Simple HTTP echo server on peer-a's tailnet IP ──────────────────
# Used to verify end-to-end TCP connectivity through the WireGuard tunnel.
# Listens on peer-a's container network; reachable via peer-a's tailnet IP.
echo:
image: hashicorp/http-echo:latest
command: -listen=:5678 -text="sunbeam-net integration test"
network_mode: "service:peer-a"
depends_on:
peer-a:
condition: service_healthy
volumes:
headscale-data:
peer-a-state:
peer-b-state: