---
title: Testing and interop
description: Run the local suite, the benchmarks, and the opt-in Rust interop gates that back the wire-compatibility claim.
icon: flask
---

go-iroh's central claim is wire compatibility with Rust iroh. This page is how
you check it rather than take it on faith. The commands are the ones the
go-iroh README documents; run them from a checkout of the module.

## The local suite

```sh
go test ./...
```

For a repeatable check that ignores the test cache:

```sh
go test ./... -count=1
```

This covers the public packages, the `qng` transport extensions, and local
relay and direct behavior. It requires nothing beyond a Go toolchain — no Rust,
no network.

## Benchmarks

Loopback stream and datagram latency and throughput, with raw TCP and UDP
baselines:

```sh
GOMAXPROCS=4 go test ./iroh -run '^$' -bench 'Benchmark(Conn|RawTCP|RawUDP)' \
    -benchtime=5s -count=5
```

`BenchmarkRawUDPMagicQueuedPingPong` is the closest raw-UDP latency baseline
for the magic-socket path: it uses the same receive queue depth, pooled receive
buffers, caller-buffer copy, and separate write queue shape as the direct IP
transport. Compare against that rather than against a naive UDP loop, which
measures a different program.

## Live Rust interop gates

These are opt-in because they require a checked-out and built Rust iroh tree.
They are the only tests in the module where a real Rust process is on the other
end of the wire.

Connectivity and transfer:

```sh
GO_IROH_LIVE_RUST_INTEROP=1 \
IROH_RUST_REPO=/path/to/n0-computer/iroh \
go test ./internal/compat -run 'TestLiveRust' -count=1 -v

GO_IROH_LIVE_RUST_INTEROP=1 \
IROH_RUST_REPO=/path/to/n0-computer/iroh \
go test ./iroh -run TestLiveRustTransferFetchPingDirectPath -count=1 -v
```

Gossip has its own gate, which builds a Rust `iroh-gossip` helper from
`gossip/testdata/rust-gossip-interop` and exchanges membership and broadcast
over `/iroh-gossip/1`. It requires `cargo`:

```sh
GO_IROH_LIVE_RUST_GOSSIP=1 go test ./gossip -run TestLiveRustGossipInterop -count=1 -v
```

The README states these gates cover live echo, the Rust `transfer`
provider/upload path, direct-path selection, qlog evidence for QNT frames, and
Go↔Rust gossip membership and broadcast — "when the host environment provides
the required binaries and network topology". That conditional matters: a gate
that is skipped is not a gate that passed. Read the test output, not just the
exit code.

## What is not mechanically proven

Being precise about the boundary is more useful than a badge:

- The `blobs` and `docs` packages have no live Rust gate of their own in the
  commands above; their compatibility rests on the ported wire codecs and unit
  vectors, not on a running Rust peer.
- Browser (js/wasm) support is a compile target plus a smoke test
  (`cmd/wasmrelaytest`), not a tested transport matrix.
- The experiment modules have their own tests and no compatibility posture at
  all.

## The compatibility matrix

The cross-implementation harness described in
`design/compat-harness-spec.md` now exists as a nested module,
`iroh-compat-harness/`, and produces the `COMPATIBILITY.md` matrix and the
parity badge in the README.

It is worth understanding what its "pass" means, because the harness is
deliberately strict:

- A passing cell **requires a real Rust process**, and records that process
  and the **SHA-256 of the binary** it ran. A cell with no recorded peer
  cannot pass.
- **Setup errors and unsupported cells never count as passes.** Unsupported
  means go-iroh does not implement the thing, and is reported as such rather
  than quietly omitted.
- Scenarios declare a *predicted* verdict in
  `iroh-compat-harness/scenarios/`, so a cell that passes for the wrong reason
  is visible.

Scenarios span four groups — `handshake`, `discovery`, `relay`, and `vectors`
— run against pinned Rust iroh releases. The vectors group is the interesting
one for day-to-day work: the corpus is generated by the pinned Rust driver and
committed, so `go test ./vectors` re-verifies Rust-generated bytes **offline
and in pure Go**, with `make vectors` regenerating and requiring byte
identity.

Reproduce the full matrix from a clean checkout:

```sh
cd iroh-compat-harness
make parity          # Docker: builds the pinned Rust image, runs both sides
make parity-native   # or use native pinned binaries
```

This writes `results/results.json`, `results/badge.json`, and the
repository-root `COMPATIBILITY.md`.

<Note>
The harness lands with the `compat-harness` branch. If you are reading a
checkout of `main` that has no `iroh-compat-harness/` directory, the branch has
not merged yet.
</Note>

## Testing your own protocol

Two patterns from the repository are worth copying:

- Bind both endpoints to `netip.AddrPortFrom(netip.IPv6Loopback(), 0)` and dial
  `netaddr.NewEndpointAddr(server.ID()).WithIP(server.LocalAddr())`. No relay,
  no discovery, no network — this is how the in-repo `Example` functions in
  `iroh/example_test.go` run.
- Write examples as `Example` functions with an `// Output:` comment so `go
  test` keeps your documentation honest. That is how go-iroh documents its own
  API, and it is why the samples on this site could be verified before
  publication.

## Next steps

- [Troubleshooting](troubleshooting) — when a test hangs instead of failing.
- [Ecosystem map](ecosystem-map) — the maturity tiers these gates back.
