Skip to content

Extract AppState into testable ConsaiKit + comprehensive unit tests#20

Merged
DonsWayo merged 3 commits into
mainfrom
test/appstate-coverage
Jun 17, 2026
Merged

Extract AppState into testable ConsaiKit + comprehensive unit tests#20
DonsWayo merged 3 commits into
mainfrom
test/appstate-coverage

Conversation

@DonsWayo

Copy link
Copy Markdown
Owner

What

Extracts the app's orchestration layer (AppState, mock engines, the Terminal shell launcher) out of the App target into a new UI-free ConsaiKit library so it can be unit-tested without SwiftUI, then adds a comprehensive unit-test suite across the pure logic tier.

Why

The largest piece of behavior — AppState (refresh cadence, optimistic actions, stack grouping, error surfacing) — lived in the SwiftUI target and couldn't be tested in isolation. Moving it to a library makes the whole orchestration layer testable with in-memory fakes.

Tests added (86 total, all green)

In-memory fakes + a SpyProcessRunner (records argv/cwd, never spawns):

  • AppState — refresh + vitals carry-forward, container/stack actions, compose up/down gating, image & infra mutations, service start/stop, container detail, every error path, link/forget stack, polling lifecycle, project-name parsing
  • CLI engines (compose, creator, service health) — argv/cwd, non-zero-exit and missing-binary handling, status parsing, binary resolution
  • RegistryStore — save/load round-trip, empty + corrupt-file handling
  • Models — port/mount/network/volume identity, stack counts, cpu% and byte formatting

Coverage

Logic tier ≈ 93% line / 89% region:

File Line cov
AppState 93%
ProjectRegistry 94%
RegistryStore 93%
CLIServiceHealth 91%
CLIComposeEngine 88%
CLIContainerCreator 84%
VitalsSampler / models 90–100%

The I/O-boundary layer (SDKContainerEngine/SDKImageEngine/SDKInfraEngine XPC, ProcessRunner, LogStreamer, ContainerShell) is intentionally left to the E2ETests target + manual QA — it requires a live container daemon and real subprocesses. Their pure inputs (argv builders, parsers, tokenizer, name validation) are unit-tested. See docs/TESTING.md for the two-tier rationale.

Verification

swift test — 86 tests in 23 suites pass.

DonsWayo added 3 commits June 17, 2026 13:46
Move AppState, mock engines, and the Terminal shell launcher out of the App
target into a new UI-free ConsaiKit library so the app's orchestration layer
can be unit-tested without SwiftUI. App views now import ConsaiKit.

Add 86 unit tests across the pure logic tier with in-memory fakes and a
process-spy:
- AppState: refresh/vitals carry-forward, container & stack actions, compose
  up/down gating, image & infra mutations, service start/stop, detail, error
  paths, link/forget, polling lifecycle, project-name parsing
- CLI engines (compose, creator, service health): argv/cwd, exit-code and
  missing-binary handling, status parsing, binary resolution
- RegistryStore: save/load round-trip, empty + corrupt file handling
- Models: ports, mounts, networks, volumes, stacks, cpu/byte math

Logic tier now ~93% line coverage (AppState 93%, ProjectRegistry 94%, models
90-100%). The I/O-boundary layer (SDK XPC engines, ProcessRunner, LogStreamer,
ContainerShell) stays at E2E/manual QA since it requires a live daemon; see
docs/TESTING.md for the two-tier rationale.
This project builds and tests entirely on the developer's macOS 26 / Xcode 26
machine — Apple's container SDK graph can't build on hosted runners, and macOS
runners are billed minutes. Replace the workflow with a local pre-flight script:

  scripts/check.sh            # swift build + swift test
  scripts/check.sh coverage   # + llvm-cov report for the logic layers

Update docs/TESTING.md to document the local-only flow.
No shell scripts: tests run via the native `swift test`, and the llvm-cov
report is a small Swift executable target (Tools/coverage) invoked with
`swift run coverage`.

  swift test --enable-code-coverage   # native test runner
  swift run coverage                  # prints the logic-tier llvm-cov report

The tool only shells out to `xcrun llvm-cov` (never re-invokes swift), so it
avoids the build-lock deadlock a SwiftPM command plugin hits when it tries to
spawn a nested swift build/test. Drops scripts/check.sh and updates docs.
@DonsWayo

Copy link
Copy Markdown
Owner Author

Follow-up on this branch: removed the GitHub Actions workflow (hosted runners can't build Apple's container SDK graph, and the macOS-runner billing is blocked anyway). Verification is now fully local with no shell scripts:

swift test --enable-code-coverage   # native test runner — 86 tests, 23 suites
swift run coverage                  # native Swift tool: prints the logic-tier llvm-cov report

Tools/coverage only shells out to xcrun llvm-cov, so it sidesteps the build-lock deadlock a SwiftPM command plugin hits when spawning a nested swift build. See docs/TESTING.md.

@DonsWayo DonsWayo merged commit 33e8fa7 into main Jun 17, 2026
@DonsWayo DonsWayo deleted the test/appstate-coverage branch June 17, 2026 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant