update history pytest
This commit is contained in:
@@ -73,18 +73,21 @@ def mock_llm_managers():
|
||||
with patch("src.sim.simulator.llm_ai") as mock_ai, \
|
||||
patch("src.sim.simulator.process_avatar_long_term_objective", new_callable=AsyncMock) as mock_lto, \
|
||||
patch("src.classes.nickname.process_avatar_nickname", new_callable=AsyncMock) as mock_nick, \
|
||||
patch("src.classes.relation_resolver.RelationResolver.run_batch", new_callable=AsyncMock) as mock_rr:
|
||||
patch("src.classes.relation_resolver.RelationResolver.run_batch", new_callable=AsyncMock) as mock_rr, \
|
||||
patch("src.classes.history.HistoryManager.apply_history_influence", new_callable=AsyncMock) as mock_hist:
|
||||
|
||||
mock_ai.decide = AsyncMock(return_value={})
|
||||
mock_lto.return_value = None
|
||||
mock_nick.return_value = None
|
||||
mock_rr.return_value = []
|
||||
mock_hist.return_value = None
|
||||
|
||||
yield {
|
||||
"ai": mock_ai,
|
||||
"lto": mock_lto,
|
||||
"nick": mock_nick,
|
||||
"rr": mock_rr
|
||||
"rr": mock_rr,
|
||||
"hist": mock_hist
|
||||
}
|
||||
|
||||
# --- Shared Helpers for Item Creation ---
|
||||
|
||||
@@ -89,8 +89,8 @@ async def test_history_influence(base_world):
|
||||
# Mock _read_csv to return dummy string
|
||||
manager._read_csv = MagicMock(return_value="dummy,csv,content")
|
||||
|
||||
# Mock call_llm_with_template
|
||||
with patch("src.classes.history.call_llm_with_template", new_callable=AsyncMock) as mock_llm:
|
||||
# Mock call_llm_with_task_name
|
||||
with patch("src.classes.history.call_llm_with_task_name", new_callable=AsyncMock) as mock_llm:
|
||||
mock_llm.return_value = mock_response
|
||||
|
||||
# --- Execute ---
|
||||
|
||||
@@ -67,7 +67,7 @@ class TestInitStatusEndpoint:
|
||||
def test_init_status_in_progress(self, client, reset_game_instance):
|
||||
"""Test init-status during initialization."""
|
||||
game_instance["init_status"] = "in_progress"
|
||||
game_instance["init_phase"] = 2
|
||||
game_instance["init_phase"] = 3
|
||||
game_instance["init_phase_name"] = "initializing_sects"
|
||||
game_instance["init_progress"] = 33
|
||||
game_instance["init_start_time"] = time.time() - 5 # 5 seconds ago
|
||||
@@ -77,7 +77,7 @@ class TestInitStatusEndpoint:
|
||||
|
||||
data = response.json()
|
||||
assert data["status"] == "in_progress"
|
||||
assert data["phase"] == 2
|
||||
assert data["phase"] == 3
|
||||
assert data["phase_name"] == "initializing_sects"
|
||||
assert data["progress"] == 33
|
||||
assert data["elapsed_seconds"] >= 5
|
||||
@@ -85,7 +85,7 @@ class TestInitStatusEndpoint:
|
||||
def test_init_status_ready(self, client, reset_game_instance):
|
||||
"""Test init-status when initialization is complete."""
|
||||
game_instance["init_status"] = "ready"
|
||||
game_instance["init_phase"] = 5
|
||||
game_instance["init_phase"] = 6
|
||||
game_instance["init_phase_name"] = "generating_initial_events"
|
||||
game_instance["init_progress"] = 100
|
||||
|
||||
@@ -127,29 +127,30 @@ class TestUpdateInitProgress:
|
||||
|
||||
def test_update_progress_with_phase_name(self, reset_game_instance):
|
||||
"""Test updating progress with explicit phase name."""
|
||||
update_init_progress(2, "initializing_sects")
|
||||
update_init_progress(3, "initializing_sects")
|
||||
|
||||
assert game_instance["init_phase"] == 2
|
||||
assert game_instance["init_phase"] == 3
|
||||
assert game_instance["init_phase_name"] == "initializing_sects"
|
||||
assert game_instance["init_progress"] == 20
|
||||
assert game_instance["init_progress"] == 40
|
||||
|
||||
def test_update_progress_without_phase_name(self, reset_game_instance):
|
||||
"""Test updating progress uses default phase name from mapping."""
|
||||
update_init_progress(3)
|
||||
update_init_progress(4)
|
||||
|
||||
assert game_instance["init_phase"] == 3
|
||||
assert game_instance["init_phase"] == 4
|
||||
assert game_instance["init_phase_name"] == "generating_avatars"
|
||||
assert game_instance["init_progress"] == 30
|
||||
assert game_instance["init_progress"] == 55
|
||||
|
||||
def test_all_phase_names_mapped(self):
|
||||
"""Test all phases have corresponding names."""
|
||||
expected_phases = {
|
||||
0: "scanning_assets",
|
||||
1: "loading_map",
|
||||
2: "initializing_sects",
|
||||
3: "generating_avatars",
|
||||
4: "checking_llm",
|
||||
5: "generating_initial_events",
|
||||
2: "processing_history",
|
||||
3: "initializing_sects",
|
||||
4: "generating_avatars",
|
||||
5: "checking_llm",
|
||||
6: "generating_initial_events",
|
||||
}
|
||||
assert INIT_PHASE_NAMES == expected_phases
|
||||
|
||||
@@ -165,7 +166,8 @@ class TestNewGameEndpoint:
|
||||
"init_npc_num": 10,
|
||||
"sect_num": 2,
|
||||
"protagonist": "none",
|
||||
"npc_awakening_rate_per_month": 0.01
|
||||
"npc_awakening_rate_per_month": 0.01,
|
||||
"world_history": "Some history"
|
||||
}
|
||||
response = client.post("/api/game/start", json=payload)
|
||||
|
||||
@@ -221,7 +223,7 @@ class TestReinitEndpoint:
|
||||
game_instance["sim"] = MagicMock()
|
||||
game_instance["init_status"] = "error"
|
||||
game_instance["init_error"] = "Some error"
|
||||
game_instance["init_phase"] = 3
|
||||
game_instance["init_phase"] = 4
|
||||
game_instance["init_progress"] = 50
|
||||
|
||||
with patch.object(main, 'init_game_async', new_callable=AsyncMock):
|
||||
@@ -262,7 +264,7 @@ class TestMapAndStateAPIDuringInit:
|
||||
|
||||
game_instance["world"] = mock_world
|
||||
game_instance["init_status"] = "in_progress"
|
||||
game_instance["init_phase"] = 4
|
||||
game_instance["init_phase"] = 5
|
||||
game_instance["init_phase_name"] = "checking_llm"
|
||||
|
||||
# The /api/map endpoint should work.
|
||||
@@ -280,7 +282,7 @@ class TestMapAndStateAPIDuringInit:
|
||||
|
||||
game_instance["world"] = mock_world
|
||||
game_instance["init_status"] = "in_progress"
|
||||
game_instance["init_phase"] = 5
|
||||
game_instance["init_phase"] = 6
|
||||
game_instance["init_phase_name"] = "generating_initial_events"
|
||||
|
||||
response = client.get("/api/state")
|
||||
@@ -291,7 +293,7 @@ class TestInitGameAsync:
|
||||
"""Tests for the async initialization flow."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_init_sets_status_to_in_progress(self, reset_game_instance):
|
||||
async def test_init_sets_status_to_in_progress(self, reset_game_instance, mock_llm_managers):
|
||||
"""Test initialization sets status to in_progress immediately."""
|
||||
with patch.object(main, 'scan_avatar_assets'), \
|
||||
patch.object(main, 'load_cultivation_world_map') as mock_load_map, \
|
||||
@@ -317,7 +319,7 @@ class TestInitGameAsync:
|
||||
await task # Let it complete.
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_init_error_sets_error_status(self, reset_game_instance):
|
||||
async def test_init_error_sets_error_status(self, reset_game_instance, mock_llm_managers):
|
||||
"""Test initialization error sets status to error."""
|
||||
with patch.object(main, 'scan_avatar_assets', side_effect=Exception("Test error")):
|
||||
await main.init_game_async()
|
||||
@@ -326,7 +328,7 @@ class TestInitGameAsync:
|
||||
assert "Test error" in game_instance["init_error"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_init_completes_with_ready_status(self, reset_game_instance):
|
||||
async def test_init_completes_with_ready_status(self, reset_game_instance, mock_llm_managers):
|
||||
"""Test successful initialization sets status to ready."""
|
||||
with patch.object(main, 'scan_avatar_assets'), \
|
||||
patch.object(main, 'load_cultivation_world_map') as mock_load_map, \
|
||||
@@ -355,7 +357,7 @@ class TestInitGameAsync:
|
||||
assert game_instance["init_progress"] == 100
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_init_records_llm_failure(self, reset_game_instance):
|
||||
async def test_init_records_llm_failure(self, reset_game_instance, mock_llm_managers):
|
||||
"""Test LLM check failure is recorded but doesn't stop initialization."""
|
||||
with patch.object(main, 'scan_avatar_assets'), \
|
||||
patch.object(main, 'load_cultivation_world_map') as mock_load_map, \
|
||||
@@ -387,7 +389,47 @@ class TestInitGameAsync:
|
||||
assert game_instance["llm_error_message"] == "API key invalid"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_init_pauses_after_initial_events(self, reset_game_instance):
|
||||
async def test_init_calls_history_manager(self, reset_game_instance, mock_llm_managers):
|
||||
"""Test initialization calls HistoryManager when history is present."""
|
||||
with patch.object(main, 'scan_avatar_assets'), \
|
||||
patch.object(main, 'load_cultivation_world_map') as mock_load_map, \
|
||||
patch.object(main, 'check_llm_connectivity', return_value=(True, "")), \
|
||||
patch('src.server.main.World') as mock_world_class, \
|
||||
patch('src.server.main.Simulator') as mock_sim_class, \
|
||||
patch('src.server.main.sects_by_id', {}), \
|
||||
patch('src.server.main.CONFIG') as mock_config, \
|
||||
patch('src.server.main.HistoryManager') as mock_history_class:
|
||||
|
||||
mock_config.game.sect_num = 0
|
||||
mock_config.game.init_npc_num = 0
|
||||
mock_config.avatar.protagonist = "none"
|
||||
mock_config.game.world_history = "Ancient times..."
|
||||
|
||||
mock_map = MagicMock()
|
||||
mock_load_map.return_value = mock_map
|
||||
mock_world = MagicMock()
|
||||
mock_world.avatar_manager.avatars = {}
|
||||
mock_world_class.create_with_db.return_value = mock_world
|
||||
mock_sim = MagicMock()
|
||||
mock_sim.step = AsyncMock()
|
||||
mock_sim_class.return_value = mock_sim
|
||||
|
||||
# Use the mock from fixture if available, but here we patch HistoryManager class specifically
|
||||
# to verify constructor call.
|
||||
mock_history_mgr = MagicMock()
|
||||
# We want to verify that apply_history_influence is called.
|
||||
# Even if mock_llm_managers mocks the underlying method on the real class,
|
||||
# here we mock the whole class, so we get a fresh mock instance.
|
||||
mock_history_mgr.apply_history_influence = AsyncMock()
|
||||
mock_history_class.return_value = mock_history_mgr
|
||||
|
||||
await main.init_game_async()
|
||||
|
||||
mock_history_class.assert_called_once_with(mock_world)
|
||||
mock_history_mgr.apply_history_influence.assert_called_once_with("Ancient times...")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_init_pauses_after_initial_events(self, reset_game_instance, mock_llm_managers):
|
||||
"""Test game is paused after generating initial events."""
|
||||
with patch.object(main, 'scan_avatar_assets'), \
|
||||
patch.object(main, 'load_cultivation_world_map') as mock_load_map, \
|
||||
|
||||
Reference in New Issue
Block a user