Development and testing¶
Setup¶
git clone https://github.com/mariuz/fbadmin && cd fbadmin
python -m venv .venv && . .venv/bin/activate
pip install -e "backend[dev]"
(cd frontend && npm install && npm run build)
scripts/test-servers.sh # Firebird 5/3/4 in Docker on ports 3050/3053/3054
Run the app with auto-reload, and the UI with hot reload:
fbadmin --reload --no-browser --log-level debug
cd frontend && npm run dev # http://localhost:5173, proxies /api to :5050
Backend tests¶
cd backend && python -m pytest -q # Firebird 5 on :3050
FBADMIN_TEST_PORT=3053 python -m pytest -q # Firebird 3
FBADMIN_TEST_PORT=3054 python -m pytest -q # Firebird 4
python -m pytest -q -m "not slow" # skip the slow property tests
ruff check backend
Integration tests skip when no server is reachable. FBADMIN_TEST_HOST, _PORT,
_PASSWORD and _DIR (a directory on the server) point them elsewhere.
Fuzz and property tests (hypothesis)¶
tests/test_sqlsplit_fuzz.pyfuzzes the SQL splitter and parameter scanner: random text never crashes it and statement offsets/lines/columns always point into the script; generated scripts (strings with terminators, quoted identifiers, comments, nestedBEGIN … ENDandCASE … END,SET TERM) split back into exactly the statements they were built from.HYPOTHESIS_PROFILE=thoroughruns 5000 examples per property.tests/test_ddl_property.pygenerates schemas (domains, tables with every data type of the server version, defaults, collations, identity and computed columns, PK, UNIQUE, CHECK and FK constraints, indices, comments), applies them, extracts their DDL through the API, replays it into a second database and requires identical DDL.FBADMIN_DDL_EXAMPLES=200runs more examples (default 12).
When hypothesis finds a failure it prints the smallest failing example; add it as a regular test next to the fix.
firebird-qa compatibility (optional, slow)¶
tests/test_firebird_qa.py reads the isql scripts of the
firebird-qa test suite (parsed with ast,
never imported):
- every script must be split by
split_sql()exactly like isql would (a reference splitter implements isql's rules; scripts using Firebird 6SET AUTOTERMare skipped); - a sample of the DDL-heavy scripts is run into a fresh database, then every object's DDL is extracted, replayed into a second database and compared.
git clone --depth 1 https://github.com/FirebirdSQL/firebird-qa /tmp/firebird-qa
FBADMIN_QA_DIR=/tmp/firebird-qa python -m pytest -q -s tests/test_firebird_qa.py
FBADMIN_QA_CLONE=1 python -m pytest tests/test_firebird_qa.py # clones into ~/.cache/fbadmin
FBADMIN_QA_SAMPLE=300 FBADMIN_QA_SEED=7 ... # bigger sample, other seed
It runs weekly in .github/workflows/compat.yml. It already found three splitter bugs
(comments before SET TERM, CREATE COLLATION … CASE INSENSITIVE,
ALTER DATABASE BEGIN BACKUP).
Native driver tests¶
tests/test_native_driver.py runs when firebird-driver is installed and libfbclient
can be loaded. To run the whole suite through the native adapter:
pip install -e "backend[native]"
FBADMIN_DRIVER=native FBADMIN_FBCLIENT=/path/to/libfbclient.so python -m pytest -q
(A libfbclient can be copied out of the Firebird container:
docker cp -L fb5:/opt/firebird/lib/libfbclient.so.2 .; it also needs libtommath.)
End-to-end tests (Playwright)¶
e2e/ is a separate npm package with Playwright tests that drive
a real browser against a real fbadmin and a real Firebird server: registering a server,
browsing the tree, properties/DDL/dependencies, running queries, :name parameters,
error positions, cancelling a long query, editing and saving data in the grid, and the
opt-in update check (no request before opting in).
(cd frontend && npm run build) # the tests use the built UI
cd e2e && npm install
npx playwright install chromium # once (or use an installed Chromium, see below)
FBADMIN_PYTHON=../.venv/bin/python npx playwright test
npx playwright test --headed # watch it
npx playwright show-report # after a failure: traces and screenshots
Playwright starts python -m fbadmin from backend/ on port E2E_PORT (default 5106)
with a temporary data directory. Variables: FB_HOST, FB_PORT (3050), FB_PASSWORD,
FB_DB_DIR (a directory on the Firebird server), E2E_BASE_URL (test an already running
instance), PW_CHROMIUM_PATH (use a specific Chromium binary). The e2e CI job runs them
against a Firebird 5 service container.
API types¶
frontend/src/api-types.gen.ts holds TypeScript types for every endpoint, generated from
FastAPI's OpenAPI schema with openapi-typescript:
scripts/gen-api-types.sh # regenerate after changing an endpoint or a pydantic model
scripts/gen-api-types.sh --check # what CI runs: fails when the file is stale
Request bodies in the API clients (frontend/src/api.ts and the features/*/api.ts files) are
typed from it. Use Body<"/api/schedules", "post"> from api.ts, which takes the JSON body of
an OpenAPI path and also fails to compile when the path no longer exists. You can also use the
schemas directly (components["schemas"]["ServerIn"]). Request-body fields that have defaults
on the server are optional (--default-non-nullable false). Most endpoints return plain
dicts, so their response types are still written by hand in types.ts.
After merging branches that touch the API, regenerate the file instead of resolving
conflicts in it by hand.
Frontend bundle¶
vite.config.ts splits vendor code into long-lived chunks (react, codemirror,
sql-formatter, vendor), and App.tsx lazy-loads the Query Tool, data grid, monitor
and processes views. The app's own start-up chunk is about 70 kB. CodeMirror is still
loaded at start-up because the SQL tab and dialogs use the editor.