You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_db_manager.py 7.0 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import os
  2. import asyncio
  3. import pytest
  4. from sqlmodel import Session, text, select
  5. from typing import Generator
  6. from pathlib import Path
  7. from autogenstudio.database import DatabaseManager
  8. from autogen_agentchat.agents import AssistantAgent
  9. from autogen_agentchat.teams import RoundRobinGroupChat
  10. from autogen_ext.models.openai import OpenAIChatCompletionClient
  11. from autogen_agentchat.conditions import TextMentionTermination
  12. from autogenstudio.datamodel.db import Team, Session as SessionModel, Run, Message, RunStatus, MessageConfig
  13. @pytest.fixture
  14. def test_db(tmp_path) -> Generator[DatabaseManager, None, None]:
  15. """Fixture for test database using temporary paths"""
  16. db_path = tmp_path / "test.db"
  17. db = DatabaseManager(f"sqlite:///{db_path}", base_dir=tmp_path)
  18. db.reset_db()
  19. # Initialize database instead of create_db_and_tables
  20. db.initialize_database(auto_upgrade=False)
  21. yield db
  22. # Clean up
  23. asyncio.run(db.close())
  24. db.reset_db()
  25. # No need to manually remove files - tmp_path is cleaned up automatically
  26. @pytest.fixture
  27. def test_user() -> str:
  28. return "test_user@example.com"
  29. @pytest.fixture
  30. def sample_team(test_user: str) -> Team:
  31. """Create a sample team with proper config"""
  32. agent = AssistantAgent(
  33. name="weather_agent",
  34. model_client=OpenAIChatCompletionClient(
  35. model="gpt-4",
  36. ),
  37. )
  38. agent_team = RoundRobinGroupChat([agent], termination_condition=TextMentionTermination("TERMINATE"))
  39. team_component = agent_team.dump_component()
  40. return Team(
  41. user_id=test_user,
  42. component=team_component.model_dump(),
  43. )
  44. class TestDatabaseOperations:
  45. def test_basic_setup(self, test_db: DatabaseManager):
  46. """Test basic database setup and connection"""
  47. with Session(test_db.engine) as session:
  48. result = session.exec(text("SELECT 1")).first()
  49. assert result[0] == 1
  50. result = session.exec(select(1)).first()
  51. assert result == 1
  52. def test_basic_entity_creation(self, test_db: DatabaseManager, sample_team: Team):
  53. """Test creating all entity types with proper configs"""
  54. # Use upsert instead of raw session
  55. response = test_db.upsert(sample_team)
  56. assert response.status is True
  57. with Session(test_db.engine) as session:
  58. saved_team = session.get(Team, sample_team.id)
  59. assert saved_team is not None
  60. def test_upsert_operations(self, test_db: DatabaseManager, sample_team: Team):
  61. """Test upsert for both create and update scenarios"""
  62. # Test Create
  63. response = test_db.upsert(sample_team)
  64. assert response.status is True
  65. assert "Created Successfully" in response.message
  66. # Test Update
  67. team_id = sample_team.id
  68. sample_team.version = "0.0.2"
  69. response = test_db.upsert(sample_team)
  70. assert response.status is True
  71. # Verify Update
  72. result = test_db.get(Team, {"id": team_id})
  73. assert result.status is True
  74. assert result.data[0].version == "0.0.2"
  75. def test_delete_operations(self, test_db: DatabaseManager, sample_team: Team):
  76. """Test delete with various filters"""
  77. # First insert the model
  78. response = test_db.upsert(sample_team)
  79. assert response.status is True # Verify insert worked
  80. # Get the ID that was actually saved
  81. team_id = sample_team.id
  82. # Test deletion by id
  83. response = test_db.delete(Team, {"id": team_id})
  84. assert response.status is True
  85. assert "Deleted Successfully" in response.message
  86. # Verify deletion
  87. result = test_db.get(Team, {"id": team_id})
  88. assert len(result.data) == 0
  89. def test_cascade_delete(self, test_db: DatabaseManager, test_user: str):
  90. """Test all levels of cascade delete"""
  91. # Enable foreign keys for SQLite (crucial for cascade delete)
  92. with Session(test_db.engine) as session:
  93. session.execute(text("PRAGMA foreign_keys=ON"))
  94. session.commit()
  95. # Test Run -> Message cascade
  96. team1 = Team(user_id=test_user, component={"name": "Team1", "type": "team"})
  97. test_db.upsert(team1)
  98. session1 = SessionModel(user_id=test_user, team_id=team1.id, name="Session1")
  99. test_db.upsert(session1)
  100. run1_id = 1
  101. test_db.upsert(Run(
  102. id=run1_id,
  103. user_id=test_user,
  104. session_id=session1.id,
  105. status=RunStatus.COMPLETE,
  106. task=MessageConfig(content="Task1", source="user").model_dump()
  107. ))
  108. test_db.upsert(Message(
  109. user_id=test_user,
  110. session_id=session1.id,
  111. run_id=run1_id,
  112. config=MessageConfig(content="Message1", source="assistant").model_dump()
  113. ))
  114. test_db.delete(Run, {"id": run1_id})
  115. assert len(test_db.get(Message, {"run_id": run1_id}).data) == 0, "Run->Message cascade failed"
  116. # Test Session -> Run -> Message cascade
  117. session2 = SessionModel(user_id=test_user, team_id=team1.id, name="Session2")
  118. test_db.upsert(session2)
  119. run2_id = 2
  120. test_db.upsert(Run(
  121. id=run2_id,
  122. user_id=test_user,
  123. session_id=session2.id,
  124. status=RunStatus.COMPLETE,
  125. task=MessageConfig(content="Task2", source="user").model_dump()
  126. ))
  127. test_db.upsert(Message(
  128. user_id=test_user,
  129. session_id=session2.id,
  130. run_id=run2_id,
  131. config=MessageConfig(content="Message2", source="assistant").model_dump()
  132. ))
  133. test_db.delete(SessionModel, {"id": session2.id})
  134. assert len(test_db.get(Run, {"session_id": session2.id}).data) == 0, "Session->Run cascade failed"
  135. assert len(test_db.get(Message, {"run_id": run2_id}).data) == 0, "Session->Run->Message cascade failed"
  136. # Clean up
  137. test_db.delete(Team, {"id": team1.id})
  138. def test_initialize_database_scenarios(self, tmp_path, monkeypatch):
  139. """Test different initialize_database parameters"""
  140. db_path = tmp_path / "test_init.db"
  141. db = DatabaseManager(f"sqlite:///{db_path}", base_dir=tmp_path)
  142. # Mock the schema manager's check_schema_status to avoid migration issues
  143. monkeypatch.setattr(db.schema_manager, "check_schema_status", lambda: (False, None))
  144. monkeypatch.setattr(db.schema_manager, "ensure_schema_up_to_date", lambda: True)
  145. try:
  146. # Test basic initialization
  147. response = db.initialize_database()
  148. assert response.status is True
  149. # Test with auto_upgrade
  150. response = db.initialize_database(auto_upgrade=True)
  151. assert response.status is True
  152. finally:
  153. asyncio.run(db.close())
  154. db.reset_db()