# Offline Client Interop This harness starts several seed-only BitTorrent clients on a Docker Compose network with `internal: true`, generates one private test torrent, mounts the same data into every seeder, and drives this engine against each client independently. It is meant to catch interoperability failures: bad handshakes, encryption/uTP negotiation mistakes, malformed requests, or behavior that makes common clients reject us. It is not a public-swarm or tracker test. ## Clients Default matrix: - `libtorrent-plain-tcp` - `libtorrent-mse-tcp` with RC4 required - `libtorrent-utp` - `libtorrent-utp-mse` - `transmission-tcp` - `transmission-utp` - `transmission-mse-tcp` with encryption required - `aria2-tcp` - `qbittorrent-tcp` - `deluge-tcp` - `rtorrent-tcp` All clients run with DHT, PEX, local peer discovery, UPnP, and NAT-PMP disabled. The fixture torrent includes the deterministic dummy announce URL `http://fixture:9/announce` because rTorrent rejects trackerless torrents, but the runner still injects peers directly. The Compose network is internal-only, so containers cannot route to the internet during the test run. ## Run From the repository root: ```sh docker compose -f interop/docker-compose.yml up --build \ --abort-on-container-exit --exit-code-from runner ``` Useful overrides: ```sh FIXTURE_SIZE=128M TEST_TIMEOUT=180 \ docker compose -f interop/docker-compose.yml up --build \ --abort-on-container-exit --exit-code-from runner ``` Results are written to `interop/results/results.json`. Clean generated containers, networks, and the fixture volume: ```sh docker compose -f interop/docker-compose.yml down -v ``` ## Run One Client The runner supports `--only`, but Compose still starts all default dependencies. For focused debugging, run a shell after the stack is up: ```sh docker compose -f interop/docker-compose.yml run --rm runner \ python3 /work/interop/run_matrix.py \ --fixture /fixture \ --clients /work/interop/clients.json \ --results /results/one.json \ --only transmission-tcp ``` ## Adding Clients Add a seeder service to `docker-compose.yml`, disable all discovery/tracker/NAT features for that client, expose it only on `torrent_lab`, then add an entry to `clients.json`: ```json { "name": "new-client-tcp", "host": "seed-new-client", "port": 6900, "utp": 0, "encryption": 0, "fallback": 0 } ``` The engine currently needs a numeric IP, so the runner resolves the Compose DNS name to IPv4 before calling `engine_add_peer`.