dbression 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dbression-0.1.0/.github/workflows/ci.yml +58 -0
- dbression-0.1.0/.github/workflows/publish.yml +51 -0
- dbression-0.1.0/.gitignore +16 -0
- dbression-0.1.0/.python-version +1 -0
- dbression-0.1.0/CHANGELOG.md +65 -0
- dbression-0.1.0/LICENSE +21 -0
- dbression-0.1.0/PKG-INFO +390 -0
- dbression-0.1.0/README.md +353 -0
- dbression-0.1.0/examples/01-hello/HelloSql.test.md +13 -0
- dbression-0.1.0/examples/01-hello/_root.wiki +2 -0
- dbression-0.1.0/examples/01-hello/connection.properties +5 -0
- dbression-0.1.0/examples/02-stored-procedure/BumpCounterTest.test.md +34 -0
- dbression-0.1.0/examples/02-stored-procedure/SuiteSetUp.test.md +23 -0
- dbression-0.1.0/examples/02-stored-procedure/SuiteTearDown.test.md +9 -0
- dbression-0.1.0/examples/02-stored-procedure/_root.wiki +2 -0
- dbression-0.1.0/examples/02-stored-procedure/connection.properties +4 -0
- dbression-0.1.0/examples/03-schema-drift/SchemaSnapshotTest.test.md +17 -0
- dbression-0.1.0/examples/03-schema-drift/SuiteSetUp.test.md +14 -0
- dbression-0.1.0/examples/03-schema-drift/SuiteTearDown.test.md +6 -0
- dbression-0.1.0/examples/03-schema-drift/_root.wiki +2 -0
- dbression-0.1.0/examples/03-schema-drift/connection.properties +4 -0
- dbression-0.1.0/examples/README.md +23 -0
- dbression-0.1.0/pyproject.toml +70 -0
- dbression-0.1.0/src/dbression/__init__.py +1 -0
- dbression-0.1.0/src/dbression/cli.py +173 -0
- dbression-0.1.0/src/dbression/db/__init__.py +12 -0
- dbression-0.1.0/src/dbression/db/connection.py +104 -0
- dbression-0.1.0/src/dbression/db/engine.py +131 -0
- dbression-0.1.0/src/dbression/db/errors.py +63 -0
- dbression-0.1.0/src/dbression/fixtures/__init__.py +32 -0
- dbression-0.1.0/src/dbression/fixtures/base.py +89 -0
- dbression-0.1.0/src/dbression/fixtures/basic.py +628 -0
- dbression-0.1.0/src/dbression/fixtures/inspect_and_store.py +292 -0
- dbression-0.1.0/src/dbression/fixtures/plugins.py +92 -0
- dbression-0.1.0/src/dbression/fixtures/suite_fixtures.py +28 -0
- dbression-0.1.0/src/dbression/parser/__init__.py +4 -0
- dbression-0.1.0/src/dbression/parser/ast.py +66 -0
- dbression-0.1.0/src/dbression/parser/markdown.py +281 -0
- dbression-0.1.0/src/dbression/parser/markdown_writer.py +84 -0
- dbression-0.1.0/src/dbression/parser/tokenizer.py +208 -0
- dbression-0.1.0/src/dbression/parser/wiki.py +204 -0
- dbression-0.1.0/src/dbression/report/__init__.py +11 -0
- dbression-0.1.0/src/dbression/report/console.py +103 -0
- dbression-0.1.0/src/dbression/report/json_report.py +126 -0
- dbression-0.1.0/src/dbression/report/junit.py +188 -0
- dbression-0.1.0/src/dbression/runner.py +310 -0
- dbression-0.1.0/src/dbression/symbols.py +138 -0
- dbression-0.1.0/tests/conftest.py +34 -0
- dbression-0.1.0/tests/test_connection.py +36 -0
- dbression-0.1.0/tests/test_markdown_parser.py +133 -0
- dbression-0.1.0/tests/test_markdown_roundtrip.py +92 -0
- dbression-0.1.0/tests/test_parser.py +128 -0
- dbression-0.1.0/tests/test_phase2_fixtures.py +99 -0
- dbression-0.1.0/tests/test_plugins.py +93 -0
- dbression-0.1.0/tests/test_postgres_live.py +52 -0
- dbression-0.1.0/tests/test_report_junit.py +123 -0
- dbression-0.1.0/tests/test_smoke.py +31 -0
- dbression-0.1.0/tests/test_symbols.py +58 -0
- dbression-0.1.0/tests/test_tokenizer.py +79 -0
- dbression-0.1.0/tests/test_update_fixture.py +122 -0
- dbression-0.1.0/uv.lock +532 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
# Cancel in-progress runs for the same ref when a new commit arrives.
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ci-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
test:
|
|
16
|
+
name: Tests (Python ${{ matrix.python }})
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
python: ['3.12', '3.13']
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
|
|
26
|
+
- name: Install uv
|
|
27
|
+
uses: astral-sh/setup-uv@v6
|
|
28
|
+
with:
|
|
29
|
+
enable-cache: true
|
|
30
|
+
|
|
31
|
+
- name: Set up Python ${{ matrix.python }}
|
|
32
|
+
run: uv python install ${{ matrix.python }}
|
|
33
|
+
|
|
34
|
+
- name: Install project + dev dependencies
|
|
35
|
+
run: uv sync --python ${{ matrix.python }}
|
|
36
|
+
|
|
37
|
+
# Live database tests are gated behind `skipif` on the presence of
|
|
38
|
+
# local connection.properties files — on CI runners they will skip
|
|
39
|
+
# automatically, so unit-only execution is the default here.
|
|
40
|
+
- name: Run tests
|
|
41
|
+
run: uv run python -m pytest -q --tb=short
|
|
42
|
+
|
|
43
|
+
build:
|
|
44
|
+
name: Build sdist + wheel
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
needs: test
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v4
|
|
49
|
+
- uses: astral-sh/setup-uv@v6
|
|
50
|
+
with:
|
|
51
|
+
enable-cache: true
|
|
52
|
+
- run: uv build
|
|
53
|
+
- name: Upload artifacts
|
|
54
|
+
uses: actions/upload-artifact@v4
|
|
55
|
+
with:
|
|
56
|
+
name: dist-${{ github.sha }}
|
|
57
|
+
path: dist/
|
|
58
|
+
retention-days: 7
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Triggered when a GitHub Release is published. Tag the release with
|
|
4
|
+
# the version (e.g. `v0.2.0`) — the workflow builds wheel + sdist and
|
|
5
|
+
# publishes via PyPI Trusted Publishing (OIDC, no API token).
|
|
6
|
+
#
|
|
7
|
+
# One-time setup on PyPI: create a Trusted Publisher entry under
|
|
8
|
+
# https://pypi.org/manage/project/dbression/settings/publishing/
|
|
9
|
+
# with:
|
|
10
|
+
# * Owner: angrydat
|
|
11
|
+
# * Repository name: dbression
|
|
12
|
+
# * Workflow name: publish.yml
|
|
13
|
+
# * Environment: pypi
|
|
14
|
+
on:
|
|
15
|
+
release:
|
|
16
|
+
types: [published]
|
|
17
|
+
|
|
18
|
+
# Allow manual runs for emergencies / re-publishes from a tag.
|
|
19
|
+
workflow_dispatch:
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
build:
|
|
23
|
+
name: Build distributions
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
- uses: astral-sh/setup-uv@v6
|
|
28
|
+
- run: uv build
|
|
29
|
+
- uses: actions/upload-artifact@v4
|
|
30
|
+
with:
|
|
31
|
+
name: dist
|
|
32
|
+
path: dist/
|
|
33
|
+
|
|
34
|
+
publish:
|
|
35
|
+
name: Publish to PyPI
|
|
36
|
+
needs: build
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
environment:
|
|
39
|
+
name: pypi
|
|
40
|
+
url: https://pypi.org/p/dbression
|
|
41
|
+
permissions:
|
|
42
|
+
id-token: write # required for Trusted Publishing (OIDC)
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/download-artifact@v4
|
|
45
|
+
with:
|
|
46
|
+
name: dist
|
|
47
|
+
path: dist/
|
|
48
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
49
|
+
with:
|
|
50
|
+
# Optional belt-and-braces: verify package metadata before upload.
|
|
51
|
+
verify-metadata: true
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv
|
|
11
|
+
|
|
12
|
+
# Oracle InstantClient (lokal, optional, ~90MB) — Pfad bei Bedarf via
|
|
13
|
+
# DBTEST_ORACLE_CLIENT_LIB_DIR an OracleAdapter weitergegeben.
|
|
14
|
+
.instantclient/
|
|
15
|
+
.idea/
|
|
16
|
+
dist/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `dbression` are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
|
|
6
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] — 2026-05-29
|
|
11
|
+
|
|
12
|
+
Initial public release. Functional core that runs real-world DBFit suites against PostgreSQL,
|
|
13
|
+
with code paths in place for SQL Server and Oracle.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Wiki parser** for the DBFit subset that real-world suites actually use, including
|
|
18
|
+
`!- ... -!` multi-line escapes, Oracle `q'~ ... ~'` custom quoting, YAML-style
|
|
19
|
+
front-matter for tags, and lenient detection of fixture-prefixed tables without `!|`.
|
|
20
|
+
- **Executable Markdown** (`.test.md`) — a Markdown-based test format that renders cleanly
|
|
21
|
+
in any viewer and runs the same way `.wiki` files do. Conventions: `### <Fixture> [args]`
|
|
22
|
+
headings, fenced ```` ```sql ```` blocks for SQL, Markdown tables for data rows, and
|
|
23
|
+
`<!-- dbression:env=… -->` style HTML-comment directives.
|
|
24
|
+
- **`dbression convert`** — one-shot or recursive migration tool that turns `.wiki` suites
|
|
25
|
+
into `.test.md`. Both formats coexist; Markdown wins at runtime.
|
|
26
|
+
- **Fixtures**:
|
|
27
|
+
- `Query` with `>>capture` / `<<read` / `:bind` / `_:text-substitution`
|
|
28
|
+
- `Execute` / `Execute Ddl`
|
|
29
|
+
- `Execute Procedure` (dialect-aware: `SELECT`/`CALL` for PG, `EXEC` for MSSQL,
|
|
30
|
+
`BEGIN…END;` for Oracle)
|
|
31
|
+
- `Execute Procedure Expect Exception` with SQLSTATE / ORA-code matching
|
|
32
|
+
- `Insert` (with `>>capture` via `RETURNING`) and `Delete`
|
|
33
|
+
- `Set Parameter` with Java-type-hint conversion
|
|
34
|
+
- `Inspect Table` / `Inspect View` / `Inspect Procedure` with optional body comparison
|
|
35
|
+
- `Store Query` and `Compare Stored Queries`
|
|
36
|
+
- **Multi-database support** via SQLAlchemy 2.0:
|
|
37
|
+
- PostgreSQL through `psycopg` v3 — live-verified
|
|
38
|
+
- SQL Server through `pymssql` (pure Python, no ODBC stack needed) — code-complete
|
|
39
|
+
- Oracle through `oracledb` (thin mode by default, optional thick mode via
|
|
40
|
+
`DBRESSION_ORACLE_CLIENT_LIB_DIR`) — code-complete
|
|
41
|
+
- **Runner** with a DBFit-compatible transaction model: one connection + one transaction
|
|
42
|
+
per suite, with savepoints per test for the default rollback-per-test isolation. A
|
|
43
|
+
`--commit-mode page` flag re-enables the DBFit commit-per-page behavior.
|
|
44
|
+
- **CLI**: `dbression run <path>`, `dbression convert`, `dbression version`. Tag-based
|
|
45
|
+
filtering via `--tag` / `--skip-tag`. Verbose output via `-v`.
|
|
46
|
+
- **Reporters**:
|
|
47
|
+
- Rich console output (pytest-style ✓/✗ tree, full exception bodies, agentic-friendly
|
|
48
|
+
plain-text failures)
|
|
49
|
+
- JUnit XML via `--junit-xml` for Bitbucket Pipelines, Jenkins, GitLab CI, etc.
|
|
50
|
+
- JSON via `--json` for tooling / LLM consumption
|
|
51
|
+
- **Plugin entry-points** under the `dbression.fixtures` group, plus the
|
|
52
|
+
`DBRESSION_PLUGINS` environment variable for ad-hoc / unpackaged extensions.
|
|
53
|
+
- **Connection configuration** via DBFit-compatible `connection.properties`, including
|
|
54
|
+
`${ENV_VAR}` expansion and walk-up resolution of declared paths.
|
|
55
|
+
|
|
56
|
+
### Known limitations
|
|
57
|
+
|
|
58
|
+
- `Update` fixture is stubbed — implementation deferred until a real-world example calls
|
|
59
|
+
for it.
|
|
60
|
+
- Live Oracle connectivity may require InstantClient (thick mode) against servers that
|
|
61
|
+
reject `python-oracledb` thin-mode authentication. Configuration is via
|
|
62
|
+
`DBRESSION_ORACLE_CLIENT_LIB_DIR`.
|
|
63
|
+
|
|
64
|
+
[Unreleased]: https://github.com/angrydat/dbression/compare/v0.1.0...HEAD
|
|
65
|
+
[0.1.0]: https://github.com/angrydat/dbression/releases/tag/v0.1.0
|
dbression-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jürgen Zornig / msgis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
dbression-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dbression
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Rage-quit your flaky DB regressions — modern, lightweight, multi-DB regression testing.
|
|
5
|
+
Project-URL: Homepage, https://angrydata.info/dbression
|
|
6
|
+
Project-URL: Repository, https://github.com/angrydat/dbression
|
|
7
|
+
Project-URL: Issues, https://github.com/angrydat/dbression/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/angrydat/dbression/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Jürgen Zornig <info@angrydata.info>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: database,dbfit,fitnesse,markdown,oracle,postgres,regression,sql,sqlserver,testing
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Information Technology
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: SQL
|
|
24
|
+
Classifier: Topic :: Database
|
|
25
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
26
|
+
Classifier: Topic :: Software Development :: Testing
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.12
|
|
29
|
+
Requires-Dist: markdown-it-py>=4.2.0
|
|
30
|
+
Requires-Dist: oracledb>=4.0.1
|
|
31
|
+
Requires-Dist: psycopg[binary]>=3.3.4
|
|
32
|
+
Requires-Dist: pymssql>=2.3.13
|
|
33
|
+
Requires-Dist: rich>=13.7
|
|
34
|
+
Requires-Dist: sqlalchemy>=2.0
|
|
35
|
+
Requires-Dist: typer>=0.12
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# dbression
|
|
39
|
+
|
|
40
|
+
> ### Rage-quit your flaky DB regressions.
|
|
41
|
+
|
|
42
|
+
[](LICENSE)
|
|
43
|
+
[](https://www.python.org/downloads/)
|
|
44
|
+
|
|
45
|
+
Modern, lightweight database regression testing — read your existing DBFit wikis, run them
|
|
46
|
+
anywhere. `dbression` is a Python re-implementation in the spirit of the fantastic [DBFit](https://dbfit.github.io/dbfit/) Framework:
|
|
47
|
+
**your `.wiki` suites stay, the Java runtime, the bulky FitNesse server, and the Browser based Wiki pages are gone.** Multi-DB, pytest-style CLI, JUnit XML and JSON for CI as well as a developer and agentic friendly STDOUT.
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
$ dbression run tests/
|
|
51
|
+
dbression 0.1.0 — Suite: tests @ postgresql+psycopg://wlk:***@db01/wlk
|
|
52
|
+
|
|
53
|
+
✓ HelloSql 0.004s
|
|
54
|
+
CommonSuite/
|
|
55
|
+
MerklisteSuite/
|
|
56
|
+
✓ AAddBasicTest 0.027s
|
|
57
|
+
✓ BAddNormalizationTest 0.029s
|
|
58
|
+
✓ CAddWhitelistTest 0.025s
|
|
59
|
+
✓ DAddInvalidArgsTest 0.014s
|
|
60
|
+
✓ ERemTest 0.052s
|
|
61
|
+
✓ FViewWbTest 1.236s
|
|
62
|
+
EreignisSuite/
|
|
63
|
+
WaldbrandSuite/
|
|
64
|
+
✓ LookupTest 0.157s
|
|
65
|
+
✗ SchemaTest 0.013s
|
|
66
|
+
|
|
67
|
+
══════════════════════ FAILURES ══════════════════════
|
|
68
|
+
EventsSuite/FloodingSuite/SchemaTest :: Query Row-Mismatch
|
|
69
|
+
SQL: SELECT column_name, data_type FROM information_schema.columns WHERE ...
|
|
70
|
+
Expected: | id | integer | … |
|
|
71
|
+
Actual: | id | integer | … | catastrophic | boolean |
|
|
72
|
+
^^^^^^^^^^^^
|
|
73
|
+
|
|
74
|
+
══════════════════════ SUMMARY ══════════════════════
|
|
75
|
+
8 passed, 1 failed in 1.56s
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Why dbression?
|
|
79
|
+
|
|
80
|
+
| Pain with DBFit | dbression's answer |
|
|
81
|
+
|---|---|
|
|
82
|
+
| Java runtime + FitNesse server + 80 MB InstantClient | One `pip install`, pure Python, ~30 MB |
|
|
83
|
+
| CLI shows only pass/fail counts; failures only visible in web UI | Full exception, SQL, bind values, row diff in stdout |
|
|
84
|
+
| Stagnant, no recent releases | Active development, modern toolchain (uv, SQLAlchemy 2.0, Typer, Rich) |
|
|
85
|
+
| One driver per DB, Oracle thick-mode only | Postgres (psycopg), SQL Server (pymssql), Oracle (oracledb thin) — no native libs needed |
|
|
86
|
+
| No CI integration | JUnit XML + JSON out of the box |
|
|
87
|
+
|
|
88
|
+
**LLM-friendly by design.** Failures land as text — paste them into Claude/ChatGPT/Copilot and
|
|
89
|
+
the model gets every detail it needs to suggest a fix, no screenshots, no context-switching.
|
|
90
|
+
|
|
91
|
+
## Quickstart
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# install (we use uv, but pip works too)
|
|
95
|
+
uv tool install git+https://github.com/angrydat/dbression.git
|
|
96
|
+
|
|
97
|
+
# run
|
|
98
|
+
dbression run tests/
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
There's also an [`examples/`](examples/) folder with three runnable demo suites
|
|
102
|
+
(hello-SQL, stored-procedure-with-capture, schema-drift via `Inspect Table`) — each
|
|
103
|
+
file is browsable Markdown *and* an executable test.
|
|
104
|
+
|
|
105
|
+
### Your first test
|
|
106
|
+
|
|
107
|
+
Drop a `.wiki` file in a folder with a `_root.wiki` and a `connection.properties`:
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
tests/
|
|
111
|
+
├── _root.wiki
|
|
112
|
+
├── connection.properties
|
|
113
|
+
└── HelloSql.wiki
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`_root.wiki`:
|
|
117
|
+
```
|
|
118
|
+
!|DatabaseEnvironment|postgres|
|
|
119
|
+
|ConnectUsingFile|connection.properties|
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`connection.properties`:
|
|
123
|
+
```properties
|
|
124
|
+
service=localhost
|
|
125
|
+
username=postgres
|
|
126
|
+
password=${POSTGRES_PASSWORD} # env-var expansion supported
|
|
127
|
+
database=mydb
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`HelloSql.wiki`:
|
|
131
|
+
```
|
|
132
|
+
!|Query|select 'OK' as connection|
|
|
133
|
+
|connection|
|
|
134
|
+
|OK|
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
$ dbression run tests/
|
|
139
|
+
✓ HelloSql 0.004s
|
|
140
|
+
1 passed in 0.04s
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## What dbression understands
|
|
144
|
+
|
|
145
|
+
The full DBFit fixture subset that real-world suites actually use:
|
|
146
|
+
|
|
147
|
+
| Fixture | What it does |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `Query` | SELECT with expected rows; `>>name` captures values, `<<name` reads them back |
|
|
150
|
+
| `Execute` / `Execute Ddl` | Run arbitrary SQL/PL-SQL/DDL |
|
|
151
|
+
| `Execute Procedure` | Call a stored procedure (dialect-aware: `SELECT/CALL` PG, `EXEC` MSSQL, `BEGIN…END` Oracle) |
|
|
152
|
+
| `Execute Procedure Expect Exception` | Assert a procedure raises a specific SQLSTATE or ORA code |
|
|
153
|
+
| `Insert` / `Delete` | DML with column-header + value-rows, `<<sym` substitution, `>>id` capture via RETURNING |
|
|
154
|
+
| `Set Parameter` | Set a symbol/bind variable from the wiki |
|
|
155
|
+
| `Inspect Table` / `Inspect View` / `Inspect Procedure` | Schema introspection with optional diff against expected |
|
|
156
|
+
| `Store Query` / `Compare Stored Queries` | Snapshot a query result, compare snapshots later |
|
|
157
|
+
|
|
158
|
+
Plus the DBFit-isms you already rely on:
|
|
159
|
+
|
|
160
|
+
- `!- ... -!` escape blocks for multi-line SQL with pipes
|
|
161
|
+
- Oracle `q'~ ... ~'` custom quoting
|
|
162
|
+
- `:name` (bind), `<<name` (cell read), `_:name` (text substitution before compile)
|
|
163
|
+
- Nested sub-suites with `_root.wiki` per directory
|
|
164
|
+
- `SuiteSetUp` / `SuiteTearDown` per suite, with one transaction wrapping everything
|
|
165
|
+
- YAML-style front-matter for tags: `--- Suites: critical NotOnCI ---`
|
|
166
|
+
|
|
167
|
+
## Executable Markdown: `.test.md`
|
|
168
|
+
|
|
169
|
+
If you'd rather never see FitNesse wiki syntax again, write your tests in plain Markdown —
|
|
170
|
+
the same file is a readable document **and** a runnable test:
|
|
171
|
+
|
|
172
|
+
````markdown
|
|
173
|
+
# Example test
|
|
174
|
+
|
|
175
|
+
<!-- dbression:env=postgres -->
|
|
176
|
+
<!-- dbression:connection=conn.properties -->
|
|
177
|
+
|
|
178
|
+
### Query
|
|
179
|
+
|
|
180
|
+
```sql
|
|
181
|
+
select count(*) as cnt from wlk.app_selectset where oid = 999900001
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
| cnt |
|
|
185
|
+
|-----|
|
|
186
|
+
| 0 |
|
|
187
|
+
|
|
188
|
+
### Execute Procedure pr_foo_bar
|
|
189
|
+
|
|
190
|
+
| p_oid | p_order |
|
|
191
|
+
|-----------|-------------------|
|
|
192
|
+
| 999900001 | ASCENDING |
|
|
193
|
+
````
|
|
194
|
+
|
|
195
|
+
Renders in **GitHub, GitLab, Obsidian, Typora, VS Code** out of the box — tables look
|
|
196
|
+
clean, SQL is syntax-highlighted, directives are invisible (HTML comments).
|
|
197
|
+
Conventions:
|
|
198
|
+
|
|
199
|
+
- `### <FixtureName> [args…]` starts a fixture table (longest-prefix match against the registry)
|
|
200
|
+
- A fenced ` ```sql … ``` ` block directly below becomes the SQL argument for `Query` / `Execute` / `Store Query`
|
|
201
|
+
- The next Markdown table → column headers + data rows, with full DBFit idiom support (`>>capture`, `<<read`, `:bind`)
|
|
202
|
+
- `<!-- dbression:env=… -->`, `<!-- dbression:connection=… -->`, `<!-- dbression:tags critical, NotOnCI -->` carry suite directives
|
|
203
|
+
|
|
204
|
+
Built-in migration tool:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
dbression convert path/to/wiki-suite/ # mirrors the directory, generates a .test.md next to each .wiki
|
|
208
|
+
dbression convert one-file.wiki -o out.test.md
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`.wiki` and `.test.md` may coexist — the Markdown file wins at runtime (newer format).
|
|
212
|
+
That lets you migrate one suite at a time.
|
|
213
|
+
|
|
214
|
+
## CI Integration
|
|
215
|
+
|
|
216
|
+
`dbression` writes JUnit-XML (the universal CI lingua franca) and JSON (rich, for tooling) side
|
|
217
|
+
by side. Pick one or both.
|
|
218
|
+
|
|
219
|
+
### Bitbucket Pipelines
|
|
220
|
+
|
|
221
|
+
```yaml
|
|
222
|
+
pipelines:
|
|
223
|
+
default:
|
|
224
|
+
- step:
|
|
225
|
+
name: dbression
|
|
226
|
+
image: python:3.12
|
|
227
|
+
script:
|
|
228
|
+
- pip install uv
|
|
229
|
+
- uv sync
|
|
230
|
+
- uv run dbression run tests/ \
|
|
231
|
+
--junit-xml test-reports/dbression-junit.xml \
|
|
232
|
+
--json test-reports/dbression.json
|
|
233
|
+
artifacts:
|
|
234
|
+
- test-reports/**
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Bitbucket scans `test-reports/*.xml` automatically and renders test results in the pipeline UI.
|
|
238
|
+
No plugin needed.
|
|
239
|
+
|
|
240
|
+
### Jenkins (declarative)
|
|
241
|
+
|
|
242
|
+
```groovy
|
|
243
|
+
pipeline {
|
|
244
|
+
agent any
|
|
245
|
+
stages {
|
|
246
|
+
stage('dbression') {
|
|
247
|
+
steps {
|
|
248
|
+
sh 'uv run dbression run tests/ --junit-xml test-reports/dbression-junit.xml --json test-reports/dbression.json'
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
post {
|
|
253
|
+
always {
|
|
254
|
+
junit 'test-reports/dbression-junit.xml'
|
|
255
|
+
archiveArtifacts 'test-reports/dbression.json'
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### GitLab CI
|
|
262
|
+
|
|
263
|
+
```yaml
|
|
264
|
+
dbression:
|
|
265
|
+
script:
|
|
266
|
+
- uv run dbression run tests/ --junit-xml test-reports/dbression-junit.xml
|
|
267
|
+
artifacts:
|
|
268
|
+
reports:
|
|
269
|
+
junit: test-reports/dbression-junit.xml
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## CLI cheat sheet
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
dbression run <suite-path> # run an entire (sub-)suite
|
|
276
|
+
dbression run <path> -v # show every fixture table, not just the page line
|
|
277
|
+
dbression run <path> --tag critical # only run pages tagged `critical`
|
|
278
|
+
dbression run <path> --skip-tag NotOnCI # skip pages tagged `NotOnCI`
|
|
279
|
+
dbression run <path> --commit-mode page # DBFit-style: commit per page (default: rollback per test)
|
|
280
|
+
dbression run <path> --junit-xml report.xml # CI report
|
|
281
|
+
dbression run <path> --json report.json # programmatic / LLM consumption
|
|
282
|
+
dbression convert path/to/wiki/ # converts .wiki → .test.md (in-place)
|
|
283
|
+
dbression convert file.wiki -o out.test.md # single file with explicit output path
|
|
284
|
+
dbression version
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## How it works
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
┌─────────────────────────────────────────────────────────┐
|
|
291
|
+
│ CLI (typer) dbression run tests/ [--flags] │
|
|
292
|
+
└─────────────────────────────────────────────────────────┘
|
|
293
|
+
│
|
|
294
|
+
▼
|
|
295
|
+
┌─────────────────────┐ ┌───────────────────────────────┐
|
|
296
|
+
│ Parser │ │ Engine Factory (SQLAlchemy) │
|
|
297
|
+
│ Wiki → AST │ │ ┌──────────┐ ┌──────────┐ │
|
|
298
|
+
│ • !- -! escapes │ │ │ psycopg │ │ oracledb │ │
|
|
299
|
+
│ • q'~ ~' quoting │ │ │ (Postgres│ │ (thin) │ │
|
|
300
|
+
│ • Nested suites │ │ └──────────┘ └──────────┘ │
|
|
301
|
+
│ • YAML front matter│ │ ┌──────────────────────┐ │
|
|
302
|
+
└─────────┬───────────┘ │ │ pymssql (SQL Server) │ │
|
|
303
|
+
│ │ └──────────────────────┘ │
|
|
304
|
+
▼ └───────────┬───────────────────┘
|
|
305
|
+
┌─────────────────────────────────────┴───────────────────┐
|
|
306
|
+
│ Runner — one TX per suite, savepoints per test │
|
|
307
|
+
│ Symbol engine: >>capture, <<read, :bind, _:text-subst │
|
|
308
|
+
│ Fixture registry — pluggable via decorator │
|
|
309
|
+
└─────────────────────┬───────────────────────────────────┘
|
|
310
|
+
▼
|
|
311
|
+
┌─────────────────────────────────────────────────────────┐
|
|
312
|
+
│ Reporters │
|
|
313
|
+
│ • Rich console (default) │
|
|
314
|
+
│ • JUnit XML (--junit-xml) │
|
|
315
|
+
│ • JSON (--json) │
|
|
316
|
+
└─────────────────────────────────────────────────────────┘
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## Status
|
|
320
|
+
|
|
321
|
+
`dbression` is **WIP but already useful** — running production-scale DBFit suites today against
|
|
322
|
+
PostgreSQL. Honest state of the parts:
|
|
323
|
+
|
|
324
|
+
| Component | Status |
|
|
325
|
+
|---|------------------------------------------|
|
|
326
|
+
| Wiki parser (DBFit subset) | ✅ verified |
|
|
327
|
+
| Fixtures (Query, Execute, Insert, Delete, Set Parameter, Execute Procedure, Inspect *, Store/Compare Query) | ✅ |
|
|
328
|
+
| PostgreSQL | ✅ verified |
|
|
329
|
+
| SQL Server | 🟡 code-complete via `pymssql`, testing |
|
|
330
|
+
| Oracle | 🟡 code-complete via `oracledb`; testing |
|
|
331
|
+
| JUnit XML + JSON output | ✅ |
|
|
332
|
+
| `Update` fixture | ⏳ stubbed — pull request welcome |
|
|
333
|
+
| `.test.md` native Markdown format + `dbression convert` | ✅ |
|
|
334
|
+
| Plugin entry-points for custom fixtures | ✅ |
|
|
335
|
+
|
|
336
|
+
Don't expect perfect compatibility with every obscure DBFit feature. We promise
|
|
337
|
+
**the subset real teams actually use**, with a sharper UX and a tenth of the footprint.
|
|
338
|
+
|
|
339
|
+
## Contributing
|
|
340
|
+
|
|
341
|
+
`dbression` is small enough to read end-to-end in an afternoon. The whole thing is roughly:
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
src/dbression/
|
|
345
|
+
├── cli.py # typer entrypoint
|
|
346
|
+
├── parser/ # wiki → AST
|
|
347
|
+
├── fixtures/ # one file per fixture family
|
|
348
|
+
├── db/ # connection.properties + SQLAlchemy engine factory
|
|
349
|
+
├── report/ # console + junit + json
|
|
350
|
+
├── runner.py # transactions, savepoints, tag filtering
|
|
351
|
+
└── symbols.py # capture / read / substitution
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Adding a fixture is one decorator and a `run()` method:
|
|
355
|
+
|
|
356
|
+
```python
|
|
357
|
+
from dbression.fixtures.base import Fixture, FixtureContext, FixtureResult, register
|
|
358
|
+
|
|
359
|
+
@register("My Custom Fixture")
|
|
360
|
+
class MyFixture(Fixture):
|
|
361
|
+
def run(self, table, ctx: FixtureContext) -> FixtureResult:
|
|
362
|
+
# ... use ctx.conn (SQLAlchemy Connection) and ctx.symbols
|
|
363
|
+
return FixtureResult(passed=True, message="OK")
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Distributing your own fixtures as a plugin
|
|
367
|
+
|
|
368
|
+
You don't have to fork dbression to add fixtures. Ship them in your own pip-installable
|
|
369
|
+
package via an entry-point:
|
|
370
|
+
|
|
371
|
+
```toml
|
|
372
|
+
# your-plugin-pkg/pyproject.toml
|
|
373
|
+
[project.entry-points."dbression.fixtures"]
|
|
374
|
+
my-fixtures = "my_plugin.fixtures"
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
dbression discovers the entry-point at startup and imports the module — your `@register`
|
|
378
|
+
decorators do the rest. For quick ad-hoc plugins without packaging:
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
PYTHONPATH=/path/to/plugin DBRESSION_PLUGINS=my_plugin dbression run tests/
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Plugin import failures emit a warning and don't crash the run.
|
|
385
|
+
|
|
386
|
+
PRs welcome — please add a test that exercises the new behavior (we use `pytest`).
|
|
387
|
+
|
|
388
|
+
## License
|
|
389
|
+
|
|
390
|
+
MIT — see [LICENSE](LICENSE).
|