agent-orchestrator/test/cli
prateek a34094e7d8
refactor: simplify session lifecycle and zellij runtime (#62)
* refactor: remove canonical lifecycle state

* refactor: move sqlite stores into subpackage (#62)

* refactor: strengthen sqlite generated model types (#62)

* refactor: remove lifecycle notifications (#62)

* docs: remove notification cleanup leftovers (#62)

* refactor: narrow lifecycle manager scope (#62)

* refactor: keep PR nudges in lifecycle (#62)

* refactor: trim unused storage and lifecycle contracts (#62)

* refactor: align storage and runtime observation surfaces (#62)

* refactor: remove stale daemon and adapter bloat (#62)

* test: fix terminal ring race assertion (#62)

* refactor: trim lifecycle and http boilerplate (#62)

* refactor: expose sqlite CDC source directly (#62)

* refactor: share process liveness checks (#62)

* test: trim lifecycle store fake surface (#62)

* refactor: separate PR observations from storage rows (#62)

* refactor: trim remaining cleanup surfaces (#62)

* refactor: narrow observation and PR display APIs (#62)

* refactor: move PR write DTOs out of domain (#62)

* refactor: normalize PR domain storage types (#62)

* refactor: remove unused session port interface (#62)

* fix: reject unexpected CLI arguments (#62)

* refactor: use session metadata for spawn completion (#62)

* refactor: narrow session runtime dependency (#62)

* fix: validate zellij version in doctor (#62)

* refactor: split observation port DTOs (#62)

* chore: add sqlc generation script (#62)

* refactor: clarify terminal mux naming (#62)

* fix: tolerate nil loggers (#62)

---------

Co-authored-by: itrytoohard <ayetrytoohard@gmail.com>
2026-06-01 08:42:49 +05:30
..
Dockerfile refactor: simplify session lifecycle and zellij runtime (#62) 2026-06-01 08:42:49 +05:30
README.md test(cli): port the E2E suite to cross-platform Go; slim the Docker harness 2026-06-01 03:14:08 +05:30
install-check.sh test(cli): port the E2E suite to cross-platform Go; slim the Docker harness 2026-06-01 03:14:08 +05:30

README.md

ao CLI end-to-end tests

These tests drive the real ao binary the way a user would — start
statusdoctorstop, plus the daemon-control HTTP surface — and assert
the whole thing works. They run against isolated, throwaway state (a per-test
temp run-file + data dir + an OS-assigned free loopback port), so they never
touch a developer's real AO installation.

Two tiers

Tier What Where
Comprehensive (primary) A cross-platform Go suite that builds ao and exercises the full behaviour. Runs natively on ubuntu + macOS + windows — the only way to cover the OS-specific process-detach paths (setsid vs CREATE_NEW_PROCESS_GROUP) and os.UserConfigDir() resolution. backend/internal/cli/e2e_test.go (build tag e2e)
Fresh-install (hardening) Proves a freshly installed binary works on a clean machine with no Go toolchain and no developer state. test/cli/Dockerfile + test/cli/install-check.sh

Run it

The Go suite (fastest, cross-platform):

cd backend
go test -tags e2e ./internal/cli/...              # run it
go test -tags e2e -v -run TestE2E ./internal/cli/...   # verbose: prints every command + output

It builds its own ao binary; git must be on PATH (required by doctor).
-v logs each ao invocation and its full output, which is the audit trail you
get for free from go test.

Fresh-machine install, in a clean container:

docker build -f test/cli/Dockerfile -t ao-cli-smoke .
docker run --rm --init ao-cli-smoke

--init gives the container a real PID-1 reaper (tini) so the daemon the
check starts is reaped after stop instead of lingering as a zombie.

What the Go suite covers

TestE2E_VersionAndHelp (version/--version/help, daemon hidden) ·
TestE2E_DoctorDoesNotTouchTheStore (doctor text + --json; proves it does
not create/migrate ao.db) · TestE2E_StatusStopped (stopped + idempotent
stop) · TestE2E_Lifecycle (start, ready, idempotent, daemon-created store,
/healthz identity, stop, run-file cleanup) · TestE2E_ShutdownGuard (the
/shutdown CSRF + DNS-rebinding 403 guard, daemon survives) ·
TestE2E_StaleRunFile (dead-PID run-file → stale → cleaned) · TestE2E_ExitCodes
(2 usage / 1 runtime / config error) · TestE2E_Completion (all four shells).

Why a Go suite (not bash, not Python)

The bash version grew past the point where bash was a good fit, and a Linux
container can't observe the macOS/Windows code paths at all. A Go os/exec
suite is the right home: it uses the repo's own toolchain (runs under go test),
gives real assertions and structured data, and — critically — runs natively on
the Windows and macOS runners, finally covering the CREATE_NEW_PROCESS_GROUP
detach path and per-OS config-dir resolution. The container stays as a thin
"clean install actually works" check.

Extending

  • Add a case: a new TestE2E_* function (or a t.Run subtest) in
    e2e_test.go. Use newEnv(t) for isolated state and the env.run/httpGet/
    postShutdown helpers.
  • Add an OS: extend the matrix.os list in .github/workflows/cli-e2e.yml.
  • Deeper per-OS path assertions (state resolves under the OS-native config dir
    when AO_RUN_FILE/AO_DATA_DIR are unset) fit best as unit tests in
    internal/config.