test_energy_stones.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import sys
  2. from pathlib import Path
  3. import pytest
  4. import pytest_asyncio
  5. from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
  6. from sqlalchemy import select
  7. PROJECT_ROOT = Path(__file__).resolve().parents[1]
  8. if str(PROJECT_ROOT) not in sys.path:
  9. sys.path.insert(0, str(PROJECT_ROOT))
  10. from models_db import Base, User, ConversationEnergyStone # noqa: E402
  11. from services.energy_stone_service import EnergyStoneService # noqa: E402
  12. class DummyDBManager:
  13. """Minimal DB manager compatible with EnergyStoneService."""
  14. def __init__(self, session_factory: async_sessionmaker[AsyncSession]):
  15. self._session_factory = session_factory
  16. def get_session(self) -> AsyncSession:
  17. return self._session_factory()
  18. @pytest_asyncio.fixture
  19. async def db_manager():
  20. engine = create_async_engine("sqlite+aiosqlite:///:memory:")
  21. async with engine.begin() as conn:
  22. await conn.run_sync(Base.metadata.create_all)
  23. session_factory = async_sessionmaker(engine, expire_on_commit=False)
  24. manager = DummyDBManager(session_factory)
  25. try:
  26. yield manager
  27. finally:
  28. await engine.dispose()
  29. @pytest_asyncio.fixture
  30. async def seeded_user(db_manager: DummyDBManager):
  31. user_id = "test-user"
  32. async with db_manager.get_session() as session:
  33. user = User(id=1, user_id=user_id, username="Tester")
  34. session.add(user)
  35. await session.commit()
  36. return user_id
  37. def build_service(interval_seconds: int = 30) -> EnergyStoneService:
  38. service = EnergyStoneService()
  39. service.conversation_interval_ms = interval_seconds * 1000
  40. return service
  41. @pytest.mark.asyncio
  42. async def test_conversation_stone_not_created_before_threshold(db_manager, seeded_user):
  43. service = build_service()
  44. await service.set_db_manager(db_manager)
  45. stones = await service.create_conversation_stones_if_needed(
  46. user_id=seeded_user,
  47. request_id="req-before-threshold",
  48. total_duration_ms=15_000,
  49. duration_increment_ms=15_000,
  50. )
  51. assert stones == []
  52. @pytest.mark.asyncio
  53. async def test_conversation_stone_created_at_30s_threshold(db_manager, seeded_user):
  54. service = build_service()
  55. await service.set_db_manager(db_manager)
  56. stones = await service.create_conversation_stones_if_needed(
  57. user_id=seeded_user,
  58. request_id="req-threshold",
  59. total_duration_ms=30_000,
  60. duration_increment_ms=30_000,
  61. )
  62. assert len(stones) == 1
  63. payload = stones[0]
  64. assert payload["stone_type"] == "conversation"
  65. assert payload["metadata"]["threshold_index"] == 1
  66. assert payload["metadata"]["total_duration_ms"] == 30_000
  67. async with db_manager.get_session() as session:
  68. result = await session.execute(
  69. select(ConversationEnergyStone).where(
  70. ConversationEnergyStone.user_id == seeded_user
  71. )
  72. )
  73. stored = result.scalars().all()
  74. assert len(stored) == 1
  75. assert stored[0].threshold_index == 1
  76. assert stored[0].total_duration_ms == 30_000