Skip to content

Unpack the mock app store fixtures and build the zips at test time - #209

Merged
max-tet merged 2 commits into
mainfrom
chore/clayde/mock-app-store-fixture
Aug 25, 2026
Merged

Unpack the mock app store fixtures and build the zips at test time#209
max-tet merged 2 commits into
mainfrom
chore/clayde/mock-app-store-fixture

Conversation

@ClaydeCode

Copy link
Copy Markdown
Contributor

The mock app store fixtures were checked in as zips, so the compose templates and app_meta.json files inside them could not be read or diffed without unpacking first. This unpacks them into the repo and builds the zips at test time instead.

Two commits: tests: drop the unused large_app fixture, then tests, meta: build the mock app store zips at test time.

What changed

Fixtures are now plain files. Each app directory holds its app_meta.json, docker-compose.yml.template and icon directly. A session-scoped fixture (mock_app_store_zips) packs them into a TemporaryDirectory at session start and removes it at the end, yielding the same <root>/<name>/<name>.zip layout the six consumers already expected.

The unpacked files came out of the zips, not from the loose copies that were sitting beside them — four of those had already drifted from what actually ran. always_on, filebrowser, large_app and mock_app lacked the version: '3.5' line the live template carried, and always_on's named the shard network where the live one names portal. Taking the zip as the source means the suite installs byte-identical apps to before, apart from the port change below.

large_app is gone. No test installed it by name; its only trace was # todo: test_large_app_does_not_start, removed with it. Its app_meta shape duplicated filebrowser's, so the migration corpus loses nothing.

ports: - 80:80 dropped from every template. Nothing consumed the host binding: Traefik reaches apps over the shared portal network at http://<container>:<port> (shard_core/service/traefik_dynamic_config.py:193), and no app in the app-repository publishes a host port. The binding only collided with whatever already held port 80, which made test_app_starts_and_stops unpassable on any host running its own reverse proxy. pause_cycle already had no ports block, so this makes the set consistent.

immich/.env needed a .gitignore negation. The repo's .env rule matched it, so unpacking it as a loose file would have left it uncommitted and the built immich zip would have silently lost it. build_mock_app_store_zips now asserts every fixture file is git-tracked, so the next such file fails the run instead of quietly producing a different app in CI than on a developer machine.

test_all_mock_app_store_metas_migrate reads the app_meta.json files directly rather than opening each zip for one entry.

Verification

  • Full suite on this branch: 308 passed, 0 failed. On main, the same machine gives 1 failed — test_app_lifecycle.py::test_app_starts_and_stops, on Bind for 0.0.0.0:80 failed: port is already allocated.
  • pytest --collect-only gives 308 on both this branch and main, so no test was dropped.
  • Built zips compared file-by-file against the deleted ones from main: every entry byte-identical, and the six templates differ only by the removed ports block.
  • The git-tracked assertion was proven to fire — a stray stray_secret.env in mock_app/ produced AssertionError: mock_app has uncommitted fixture files: ['stray_secret.env'].

Recommended reading order

  1. .gitignore — the negation that lets immich/.env be committed
  2. tests/mock_app_store/** — the unpacked fixtures (the template diffs are the removed ports block; version: '3.5' lines appear because the stale loose copies lacked them)
  3. tests/util.pybuild_mock_app_store_zips and the git-tracked assertion
  4. tests/conftest.py — the session fixture, and mock_app_store taking the built root
  5. tests/test_app_installation.py, tests/test_app_zip.py, tests/test_app_install_crash_recovery.py — consumers moved onto the fixture
  6. tests/test_app_meta_migration.py — reads app_meta.json directly
  7. tests/test_app_lifecycle.py — the removed todo

🤖 Generated with Claude Code

https://claude.ai/code/session_01AHmisdKK8deh7iEd3Shn2Q

ClaydeCode and others added 2 commits August 25, 2026 09:58
Nothing referenced it: no test installs it by name, and its only trace
was the `# todo: test_large_app_does_not_start` comment removed here. Its
app_meta shape duplicated filebrowser's, so it added nothing to the
corpus that test_all_mock_app_store_metas_migrate walks either.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHmisdKK8deh7iEd3Shn2Q
The fixtures were checked in as zips, so the compose templates and
app_meta files they carry could not be read or diffed without unpacking
them first. Four of the loose copies sitting next to the zips had already
drifted from the zip that actually ran: they lacked the `version: '3.5'`
line, and always_on's named the `shard` network where the live one names
`portal`.

The zips are now unpacked into the repo and a session-scoped fixture
packs them into a temporary directory at test start, removing it at
session end. The unpacked files come from the zips themselves, so what
the suite installs is byte-identical to before, bar the port change
below.

Dropping `ports: - 80:80` from every template while the files were open:
nothing consumed the host binding. Traefik reaches an app over the shared
portal network at `http://<container>:<port>`, and no app in the
app-repository publishes a host port. The binding only ever collided with
whatever already held port 80 on the machine, which made
test_app_starts_and_stops unpassable on a host running its own reverse
proxy. pause_cycle already carried no ports block.

immich's zip contains a .env that .gitignore's `.env` rule would have
kept out of the repo, so the built zip would have silently lost it — hence
the negation. build_mock_app_store_zips asserts every fixture file is
git-tracked, so the next such file fails the run instead of quietly
producing a different app in CI than on a developer machine.

test_all_mock_app_store_metas_migrate now reads the app_meta.json files
directly rather than unpacking each zip for one entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHmisdKK8deh7iEd3Shn2Q
@max-tet
max-tet merged commit 02bd02d into main Aug 25, 2026
7 checks passed
@max-tet
max-tet deleted the chore/clayde/mock-app-store-fixture branch August 25, 2026 10:12
ClaydeCode added a commit that referenced this pull request Aug 25, 2026
The mock app store no longer ships zips; build_mock_app_store_zips packs
each app directory at session start (#209). Leaving this one in place
would pack a stale copy of the app inside the zip built from it.

Its app_meta.json, docker-compose.yml.template and icon.svg were already
byte-identical to the zip's contents, so nothing is lost.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHmisdKK8deh7iEd3Shn2Q
ClaydeCode added a commit that referenced this pull request Aug 25, 2026
The mock app store no longer ships zips; build_mock_app_store_zips packs
each app directory at session start (#209). Leaving this one in place
would pack a stale copy of the app inside the zip built from it.

Its app_meta.json, docker-compose.yml.template and icon.svg were already
byte-identical to the zip's contents, so nothing is lost.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHmisdKK8deh7iEd3Shn2Q
ClaydeCode added a commit that referenced this pull request Aug 26, 2026
The mock app store no longer ships zips; build_mock_app_store_zips packs
each app directory at session start (#209). Leaving this one in place
would pack a stale copy of the app inside the zip built from it.

Its app_meta.json, docker-compose.yml.template and icon.svg were already
byte-identical to the zip's contents, so nothing is lost.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHmisdKK8deh7iEd3Shn2Q
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.

2 participants