-
Notifications
You must be signed in to change notification settings - Fork 5
Description
Overview
The interop test runner currently tests with a single client implementation (moq-rs). Adding more test clients dramatically increases the value of the interop matrix — instead of "does moq-rs work against each relay?", we get a true N×M matrix showing which implementations can talk to each other.
The framework is already designed for this. run-interop-tests.sh reads from implementations.json and automatically tests every registered client against every registered relay. Adding a new test client is a matter of:
- Building a test client that conforms to the interface spec
- Making its Docker image available
- Registering it in
implementations.json
This issue walks through each step.
Step 1: Implement the Test Client Interface
Your test client needs to conform to the interface defined in the repo docs:
- TEST-CLIENT-INTERFACE.md — The contract: CLI args, environment variables, exit codes, and TAP output format
- IMPLEMENTING-A-TEST-CLIENT.md — Practical guide with pseudocode examples
- tests/TEST-CASES.md — The test case definitions your client should implement
The key requirements:
| Requirement | Details |
|---|---|
| Input | Accept RELAY_URL, TESTCASE, TLS_DISABLE_VERIFY as environment variables |
| Output | TAP version 14 to stdout |
| Exit codes | 0 = all pass, 1 = failures, 127 = unsupported |
| Docker | Packaged as a Docker image |
You don't need to implement every test case to start — even just setup-only is useful for the interop matrix. Use the TAP SKIP directive for tests you haven't implemented yet.
Reference implementation
See moq-test-client in the moq-rs repo for a complete example.
Step 2: Make the Docker Image Available
The test runner executes clients as Docker containers. You have three options for making your image available:
Option A: Pre-built image from a registry (preferred)
If you publish your test client image to a container registry (ghcr.io, Docker Hub, etc.), the CI workflow can just pull it. This is the fastest and simplest approach.
Your implementations.json entry would reference the registry image directly:
"client": {
"docker": {
"image": "ghcr.io/your-org/your-moq-test-client:latest",
"notes": "Pre-built image from GitHub Container Registry"
}
}Option B: Create an adapter
If you publish a Docker image that mostly works but doesn't quite match the interop runner's conventions (e.g., different environment variable names), you can create a thin adapter that wraps your image. Adapters live in adapters/<your-impl>/ and are typically just a Dockerfile.
For example, if your image expects TARGET_URL instead of RELAY_URL:
FROM ghcr.io/your-org/moq-client:latest
ENTRYPOINT ["sh", "-c", "TARGET_URL=$RELAY_URL SKIP_TLS_VERIFY=$TLS_DISABLE_VERIFY exec /usr/local/bin/moq-test-client"]See adapters/README.md for full documentation on the adapter pattern.
Option C: Define a source build
If you don't publish images at all, you can add a build script under builds/<your-impl>/ that compiles your implementation from source and produces a Docker image. See builds/moq-rs/ for an example and builds/README.md for the framework docs.
At minimum you need:
builds/<your-impl>/
├── build.sh # Entry point (must support --target client)
├── Dockerfile.client # Docker build for the test client
└── config.json # Source repo, default ref, targets
The build script should:
- Clone or use a local checkout of your repo
- Build a Docker image tagged as expected by your
implementations.jsonentry - Support
--target clientto build only the client image - Support
--ref <branch>for building specific versions
Which option should I pick?
| Pre-built image (A) | Adapter (B) | Source build (C) | |
|---|---|---|---|
| CI speed | Fast (pull only) | Fast (thin wrapper) | Slow (compile from source) |
| Setup effort | You maintain the image in your own CI | Small Dockerfile in this repo | Build scripts + Dockerfiles in this repo |
| Version control | You control what version gets tested | You control (wraps your image) | Runner controls via git ref |
| Best for | Images that match our conventions | Images that need minor convention mapping | No published image available |
Option A is preferred when your image already matches the conventions. Option B is great when it's close but needs minor env var or path mapping. Option C is the fallback when no image exists.
Step 3: Register in implementations.json
Add or update your implementation's entry in implementations.json to include the client role. If your implementation is already registered as a relay, you just need to add the client field under roles.
Adding a client role to an existing implementation
If your implementation already has an entry (e.g., as a relay), add the client role:
{
"your-impl": {
"name": "Your Implementation",
"organization": "Your Org",
"repository": "https://github.com/your-org/your-impl",
"draft_versions": ["draft-14"],
"roles": {
"relay": {
...existing relay config...
},
"client": {
"docker": {
"image": "ghcr.io/your-org/your-moq-test-client:latest"
}
}
}
}
}Adding a new implementation
If your implementation isn't registered at all yet, see AGENTS.md or IMPLEMENTATIONS.md for the full schema. The key fields:
name: Display nameorganization: Who maintains itrepository: Git repo URLdraft_versions: Array of supported MoQT draft versions (e.g.,["draft-14"])roles.client.docker.image: The Docker image name
What Happens Next
Once your client is registered, the existing automation handles everything:
run-interop-tests.shautomatically discovers your client and tests it against all registered relays- The CI workflow builds/pulls your client image and includes it in the nightly test run
generate-report.shincludes your client in the interop matrix on the results page
No changes to the test runner or report generator are needed.
CI considerations for multiple clients
The current CI workflow (interop-report.yml) hardcodes the moq-rs client build. When a second client is added, the workflow will need a small update. The simplest approach is sequential builds/pulls:
- name: Build/pull test clients
run: |
./builds/moq-rs/build.sh --target client
docker pull ghcr.io/your-org/your-moq-test-client:latestIf build times become a concern later, we can explore parallel matrix builds or other optimizations, but sequential is fine to start.
Checklist
- Test client implements the interface spec (at minimum:
setup-onlytest case, TAP output, Docker image) - Docker image is available (via registry, adapter, or source build)
-
implementations.jsonupdated withclientrole - PR submitted — see the existing moq-rs entry as a reference
Questions?
Reach out to @englishm if you have questions or want to discuss your implementation.