Skill: integration-test-go-app
End-to-end runtime verification for services scaffolded by go-scaffolder. The heavy lifting lives in the bundled bash driver at ${CLAUDE_SKILL_DIR}/scripts/run.sh — your job here is to do a friendly pre-flight, invoke the script, and translate its output for the user.
The compile-only smoke runner at tools/smoke/ proves the templates compile. This skill is the next layer up: it actually starts each generated binary, hits real HTTP endpoints, and asserts on the responses + cache state + log content. If smoke says 16/16 pass but this skill fails, the bug is in the runtime wiring (config, env vars, service code path), not the templates.
Step 1: Pre-flight checks
Run a single bash block to fail fast with a clear message if any prerequisite is missing. The script does its own checks too, but doing them here means the user gets actionable errors before docker even spins up:
COMPOSE="$HOME/projects/claude-plugins/plugins/go-scaffolder/docker-compose.yml"
for cmd in docker jq curl go; do
command -v "$cmd" >/dev/null || { echo "MISSING: $cmd not on PATH"; exit 2; }
done
[ -f "$COMPOSE" ] || { echo "MISSING: docker-compose.yml at $COMPOSE"; exit 2; }
echo "preflight OK"
If any check fails, surface the exact line to the user — most of these are one-command fixes (install jq, etc.). Do not try to install on the user's behalf; that's their decision. go-lib itself needs no preflight — it's a public module the driver's go mod tidy fetches from the proxy.
Step 2: Confirm scope (default 5 combos vs. filter)
If the user passed a framework name as an argument (e.g., nethttp, echo), pass it through as a filter so only matching combos run. Otherwise the default set runs:
| Combo | Framework | DB | Cache |
|---|---|---|---|
api-nethttp-postgres-redis |
nethttp | postgres | redis |
api-gin-postgres-memory |
gin | postgres | in-process memory |
api-mux-postgres-none |
mux | postgres | none |
api-echo-postgres-redis |
echo | postgres | redis |
api-nethttp-mysql-none |
nethttp | mysql | none |
| api-chi-mysql-couchbase | chi | mysql | couchbase |
Consumer and publisher combos run too — the compose file carries redis, kafka and rabbitmq. 18 combos total.
Step 3: Invoke the bundled driver
${CLAUDE_SKILL_DIR}/scripts/run.sh [optional-filter]
The script handles everything from here: docker compose up -d --wait postgres mysql redis, then for each combo it renders via tools/smoke -render, runs go mod tidy, drops + recreates the orders table (so each run starts clean — important because every combo seeds 26 entities for pagination), starts the binary on :8080 with DOCS_ENABLED=true and LOG_BODY=true, polls /healthz, runs the assertion sequence (CRUD → cursor → offset → cache → logs → OpenAPI/docs), and SIGTERMs the binary before moving on.
We drop the orders table per combo because pagination assertions check exact row counts (offset_pagination.total >= 25 after seeding 25). Leftover rows from a prior combo would inflate the count and make false positives look like real passes — the cleanup keeps the test signal honest.
The combos run sequentially on port 8080 (one starts, dies, next starts). That's slow but trivial — and trying to parallelize means dealing with port allocation, port-conflict bugs in the test harness, and noisier failure attribution. Sequential is the right tradeoff.
Step 4: Report results
Each combo emits exactly one of these lines to stdout:
[pass] <combo-id>— every assertion passed (CRUD + cursor + offset + cache + logs + OpenAPI/docs)[FAIL] <step> — <combo-id>followed by indented diagnostic lines — one of the assertions failed; the step name tells you which one (render,go mod tidy,wait_healthz,create,find,update,delete,seed-N,cursor-page1,cursor-no-overlap,offset-page1,offset-no-overlap,cache-keys,log-request-id,openapi-json,openapi-yaml,docs-ui)[skip] <combo-id>— consumer/publisher placeholder
Final line: <N> passed, <N> failed, <N> filtered out (total <N>).
When something fails, the binary's full stdout/stderr lives at ${CLAUDE_SKILL_DIR}/logs/<combo>.log. Read the last ~30 lines for the user; that's almost always where the actual error is (DSN parsing, GORM auto-migrate, redis dial, etc.). Don't dump the whole log — it's noisy.
Re-running the skill is idempotent. The drop-table step ensures every run starts with a clean schema; rendered output under ${CLAUDE_SKILL_DIR}/out/ is wiped per combo before re-rendering.
Step 5: Optional teardown
After reporting results, ask the user whether to tear down the docker-compose services:
docker compose -f "$HOME/projects/claude-plugins/plugins/go-scaffolder/docker-compose.yml" down -v
Default behavior: leave services running so the user can iterate quickly (re-run the skill, poke at the running redis manually, etc.). Only tear down when the user says yes — they may want the stack up for other work.
Stub mode is out of scope
Scaffolded services ship with a service-level canned-response stub gated by //go:build stub (see create-go-app/SKILL.md — "Stub mode — FE/BE parallel development"). This skill always tests the real service path:
- The integration binary is built without
-tags=stub, so the stub package is not linked in andfactory_default.goalways returns the production service. run.shsetsSERVICE_BACKEND=realexplicitly as a belt-and-braces guard against a future flip to-tags=stubsilently routing CRUD assertions through the stub.- The scaffolder's
.envdefault ofSERVICE_BACKEND=stubis the right default forgo run -tags=stub ./cmd/...(the FE-integration scenario) — it does not affect this skill.
Stub-mode runtime verification (boot without docker, assert canned responses on /orders, OpenAPI still served at /docs) is a separate concern. If/when it's needed, run it as its own combo class — not bolted onto these CRUD assertions, since the stub is intentionally stateless and would fail every Create→Find round-trip check.
What this skill does NOT do
- Test stub-mode behavior — see "Stub mode is out of scope" above; this skill is real-service only.
- Verify OTel trace export — would need a trace collector; the test does verify
request_idappears in logs, which is sufficient evidence that the request-context propagation works end-to-end. - Authentication / RBAC tests — generated services don't ship with auth.
- Concurrency or load testing — this is functional verification, not throughput.
- Compile-test the templates — that's
tools/smoke -all, separate concern.