test: realistic-client protocol coverage (40 new integration tests) #20
test/realistic-client-protocol-coverage
into main
Closes #30 at the test-writing level (the underlying feature gaps remain tracked in #30).
Summary
40 new integration tests across 6 suites that drive real `git` CLI invocations and real HTTP clients through `UploadPackV2` and `ReceivePack`. Motivation: after the two back-to-back UploadPackV2 regressions (PR #18, PR #19), we needed actual client-facing coverage for every advertised capability and every negotiation path — the bugs all hid in paths no test drove a real client through.
Zero production code changes. Each skipped test links its tracking note (capability gap or known bug).
What’s new
Shared harness — `test/support/git_daemon.ex`:
- `start_upload_pack/1` — git:// TCP daemon → UploadPackV2
- `start_receive_pack/2` — git:// TCP daemon → ReceivePack (hooks forwardable)
- `start_http_smart/2` — HTTP/1.1 mini-server routing GET /info/refs + POST /git-(upload|receive)-pack. No Plug/Cowboy dep; ~100 lines of raw :gen_tcp.
- Helpers: `git_at`, `git!`, `init_client_dir`, `seed_client_clone`
- Per-connection `repo_fun` for stale-haves scenarios.
Six new test files in `test/ex_git_objectstore/integration/`:
| File | What it covers |
|---|---|
| `git_daemon_smoke_test.exs` | Harness smoke checks |
| `upload_pack_v2_negotiation_test.exs` | Stale haves, partial overlap, deep divergence, negotiate-only, concurrent push/fetch |
| `upload_pack_v2_capabilities_test.exs` | symrefs, peel, unborn, shallow, deepen, blob:none, tree:0, wait-for-done, advertisement canary |
| `upload_pack_v2_dataplane_test.exs` | >64KB sideband, >1MB pack (slow), 250 refs, ref-prefix filter, client disconnect mid-pack, TCP-chunk invariance |
| `receive_pack_git_client_test.exs` | new branch, FF, non-FF ± –force, delete ref, –atomic, update-hook rejection, thin-pack REF_DELTA, concurrent push |
| `smart_http_test.exs` | clone / fetch / push over HTTP, two-daemon stale-haves, direct POST (no git client) — hits the done+haves+no-match path the git CLI avoids |
Results
`mix test –include integration`:
``` 753 tests, 0 failures, 12 skipped (35 excluded) ```
Broken-down: ~40 new tests in this PR, 12 of them are currently skipped with a `@tag skip: “…”` message explaining what’s missing. They become active once the referenced capability or bug is addressed.
Bugs found while writing
- Issue #29 — `UploadPackV2.feed/2`’s `has_complete_command?` treats `delim` (`0001`) as a command terminator. TCP-chunked requests that split between delim and flush cause the state machine to process an incomplete command and transition to `:done`, ignoring the rest. Caught by `test “fetch request response is invariant under TCP chunking”` in the dataplane suite (skipped pending fix).
- The direct-POST HTTP test deterministically reproduces the bug PR #19 fixes (`expected ‘acknowledgments’, received ‘packfile’`). Skipped pending PR #19 merge.
Follow-ups
All skipped-test feature gaps are indexed in the master tracking issue #30.
Test plan
- `mix test –include integration` — 753 pass, 12 skipped
- `mix format –check-formatted`
- `mix credo –strict` on touched files — zero issues
- CI green