Files
wireguard-admin/docs/TESTING.md
T
2026-10-18 21:39:45 +03:00

7.6 KiB

Testing and Acceptance

Read this document when writing tests, verifying a milestone, or preparing an integration environment. Required behavior and acceptance criteria remain governed by the specification.

Validation

Use fixtures, temporary directories, and replaceable system adapters by default. Never modify /etc/wireguard, restart a host service, read production private keys, or test recovery against the live VPN during ordinary development. Real integration tests must be explicitly selected for a dedicated disposable environment; installing WireGuard on the development host is not enough.

Before Cargo scaffolding exists, validate documentation links and consistency only; do not report build/test commands as passing. Once the Rust project exists, run the relevant focused tests during development and these completion checks for Rust changes:

cargo fmt --all -- --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked
cargo build --locked --release

Use only supported feature combinations; do not assume --all-features is valid. Keep privileged integration tests out of the default test suite. If a check cannot run, report the exact limitation rather than claiming success. Documentation-only edits do not require rebuilding the application.

Prioritize meaningful behavioral checks:

  • Configuration round trips preserve untouched bytes, unknown fields, and administrator comments; managed metadata cannot escape its comment block.
  • Commit/restore do not invoke runtime mutation; draft cancellation, saved/applied differences, and address reservation survive the intended transitions.
  • Allocation respects both ranges, occupied/server addresses, exhaustion, and deferred address reuse without IPv6-wide iteration.
  • Import verifies keys, preserves source files, and distinguishes missing counterparts from parameter conflicts.
  • Encryption works without a password; reissue handles correct/incorrect passwords, corruption, and first-delivery retry boundaries without leaking secrets.
  • Backup failures prevent mutation; restoration works without decryption, excludes recursive archives, and rejects unsafe archive entries.
  • Systemd success without a matching interface/client set is not marked applied; timeouts and failed restarts remain visible without automatic rollback.
  • File and QR delivery encode the same configuration; file failures, overwrite confirmation, non-TTY startup, resizing, and terminal cleanup behave correctly.

Test externally observable behavior and high-impact failure paths. Avoid tests that merely repeat implementation details, introduce root requirements, or assert real secrets in snapshots. Broaden testing when failures or new risks justify it.

Integration testing with Alpine Testcontainers

Production access is limited and experimentation on the production VPN is prohibited. Use three complementary levels: ordinary unit/fixture tests, explicitly selected Alpine container integration tests, and a separate disposable Linux VM for real systemd/D-Bus acceptance. No level authorizes using production as a test environment.

Alpine environment

  • Use testcontainers to start separate Alpine Linux server and client containers on a dedicated test network. Keep the image minimal: wireguard-tools, iproute2, and only any additional tools actually needed by the fixture. Alpine is not a systemd test environment.
  • Build and cache the fixture image ahead of repeated test runs. Pin the Alpine base/version or digest and document the image recipe; avoid package installation and image rebuilding for every test. Reuse image layers, not mutable containers or secret-bearing volumes between tests.
  • The Docker host must provide Linux kernel WireGuard support. Containers share that kernel; installing userspace tools in Alpine does not supply it. Probe prerequisites in the disposable environment and report missing capabilities clearly. Do not automatically load host modules or change host settings.
  • Grant NET_ADMIN in the test containers for their own network namespaces. Do not default to --privileged, SYS_MODULE, host networking, or shared host PID namespaces. Configure IPv6 for the dedicated test network as needed; exercise both address families.
  • Run the application operations or a test driver linked to the real library inside the server container, including the real wireguard-uapi adapter. A host-side test harness may orchestrate containers, but must not query or modify the host's WireGuard interface as a shortcut.
  • Build the in-container executable for Alpine compatibility, preferably the matching musl target. Do not assume a glibc-linked host binary runs in Alpine. Keep compiler/toolchain layers out of the small runtime fixture image where practical.
  • Generate synthetic server/client keys and configurations for each test. Copy fixtures into container-local filesystems. Never mount production files, the host's /etc/wireguard, host system D-Bus sockets, or the Docker socket inside fixture containers.
  • Poll explicit readiness and handshake/traffic conditions with deadlines rather than fixed sleeps. Always clean up containers, dedicated networks, and temporary resources after success or failure. Keep diagnostic artifacts redacted.

Required container scenarios

  1. Start an isolated server and existing client, establish a tunnel, and read real peer state through the runtime adapter.
  2. Create a dual-stack client through the application, Commit, and verify saved files/vault plus unchanged running peer state. Deliver the client configuration and verify that it cannot connect before explicit application.
  3. Use a test-only fixture operation to apply the saved configuration inside the container. Establish the new tunnel, generate IPv4/IPv6 traffic, and verify handshake and increasing counters without asserting exact byte totals.
  4. Delete a client and Commit; verify it is removed from saved data but remains in running state until explicit application, and its address remains reserved. After verified application, check removal, loss of tunnel access, and address release.
  5. Exercise backups and restoration against container-local data: restoration requires no vault password and does not mutate running state. Verify that applying the restored configuration returns the expected clients.
  6. Cover mandatory-backup failure and invalid client import with assertions about unchanged protected state and preserved source files.

Any fixture apply/restart adapter is test-only. It must not weaken the production requirement for a separate systemd restart or be reported as testing the production zbus implementation. If application orchestration uses the fixture service adapter, label those results accordingly.

Systemd acceptance and test execution

  • Use a disposable Linux VM with WireGuard, systemd, and a system D-Bus to verify the actual zbus service adapter, job completion/timeouts, restart verification, and recovery from a selected backup. Do not substitute a mounted host D-Bus or claim Alpine tests cover systemd.
  • Keep container and VM suites out of the default cargo test execution. Once implemented, document their exact opt-in commands and prerequisites in this document. Do not list a planned command as available before its test target exists.
  • When integration testing is explicitly requested, unavailable Docker, WireGuard support, IPv6, or required capabilities means the suite is not executed or incomplete, not passed. Distinguish prerequisite failures from application failures in the report.
  • Report unit/fixture results, Alpine real-WireGuard results, and VM real-systemd results separately. Full acceptance requires the relevant real-system checks, not just mocks or successful container startup.