Skip to content

test: move real-DB store tests to tests/integration/#43

Open
aivong-openhands wants to merge 5 commits intomainfrom
test/fix-store-tests-to-integration
Open

test: move real-DB store tests to tests/integration/#43
aivong-openhands wants to merge 5 commits intomainfrom
test/fix-store-tests-to-integration

Conversation

@aivong-openhands
Copy link
Copy Markdown
Owner

@aivong-openhands aivong-openhands commented Apr 17, 2026

  • A human has tested these changes.

Why

The store tests in tests/unit/ spun up a real SQLite database on every run, making them integration tests by nature. Running them alongside true unit tests inflates CI time and blurs the unit/integration boundary. Moving them to tests/integration/ makes the distinction explicit and allows them to be skipped or run separately.

Summary

  • Move test_org_store.py and test_api_key_store.py from tests/unit/ to tests/integration/
  • Move tests/unit/storage/test_api_key_store.py (system key tests) to tests/integration/test_api_key_store_system_keys.py
  • Add tests/integration/conftest.py with shared DB fixtures (db_path, engine, session_maker, async_engine, async_session_maker) and a pytest_collection_modifyitems hook that auto-applies @pytest.mark.integration to all collected tests
  • Register integration marker in enterprise/pyproject.toml
  • Add .github/workflows/enterprise-integration-tests.yml — a dedicated CI job that runs tests/integration/ so the moved tests remain in CI coverage

Issue Number

N/A

How to Test

cd enterprise && .venv/bin/python -m pytest tests/integration/ -v

Integration tests can be excluded from a unit-only run with -m "not integration".

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

Notes

  • engine and async_engine fixtures are yield-based and call .dispose() in teardown to release SQLite connections
  • async_engine depends on the sync engine fixture so tables are created once before async tests run (avoids asyncio.run() binding to a throwaway event loop)

Summary by CodeRabbit

  • Tests
    • Introduced automated enterprise integration testing through a new GitHub Actions workflow that executes on main branch pushes and pull requests.
    • Added comprehensive pytest configuration and shared test fixtures for enterprise integration tests, including database connectivity and environment setup for test isolation.

test_org_store.py and test_api_key_store.py exercise real SQLite
database behavior (queries, constraints, transactions) via
async_session_maker — that is integration-level testing, not unit
testing. Moving them out of tests/unit/ makes the boundary explicit.

Changes:
- Add tests/integration/ with __init__.py and conftest.py (DB fixtures)
- git mv tests/unit/test_org_store.py       → tests/integration/
- git mv tests/unit/test_api_key_store.py   → tests/integration/
- git mv tests/unit/storage/test_api_key_store.py
       → tests/integration/test_api_key_store_system_keys.py
- Register 'integration' pytest marker in pyproject.toml

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b31a14b5-50c1-4678-819f-725753ae08a2

📥 Commits

Reviewing files that changed from the base of the PR and between f3379db and 3f60f84.

📒 Files selected for processing (2)
  • .github/workflows/enterprise-integration-tests.yml
  • enterprise/tests/integration/conftest.py
✅ Files skipped from review due to trivial changes (1)
  • .github/workflows/enterprise-integration-tests.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • enterprise/tests/integration/conftest.py

📝 Walkthrough

Walkthrough

Adds an enterprise integration test workflow and supporting pytest configuration and fixtures: a new GitHub Actions workflow to run integration tests, an integration pytest marker in enterprise/pyproject.toml, and conftest.py fixtures that provision temporary SQLite (sync and async) databases and manage env state.

Changes

Cohort / File(s) Summary
CI / GitHub Actions
.github/workflows/enterprise-integration-tests.yml
New workflow "Run Enterprise Integration Tests" triggered on pushes to main and PRs. Runs on ubuntu-24.04 with Python 3.12, installs Poetry, runs poetry install --with dev,test, executes pytest in ./enterprise/tests/integration with --forked -n auto, sets coverage file per-Python version, and uploads coverage artifact.
Pytest config
enterprise/pyproject.toml
Adds a pytest marker integration under [tool.pytest.ini_options].markers with description indicating it requires a real DB and can be excluded via -m not integration.
Integration tests / fixtures
enterprise/tests/integration/conftest.py
New conftest registering an integration marker for collected tests, autouse fixture to set ALLOW_SHORT_CONTEXT_WINDOWS temporarily, fixtures producing unique db_path, sync engine (creates tables) and session_maker, async async_engine and async_session_maker, and imports ORM models so Base.metadata.create_all registers tables.

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub Actions
    participant Runner as Ubuntu Runner
    participant Py as Python/Poetry
    participant Pytest as pytest
    participant Art as Artifact Storage

    GH->>Runner: start workflow (push/PR)
    Runner->>Py: setup Python 3.12, install Poetry
    Runner->>Py: poetry install --with dev,test (./enterprise)
    Runner->>Pytest: run pytest ./enterprise/tests/integration --forked -n auto (COVERAGE_FILE set)
    Pytest->>Runner: generate coverage file .coverage.enterprise.integration.<pyver>
    Runner->>Art: upload artifact coverage-enterprise-integration
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰
I nibbled code beneath the moonlit tree,
New tests and workflows hopping merrily,
SQLite burrows for sync and async play,
Coverage treasures bundled on their way,
A rabbit's cheer for safer enterprise day!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: moving real-database store tests from tests/unit/ to tests/integration/ to separate integration from unit tests.
Description check ✅ Passed The PR description includes all required template sections: Why (motivation for moving tests), Summary (clear bullet points of changes), Issue Number, How to Test (with specific command), Type (Refactor selected), and Notes with implementation details.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/fix-store-tests-to-integration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@aivong-openhands aivong-openhands marked this pull request as ready for review April 17, 2026 02:44
Test Admin and others added 2 commits April 16, 2026 21:50
Mirrors the enterprise unit test job in py-tests.yml but points at
./enterprise/tests/integration instead of ./enterprise/tests/unit.

Co-Authored-By: Claude <noreply@anthropic.com>
Add pytest_collection_modifyitems hook to integration conftest so every
test collected from that directory is automatically tagged
@pytest.mark.integration. Enables targeted runs via
`pytest -m integration` without modifying individual test files.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Coverage report

This PR does not seem to contain any modification to coverable code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@aivong-openhands
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@aivong-openhands
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@aivong-openhands
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
enterprise/tests/integration/conftest.py (2)

35-37: pytest_collection_modifyitems signature is a bit narrow.

The standard hook signature is pytest_collection_modifyitems(session, config, items). Pytest's hook dispatcher tolerates fewer args, but declaring only items skips a deprecation-prone pattern and prevents future breakage if pytest ever tightens enforcement. Purely a robustness nit.

♻️ Suggested signature
-def pytest_collection_modifyitems(items):
+def pytest_collection_modifyitems(config, items):
     for item in items:
         item.add_marker(pytest.mark.integration)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@enterprise/tests/integration/conftest.py` around lines 35 - 37, The hook
function pytest_collection_modifyitems currently only accepts items; change its
signature to the standard pytest_collection_modifyitems(session, config, items)
to match Pytest's expected hook and avoid future deprecation issues, keeping the
body (for item in items: item.add_marker(pytest.mark.integration)) the same; if
linters complain about unused session/config, name them _session and _config or
prefix with underscores.

69-71: Engine/session resources aren't disposed between tests.

engine and async_engine are function-scoped but never dispose()d, so each test leaks a SQLite connection pool bound to the now-deleted tmp_path DB. Under pytest-xdist --forked -n auto this is harmless (each test gets a new process), but when running without --forked you'll accumulate file handles and, on Windows, potentially fail to clean up tmp_path. Consider converting to yield fixtures that call .dispose() in teardown.

♻️ Proposed fix
 `@pytest.fixture`
 def engine(db_path):
     """Create a sync engine with tables using file-based DB."""
     engine = create_engine(
         f'sqlite:///{db_path}', connect_args={'check_same_thread': False}
     )
     Base.metadata.create_all(engine)
-    return engine
+    try:
+        yield engine
+    finally:
+        engine.dispose()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@enterprise/tests/integration/conftest.py` around lines 69 - 71, The engine
and async_engine fixtures currently create engines but never dispose them,
leaking SQLite connection pools; change those fixtures to yield-style fixtures
that yield the engine(s) to tests and then call .dispose() in the teardown (for
async_engine, await async_engine.dispose() if it is async) to release file
handles; ensure session_maker can continue returning sessionmaker(bind=engine)
but relies on the yielded engine so disposal happens after tests complete.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/enterprise-integration-tests.yml:
- Around line 36-41: The CI job uses the wrong matrix key name: replace every
occurrence of matrix.python_version with matrix.python-version (e.g., update
COVERAGE_FILE env and the actions/upload-artifact "name" and "path" inputs) so
the coverage filename and uploaded artifact include the actual Python version;
specifically edit the lines that set COVERAGE_FILE and the upload-artifact
inputs to use ${ { matrix.python-version } } instead of ${ {
matrix.python_version } }.

In `@enterprise/tests/integration/conftest.py`:
- Around line 74-87: The async_engine fixture currently calls
asyncio.run(create_tables()) which binds the engine to a throwaway event loop;
instead make async_engine depend on the existing sync engine fixture (engine)
and remove the asyncio.run/create_tables step so tables are created by engine's
setup, or convert async_engine into an async pytest fixture that performs
create_tables() with await on the test's event loop; locate the async_engine
function and modify it to either accept engine as a parameter and drop the
table-creation coroutine, or change its signature to async def async_engine(...)
and await create_tables() (keeping create_async_engine(...) usage intact) so the
async primitives are bound to the test event loop.

---

Nitpick comments:
In `@enterprise/tests/integration/conftest.py`:
- Around line 35-37: The hook function pytest_collection_modifyitems currently
only accepts items; change its signature to the standard
pytest_collection_modifyitems(session, config, items) to match Pytest's expected
hook and avoid future deprecation issues, keeping the body (for item in items:
item.add_marker(pytest.mark.integration)) the same; if linters complain about
unused session/config, name them _session and _config or prefix with
underscores.
- Around line 69-71: The engine and async_engine fixtures currently create
engines but never dispose them, leaking SQLite connection pools; change those
fixtures to yield-style fixtures that yield the engine(s) to tests and then call
.dispose() in the teardown (for async_engine, await async_engine.dispose() if it
is async) to release file handles; ensure session_maker can continue returning
sessionmaker(bind=engine) but relies on the yielded engine so disposal happens
after tests complete.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2607a880-7f3a-407c-b825-353333cf16de

📥 Commits

Reviewing files that changed from the base of the PR and between 97343eb and f3379db.

📒 Files selected for processing (7)
  • .github/workflows/enterprise-integration-tests.yml
  • enterprise/pyproject.toml
  • enterprise/tests/integration/__init__.py
  • enterprise/tests/integration/conftest.py
  • enterprise/tests/integration/test_api_key_store.py
  • enterprise/tests/integration/test_api_key_store_system_keys.py
  • enterprise/tests/integration/test_org_store.py

Comment thread .github/workflows/enterprise-integration-tests.yml Outdated
Comment thread enterprise/tests/integration/conftest.py Outdated
… and workflow

- Fix matrix.python_version → matrix.python-version in enterprise-integration-tests.yml
- Use standard pytest_collection_modifyitems(config, items) hook signature
- Convert engine fixture to yield + dispose() to release SQLite connections
- Remove asyncio.run(create_tables()) from async_engine; depend on engine fixture
  so tables already exist, avoiding a throwaway event loop binding

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@aivong-openhands
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@aivong-openhands
Copy link
Copy Markdown
Owner Author

/review

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