test_ai_failure_template_migration_3236.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. """Upgrades and resets use the provider-neutral AI template without losing custom text."""
  2. from unittest.mock import patch
  3. import pytest
  4. from sqlalchemy import select
  5. from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
  6. from backend.app.core.database import _migrate_ai_failure_detection_template, seed_notification_templates
  7. from backend.app.models.notification_template import DEFAULT_TEMPLATES, NotificationTemplate
  8. LEGACY_BODY = "{printer}: {task_name}\nConfidence: {confidence}\nAction taken: {action}"
  9. AI_DEFAULT = next(t for t in DEFAULT_TEMPLATES if t["event_type"] == "ai_failure_detection")
  10. @pytest.fixture
  11. async def engine():
  12. engine = create_async_engine("sqlite+aiosqlite:///:memory:")
  13. async with engine.begin() as conn:
  14. await conn.run_sync(NotificationTemplate.__table__.create)
  15. try:
  16. yield engine
  17. finally:
  18. await engine.dispose()
  19. @pytest.mark.parametrize(
  20. ("event_type", "body", "expected_body"),
  21. [
  22. ("ai_failure_detection", LEGACY_BODY, AI_DEFAULT["body_template"]),
  23. ("ai_failure_detection", "Check {printer}: {confidence}", "Check {printer}: {confidence}"),
  24. ("printer_error", LEGACY_BODY, LEGACY_BODY),
  25. ],
  26. )
  27. async def test_migration_updates_only_legacy_ai_body_and_is_idempotent(engine, event_type, body, expected_body):
  28. session_factory = async_sessionmaker(engine)
  29. async with session_factory() as session:
  30. session.add(
  31. NotificationTemplate(
  32. event_type=event_type,
  33. name="My template",
  34. title_template="Check {printer}",
  35. body_template=body,
  36. )
  37. )
  38. await session.commit()
  39. for _ in range(2):
  40. async with engine.begin() as conn:
  41. await _migrate_ai_failure_detection_template(conn)
  42. async with session_factory() as session:
  43. template = (await session.execute(select(NotificationTemplate))).scalar_one()
  44. assert template.body_template == expected_body
  45. assert template.title_template == "Check {printer}"
  46. assert template.name == "My template"
  47. async def test_seed_and_reset_share_the_provider_neutral_default(engine):
  48. from backend.app.api.routes.notification_templates import reset_template
  49. session_factory = async_sessionmaker(engine)
  50. with patch("backend.app.core.database.async_session", session_factory):
  51. await seed_notification_templates()
  52. async with session_factory() as session:
  53. template = (
  54. await session.execute(
  55. select(NotificationTemplate).where(NotificationTemplate.event_type == "ai_failure_detection")
  56. )
  57. ).scalar_one()
  58. assert template.body_template == AI_DEFAULT["body_template"]
  59. assert {"{provider}", "{print_quality}", "{confidence}"} <= set(template.body_template.split())
  60. template_id = template.id
  61. template.title_template = "Check {printer}"
  62. template.body_template = "My custom body"
  63. await session.commit()
  64. with patch("backend.app.api.routes.notification_templates.notification_service.clear_template_cache") as clear:
  65. reset = await reset_template(template_id, db=session)
  66. assert reset.title_template == AI_DEFAULT["title_template"]
  67. assert reset.body_template == AI_DEFAULT["body_template"]
  68. clear.assert_called_once()