Merge 551b084021 into b5b53acc57
This commit is contained in:
commit
7aeebc45ea
|
|
@ -273,7 +273,7 @@ def _check_simulation_prepared(simulation_id: str) -> tuple:
|
|||
|
||||
检查条件:
|
||||
1. state.json 存在且 status 为 "ready"
|
||||
2. 必要文件存在:reddit_profiles.json, twitter_profiles.csv, simulation_config.json
|
||||
2. simulation_config.json 和已启用平台对应的 Profile 文件存在
|
||||
|
||||
注意:运行脚本(run_*.py)保留在 backend/scripts/ 目录,不再复制到模拟目录
|
||||
|
||||
|
|
@ -295,10 +295,26 @@ def _check_simulation_prepared(simulation_id: str) -> tuple:
|
|||
# 必要文件列表(不包括脚本,脚本位于 backend/scripts/)
|
||||
required_files = [
|
||||
"state.json",
|
||||
"simulation_config.json",
|
||||
"reddit_profiles.json",
|
||||
"twitter_profiles.csv"
|
||||
"simulation_config.json"
|
||||
]
|
||||
|
||||
# Profile文件仅在对应平台启用时生成。旧状态文件没有平台字段,
|
||||
# 此时继续按双平台处理以保持向后兼容。
|
||||
state_file = os.path.join(simulation_dir, "state.json")
|
||||
platform_state = {}
|
||||
if os.path.exists(state_file):
|
||||
try:
|
||||
import json
|
||||
with open(state_file, 'r', encoding='utf-8') as f:
|
||||
platform_state = json.load(f)
|
||||
except (OSError, json.JSONDecodeError):
|
||||
# 保留后续原有的缺失文件和状态文件错误处理。
|
||||
pass
|
||||
|
||||
if platform_state.get("enable_reddit", True):
|
||||
required_files.append("reddit_profiles.json")
|
||||
if platform_state.get("enable_twitter", True):
|
||||
required_files.append("twitter_profiles.csv")
|
||||
|
||||
# 检查文件是否存在
|
||||
existing_files = []
|
||||
|
|
@ -318,7 +334,6 @@ def _check_simulation_prepared(simulation_id: str) -> tuple:
|
|||
}
|
||||
|
||||
# 检查state.json中的状态
|
||||
state_file = os.path.join(simulation_dir, "state.json")
|
||||
try:
|
||||
import json
|
||||
with open(state_file, 'r', encoding='utf-8') as f:
|
||||
|
|
@ -341,14 +356,19 @@ def _check_simulation_prepared(simulation_id: str) -> tuple:
|
|||
prepared_statuses = ["ready", "preparing", "running", "completed", "stopped", "failed"]
|
||||
if status in prepared_statuses and config_generated:
|
||||
# 获取文件统计信息
|
||||
profiles_file = os.path.join(simulation_dir, "reddit_profiles.json")
|
||||
config_file = os.path.join(simulation_dir, "simulation_config.json")
|
||||
|
||||
profiles_count = 0
|
||||
if os.path.exists(profiles_file):
|
||||
profiles_count = state_data.get("profiles_count", 0)
|
||||
if state_data.get("enable_reddit", True):
|
||||
profiles_file = os.path.join(simulation_dir, "reddit_profiles.json")
|
||||
with open(profiles_file, 'r', encoding='utf-8') as f:
|
||||
profiles_data = json.load(f)
|
||||
profiles_count = len(profiles_data) if isinstance(profiles_data, list) else 0
|
||||
elif state_data.get("enable_twitter", True):
|
||||
import csv
|
||||
profiles_file = os.path.join(simulation_dir, "twitter_profiles.csv")
|
||||
with open(profiles_file, 'r', encoding='utf-8', newline='') as f:
|
||||
profiles_count = sum(1 for _ in csv.DictReader(f))
|
||||
|
||||
# 如果状态是preparing但文件已完成,自动更新状态为ready
|
||||
if status == "preparing":
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from app.api.simulation import _check_simulation_prepared
|
||||
from app.config import Config
|
||||
|
||||
|
||||
def _write_prepared_simulation(
|
||||
root,
|
||||
*,
|
||||
enable_twitter=None,
|
||||
enable_reddit=None,
|
||||
profile_files=(),
|
||||
):
|
||||
simulation_id = "sim_prepared"
|
||||
simulation_dir = root / simulation_id
|
||||
simulation_dir.mkdir(parents=True)
|
||||
|
||||
state = {
|
||||
"status": "ready",
|
||||
"config_generated": True,
|
||||
"profiles_count": 1,
|
||||
}
|
||||
if enable_twitter is not None:
|
||||
state["enable_twitter"] = enable_twitter
|
||||
if enable_reddit is not None:
|
||||
state["enable_reddit"] = enable_reddit
|
||||
|
||||
(simulation_dir / "state.json").write_text(
|
||||
json.dumps(state),
|
||||
encoding="utf-8",
|
||||
)
|
||||
(simulation_dir / "simulation_config.json").write_text(
|
||||
"{}",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
for filename in profile_files:
|
||||
content = "[{}]" if filename.endswith(".json") else "user_id,user_name\n0,alice\n"
|
||||
(simulation_dir / filename).write_text(content, encoding="utf-8")
|
||||
|
||||
return simulation_id
|
||||
|
||||
|
||||
def test_twitter_only_simulation_does_not_require_reddit_profiles(tmp_path, monkeypatch):
|
||||
simulation_id = _write_prepared_simulation(
|
||||
tmp_path,
|
||||
enable_twitter=True,
|
||||
enable_reddit=False,
|
||||
profile_files=("twitter_profiles.csv",),
|
||||
)
|
||||
monkeypatch.setattr(Config, "OASIS_SIMULATION_DATA_DIR", str(tmp_path))
|
||||
|
||||
is_prepared, info = _check_simulation_prepared(simulation_id)
|
||||
|
||||
assert is_prepared is True
|
||||
assert info["profiles_count"] == 1
|
||||
assert "twitter_profiles.csv" in info["existing_files"]
|
||||
assert "reddit_profiles.json" not in info["existing_files"]
|
||||
|
||||
|
||||
def test_reddit_only_simulation_does_not_require_twitter_profiles(tmp_path, monkeypatch):
|
||||
simulation_id = _write_prepared_simulation(
|
||||
tmp_path,
|
||||
enable_twitter=False,
|
||||
enable_reddit=True,
|
||||
profile_files=("reddit_profiles.json",),
|
||||
)
|
||||
monkeypatch.setattr(Config, "OASIS_SIMULATION_DATA_DIR", str(tmp_path))
|
||||
|
||||
is_prepared, info = _check_simulation_prepared(simulation_id)
|
||||
|
||||
assert is_prepared is True
|
||||
assert info["profiles_count"] == 1
|
||||
assert "reddit_profiles.json" in info["existing_files"]
|
||||
assert "twitter_profiles.csv" not in info["existing_files"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("enable_twitter", "enable_reddit", "missing_profile"),
|
||||
[
|
||||
(True, False, "twitter_profiles.csv"),
|
||||
(False, True, "reddit_profiles.json"),
|
||||
],
|
||||
)
|
||||
def test_enabled_platform_profile_is_still_required(
|
||||
tmp_path,
|
||||
monkeypatch,
|
||||
enable_twitter,
|
||||
enable_reddit,
|
||||
missing_profile,
|
||||
):
|
||||
simulation_id = _write_prepared_simulation(
|
||||
tmp_path,
|
||||
enable_twitter=enable_twitter,
|
||||
enable_reddit=enable_reddit,
|
||||
)
|
||||
monkeypatch.setattr(Config, "OASIS_SIMULATION_DATA_DIR", str(tmp_path))
|
||||
|
||||
is_prepared, info = _check_simulation_prepared(simulation_id)
|
||||
|
||||
assert is_prepared is False
|
||||
assert info["missing_files"] == [missing_profile]
|
||||
|
||||
|
||||
def test_legacy_state_without_platform_flags_requires_both_profiles(tmp_path, monkeypatch):
|
||||
simulation_id = _write_prepared_simulation(
|
||||
tmp_path,
|
||||
profile_files=("reddit_profiles.json",),
|
||||
)
|
||||
monkeypatch.setattr(Config, "OASIS_SIMULATION_DATA_DIR", str(tmp_path))
|
||||
|
||||
is_prepared, info = _check_simulation_prepared(simulation_id)
|
||||
|
||||
assert is_prepared is False
|
||||
assert info["missing_files"] == ["twitter_profiles.csv"]
|
||||
Loading…
Reference in New Issue