Files
shopdb-flask/pytest.ini
cproudlock fb53161578
Some checks failed
CI / backend (push) Failing after 9s
CI / naming (push) Successful in 2s
CI / frontend (push) Successful in 10s
CI / migrations-mysql (push) Failing after 7s
Answer "is this a re-run of my install?" from a record, not from the machine
The installer inferred that question from whatever the server happened to look
like: a MySQL service exists, the database has tables, the site exists, the venv
exists. None of those record who created them. A retry after a failed first
install was therefore taken for an upgrade of somebody else's working system,
which produced two dead ends on exactly the retry the wizard invites: stage 3
demanded a mandatory backup of a database its own failed attempt had written,
and then refused to prune tables it had created minutes earlier, because core
migration 7d05 seeds access protocols owned by the computers plugin and any
profile without that plugin hit the refusal every single time.

An install record at ProgramData\ShopDB-Flask\install-state.json answers it
instead. It is written when provisioning STARTS rather than when it finishes,
because the run that dies halfway is precisely the run whose retry needs it, and
it records what this installer created as it goes, so a crashed run no longer
leaves the next one guessing from the machine.

During unfinished first provisioning the pre-migration backup becomes advisory
and prune may force, since every row present was written by an earlier attempt
of the same install. On an established install both stay exactly as they were.
The classification is deliberately asymmetric: an install predating this record
carries a version stamp and probably real data, so it is treated as established
and keeps the mandatory backup. Guessing "first run" there would arm
prune --force against live tables.

Get-CreatedItems comma-protects its return. A zero-length array returned from a
PowerShell function unrolls to $null, and $null.Count is fatal under StrictMode
2.0 - the same fault that made bundle verification fail on every install
earlier. The harness caught it before it shipped.

Tests: deploy/windows/installer/tests/test-install-state.ps1 exercises new
servers, retries, completed installs, unrecorded-but-stamped installs, records
naming another directory, corrupt records, and persistence across a crash.
tests/test_installer_state.py runs it wherever pwsh exists and asserts the
invariants as text everywhere else. Both were confirmed to fail when the prune
gate or the comma protection is removed.

pytest.ini stops collection walking into deploy/windows/installer/bundle, which
is build output holding a complete second copy of the application. Importing
every plugin twice made SQLAlchemy refuse a redefined table and the whole suite
fail to collect, on a tree with nothing wrong in it, purely because an installer
had been built first. It surfaced only when the bundle grew from four plugins to
thirteen.
2026-08-04 21:42:49 -04:00

29 lines
1001 B
INI

[pytest]
# Tests live in tests/. Saying so is not cosmetic.
#
# deploy/windows/installer/bundle/ is BUILD OUTPUT: build-installer.sh stages a
# complete copy of the application there, plugins included. Without this,
# collection walked into it and imported every plugin a second time under a
# second path, so SQLAlchemy raised "Table 'printeditems' is already defined for
# this MetaData instance" and the whole suite failed to collect - on a tree with
# nothing wrong in it, purely because somebody had built an installer first.
#
# It only started biting when the bundle grew from four plugins to thirteen,
# which is the sort of delay that makes this look like a code fault rather than
# a stale artefact.
testpaths = tests
# Belt and braces: even an explicit path or an IDE run must not descend into
# build output or a staged copy of the tree.
norecursedirs =
.git
venv
.venv
node_modules
bundle
dist
build
frontend/dist
frontend/dist-subpath
*.egg-info