database/migration_runner: add failing test for get_current_revision() SQLite threading error #10487

Open
opened 2026-04-18 10:08:46 +00:00 by HAL9000 · 0 comments
Owner

Metadata

  • Commit message: test(database): add failing test for get_current_revision() SQLite threading error
  • Branch name: test/migration-runner-sqlite-threading

Background and Context

MigrationRunner.get_current_revision() creates a new SQLAlchemy engine with create_engine(self.database_url) but does not pass connect_args={"check_same_thread": False} for SQLite databases. When called from a thread other than the one that created the engine, SQLite raises ProgrammingError: SQLite objects created in a thread can only be used in that same thread.

Compare with init_or_upgrade() which correctly passes connect_args={"check_same_thread": False} for SQLite:

engine = create_engine(
    self.database_url,
    connect_args={"check_same_thread": False},   # ← correct
)

But get_current_revision() does not:

def get_current_revision(self) -> str | None:
    """Get the current migration revision of the database."""
    engine = create_engine(self.database_url)   # ← no check_same_thread=False
    with engine.connect() as connection:
        context = MigrationContext.configure(connection)
        return context.get_current_revision()

A failing test should be written to document this threading issue before the fix is implemented, following TDD discipline.

Expected Behavior

A test file tests/infrastructure/database/test_migration_runner_threading.py exists that:

  • Calls get_current_revision() from a background thread
  • Is marked @pytest.mark.tdd_expected_fail
  • Currently fails with ProgrammingError about SQLite thread safety
  • Will pass once the bug is fixed

Acceptance Criteria

  • Test file tests/infrastructure/database/test_migration_runner_threading.py is created
  • Test is marked @pytest.mark.tdd_issue, @pytest.mark.tdd_issue_3, and @pytest.mark.tdd_expected_fail
  • Test calls get_current_revision() from a background thread using threading.Thread
  • Test currently fails with ProgrammingError about SQLite thread safety
  • CI confirms the test fails as expected

Subtasks

  • Create tests/infrastructure/database/test_migration_runner_threading.py with the following test:
# tests/infrastructure/database/test_migration_runner_threading.py

import pytest
import threading
from cleveragents.infrastructure.database.migration_runner import MigrationRunner

@pytest.mark.tdd_issue
@pytest.mark.tdd_issue_3
@pytest.mark.tdd_expected_fail
def test_get_current_revision_works_from_background_thread(tmp_path):
    """MigrationRunner.get_current_revision() must work from a background thread.

    Currently FAILS because get_current_revision() creates a SQLite engine
    without check_same_thread=False, causing:
        ProgrammingError: SQLite objects created in a thread can only be
        used in that same thread.
    """
    db_path = tmp_path / "test.db"
    db_url = f"sqlite:///{db_path}"
    runner = MigrationRunner(db_url)
    runner.init_or_upgrade(require_confirmation=False)

    errors = []

    def call_from_thread():
        try:
            runner.get_current_revision()
        except Exception as e:
            errors.append(e)

    t = threading.Thread(target=call_from_thread)
    t.start()
    t.join()

    # This assertion FAILS because SQLite raises ProgrammingError
    assert not errors, (
        f"get_current_revision() must not raise from a background thread; "
        f"got: {errors}"
    )
  • Verify the test fails with ProgrammingError about thread safety
  • Commit the failing test

Definition of Done

  • Failing test written and committed
  • Test is marked @pytest.mark.tdd_expected_fail
  • CI confirms the test fails with ProgrammingError about thread safety
  • Issue is closed once the failing test is committed and CI confirms the expected failure

Automated by CleverAgents Bot
Supervisor: Bug Hunt Pool | Agent: bug-hunt-pool-supervisor


Automated by CleverAgents Bot
Agent: new-issue-creator

## Metadata - **Commit message:** `test(database): add failing test for get_current_revision() SQLite threading error` - **Branch name:** `test/migration-runner-sqlite-threading` ## Background and Context `MigrationRunner.get_current_revision()` creates a new SQLAlchemy engine with `create_engine(self.database_url)` but does not pass `connect_args={"check_same_thread": False}` for SQLite databases. When called from a thread other than the one that created the engine, SQLite raises `ProgrammingError: SQLite objects created in a thread can only be used in that same thread`. Compare with `init_or_upgrade()` which correctly passes `connect_args={"check_same_thread": False}` for SQLite: ```python engine = create_engine( self.database_url, connect_args={"check_same_thread": False}, # ← correct ) ``` But `get_current_revision()` does not: ```python def get_current_revision(self) -> str | None: """Get the current migration revision of the database.""" engine = create_engine(self.database_url) # ← no check_same_thread=False with engine.connect() as connection: context = MigrationContext.configure(connection) return context.get_current_revision() ``` A failing test should be written to document this threading issue before the fix is implemented, following TDD discipline. ## Expected Behavior A test file `tests/infrastructure/database/test_migration_runner_threading.py` exists that: - Calls `get_current_revision()` from a background thread - Is marked `@pytest.mark.tdd_expected_fail` - Currently **fails** with `ProgrammingError` about SQLite thread safety - Will **pass** once the bug is fixed ## Acceptance Criteria - [ ] Test file `tests/infrastructure/database/test_migration_runner_threading.py` is created - [ ] Test is marked `@pytest.mark.tdd_issue`, `@pytest.mark.tdd_issue_3`, and `@pytest.mark.tdd_expected_fail` - [ ] Test calls `get_current_revision()` from a background thread using `threading.Thread` - [ ] Test currently fails with `ProgrammingError` about SQLite thread safety - [ ] CI confirms the test fails as expected ## Subtasks - [ ] Create `tests/infrastructure/database/test_migration_runner_threading.py` with the following test: ```python # tests/infrastructure/database/test_migration_runner_threading.py import pytest import threading from cleveragents.infrastructure.database.migration_runner import MigrationRunner @pytest.mark.tdd_issue @pytest.mark.tdd_issue_3 @pytest.mark.tdd_expected_fail def test_get_current_revision_works_from_background_thread(tmp_path): """MigrationRunner.get_current_revision() must work from a background thread. Currently FAILS because get_current_revision() creates a SQLite engine without check_same_thread=False, causing: ProgrammingError: SQLite objects created in a thread can only be used in that same thread. """ db_path = tmp_path / "test.db" db_url = f"sqlite:///{db_path}" runner = MigrationRunner(db_url) runner.init_or_upgrade(require_confirmation=False) errors = [] def call_from_thread(): try: runner.get_current_revision() except Exception as e: errors.append(e) t = threading.Thread(target=call_from_thread) t.start() t.join() # This assertion FAILS because SQLite raises ProgrammingError assert not errors, ( f"get_current_revision() must not raise from a background thread; " f"got: {errors}" ) ``` - [ ] Verify the test fails with `ProgrammingError` about thread safety - [ ] Commit the failing test ## Definition of Done - [ ] Failing test written and committed - [ ] Test is marked `@pytest.mark.tdd_expected_fail` - [ ] CI confirms the test fails with `ProgrammingError` about thread safety - [ ] Issue is closed once the failing test is committed and CI confirms the expected failure --- **Automated by CleverAgents Bot** Supervisor: Bug Hunt Pool | Agent: bug-hunt-pool-supervisor --- **Automated by CleverAgents Bot** Agent: new-issue-creator
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#10487
No description provided.