* feat(db): add pair schema and stage restore migrations for #193 * feat(database): persist reusable ordered prompt pairs (#193) * feat(api): expose reusable pairs and atomic metadata enrichment (#193) * feat(metadata): resolve canonical prompt pairs with bounded provenance (#193) * feat(scan): enrich image pairs without guessing or duplicate links (#193) * fix(database): preserve pair tags during global maintenance (#193) * feat(tracking): enrich live image pairs and cancel scans safely (#193) * feat(nodes): encode paired prompts and count cached recipe runs (#193) * fix(database): validate restored pair ownership and provenance (#193) * feat(admin): report pair scan outcomes and cancellation (#193) * feat(ui): add paired prompt editor and explicit recipe library for #193 * fix(autocomplete): include reusable pair metadata vocabulary (#193) * fix(pairs): honor recent sorting and conservative scan outcomes (#193) * fix(ui): protect paired draft saves and clarify negative variants (#193) * fix(metadata): preserve bounded paired execution evidence (#193) * fix(tracking): follow actual pair output roles and prefer execution evidence (#193) * docs(pairs): document live validation and retain renderer screenshots (#193) * test(api): inject disposable databases before API startup (#194) * test(api): canonicalize portable temporary gallery roots (#194) * docs(ui): prototype branching negative variant history (#193) * docs(ui): show selected negative beneath positive in timeline concept (#193) * docs: retain approved timeline for later gallery redesign (#193) * test(db): close restore fixture connections before cleanup (#194) * test(db): reuse existing handle guards in all pair fixtures (#194) * chore: clarify rollback test and intentional exception handling (#193)
72 lines
2.7 KiB
Python
72 lines
2.7 KiB
Python
"""API fixtures never open the configured database before installing test state."""
|
|
|
|
import unittest.mock
|
|
|
|
from py.api import PromptManagerAPI
|
|
|
|
|
|
class TestAPIDatabaseIsolation(unittest.TestCase):
|
|
def test_injected_database_never_constructs_the_configured_database(self):
|
|
database = unittest.mock.MagicMock()
|
|
database.cleanup_duplicates.return_value = 0
|
|
with (
|
|
unittest.mock.patch(
|
|
"py.api.PromptDatabase", side_effect=AssertionError("default DB opened")
|
|
) as factory,
|
|
unittest.mock.patch("py.api.get_logger"),
|
|
):
|
|
api = PromptManagerAPI(db=database)
|
|
self.assertIs(api.db, database)
|
|
factory.assert_not_called()
|
|
database.cleanup_duplicates.assert_called_once_with()
|
|
|
|
def test_falsey_injected_database_is_still_used(self):
|
|
database = unittest.mock.MagicMock()
|
|
database.__bool__.return_value = False
|
|
database.cleanup_duplicates.return_value = 0
|
|
with (
|
|
unittest.mock.patch(
|
|
"py.api.PromptDatabase", side_effect=AssertionError("default DB opened")
|
|
) as factory,
|
|
unittest.mock.patch("py.api.get_logger"),
|
|
):
|
|
api = PromptManagerAPI(db=database)
|
|
self.assertIs(api.db, database)
|
|
factory.assert_not_called()
|
|
|
|
def test_default_runtime_construction_still_uses_the_configured_factory(self):
|
|
database = unittest.mock.MagicMock()
|
|
database.cleanup_duplicates.return_value = 2
|
|
with (
|
|
unittest.mock.patch(
|
|
"py.api.PromptDatabase", return_value=database
|
|
) as factory,
|
|
unittest.mock.patch("py.api.get_logger") as logger,
|
|
):
|
|
api = PromptManagerAPI()
|
|
self.assertIs(api.db, database)
|
|
factory.assert_called_once_with()
|
|
logger.return_value.info.assert_any_call(
|
|
"Startup cleanup: removed 2 duplicate prompts"
|
|
)
|
|
|
|
def test_injected_cleanup_failure_is_logged_without_falling_back_to_default(self):
|
|
database = unittest.mock.MagicMock()
|
|
database.cleanup_duplicates.side_effect = RuntimeError("test cleanup")
|
|
with (
|
|
unittest.mock.patch(
|
|
"py.api.PromptDatabase", side_effect=AssertionError("default DB opened")
|
|
) as factory,
|
|
unittest.mock.patch("py.api.get_logger") as logger,
|
|
):
|
|
api = PromptManagerAPI(db=database)
|
|
self.assertIs(api.db, database)
|
|
factory.assert_not_called()
|
|
logger.return_value.error.assert_called_once_with(
|
|
"Startup cleanup failed: test cleanup"
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|