Files
Rendezvous/docs/integration/test-client.md
KyuubiYoru 2ff7cd6d9d
quality-gate / quality (push) Failing after 1m3s
test(integration): add deterministic NAT topology harness (#14)
2026-07-16 11:50:53 +02:00

4.3 KiB

Diagnostic TestClient integration guide

Tracking: #25

FinalFactory.Rendezvous.TestClient is the smallest supported public-SDK consumer. It exists for integration development, CI smoke checks, deployment verification, and operator diagnosis. It is intentionally not a production game client, game server, matchmaking UI, or relay.

The automated scenario matrix, privileged Linux namespace run, and topology limitations are documented in the deterministic topology harness.

Prerequisites

Start a configured Rendezvous service and note both its HTTP base URL and UDP mediator endpoint. The host needs a tenant-scoped publisher credential from the deployment secret boundary. Put it in an environment variable and pass only that variable's name when the default is unsuitable:

export RENDEZVOUS_PUBLISHER_CREDENTIAL='<deployment-supplied value>'

Never put the credential in a command argument, URL, checked-in configuration, shell trace, or captured test fixture. The development server's signing material is process-ephemeral; credentials from a prior development process are invalid.

Manual three-terminal flow

Start the host:

dotnet run --project src/FinalFactory.Rendezvous.TestClient -- \
  host --service http://127.0.0.1:5000/ --mediator 127.0.0.1:9050 \
  --game space-game --environment development --region local --protocol 1

Browse from another terminal:

dotnet run --project src/FinalFactory.Rendezvous.TestClient -- \
  browse --service http://127.0.0.1:5000/ \
  --game space-game --environment development --region local --protocol 1

Join from a third terminal. Omit --listing for an interactive choice:

dotnet run --project src/FinalFactory.Rendezvous.TestClient -- \
  join --service http://127.0.0.1:5000/ --mediator 127.0.0.1:9050 \
  --game space-game --environment development --region local --protocol 1 \
  --listing 00000000-0000-0000-0000-000000000000

Replace the sample UUID with the public listing ID printed by host or browse. Host and join each create one caller-owned LiteNetLib manager. That same socket sends presence/punch traffic, establishes the authenticated direct connection, and carries the ping/echo/ack/completion payload. The final completion confirms that the host received the reliable acknowledgement; none of this traffic passes through the HTTP service or UDP mediator.

CI and deployment smoke flow

Use --script --json, set --listing when deterministic selection matters, and check the documented process exit code. --timeout-seconds bounds each startup, traversal, or direct-traffic stage; a script host also uses it as its total runtime unless --run-seconds is explicit. A host can add --exit-after-echo so it terminates after the joining peer acknowledges direct traffic and receives the host's completion confirmation. Every wait is bounded by coordinator state and --timeout-seconds; no orchestration should use an unbounded sleep.

The normal test suite contains a real process gate that starts the built Server, host TestClient, and join TestClient, waits for readiness and versioned events, and verifies direct traffic, cleanup, JSON shape, and secret canaries. Process trees are force-terminated in the test cleanup path if normal shutdown fails.

Useful success events are:

  • host.registered, host.ready, host.direct-traffic, and host.deregistered;
  • browse.completed and browse.session; and
  • join.connected, join.direct-traffic, and join.outcome-report.

Failure events preserve stable typed phases and outcomes. When a terminal outcome contains a configured dedicated endpoint, join.fallback reports available with endpoint type dedicated; no raw address is printed and no fallback is started implicitly.

What the proof does and does not establish

The deterministic loopback test proves the complete service/host/client protocol, ticket admission, and peer-to-peer payload path. Loopback is not evidence that all consumer routers, carrier-grade NATs, symmetric NATs, firewalls, VPNs, IPv6 paths, or platform policies permit hole punching. Same-LAN, separated observed endpoints, network namespaces/containers, mediator restart, and adverse topology coverage belong to the topology harness tracked by #14. Production rollout still requires tests from representative networks and a game-owned fallback policy.