8f016f25df
- ORM migration: models/ops 重构 - deploy: 标准化 systemd timer/service 部署体系 - MCP server: 5 个只读工具(任务/状态/数据集) - daily check: 数据一致性巡检 - watch: task_watch 后台监控 - kline_daily: 麦蕊优先,时间门禁15:00 - 删除: task_industry_sector, task_sector_features
108 lines
3.8 KiB
Python
108 lines
3.8 KiB
Python
"""冒烟测试:不依赖 MySQL/网络,只验证 import + 基本逻辑。
|
||
|
||
跑:pytest tests/test_smoke.py -v
|
||
"""
|
||
import pytest
|
||
|
||
|
||
def test_import_config():
|
||
from app.core.config import settings
|
||
assert settings is not None
|
||
assert hasattr(settings, "pg_host")
|
||
|
||
|
||
def test_import_data_source_base():
|
||
from app.core.datasource.base import DataSource, FetchResult, registry
|
||
assert DataSource is not None
|
||
assert FetchResult is not None
|
||
assert registry is not None
|
||
# registry 应该是 dict-like
|
||
assert hasattr(registry, "register")
|
||
assert hasattr(registry, "get")
|
||
|
||
|
||
def test_import_sync_base():
|
||
from app.core.sync.base import SyncTask, _is_market_closed, _effective_sync_end
|
||
assert SyncTask is not None
|
||
assert isinstance(_is_market_closed(), bool)
|
||
assert isinstance(_effective_sync_end(), str)
|
||
# 同步任务基类不允许空 dataset_id
|
||
with pytest.raises(ValueError):
|
||
SyncTask()
|
||
|
||
|
||
def test_tasks_registry():
|
||
from app.tasks import TASKS, get_task
|
||
assert isinstance(TASKS, dict)
|
||
# 注:每次新增 task 都要更新这里的数字
|
||
# 当前 12 个:stock_basic, kline_daily, kline_index, kline_5min, tick_trade,
|
||
# moneyflow, share_snapshot, market_regime,
|
||
# longhubang, mairui_ma_daily, stock_node, mairui_indicators
|
||
assert len(TASKS) == 12
|
||
# get_task 应该返回实例
|
||
task = get_task("kline_daily")
|
||
assert task.dataset_id == "kline_daily"
|
||
|
||
|
||
def test_sync_definitions():
|
||
from app.core.sync.registry import SYNC_DEFINITIONS
|
||
assert len(SYNC_DEFINITIONS) == 12
|
||
# 所有 dataset_id 应唯一
|
||
ids = [d["dataset_id"] for d in SYNC_DEFINITIONS]
|
||
assert len(set(ids)) == 12
|
||
# tick_trade 应在其中且 sort_order=45
|
||
tt = next(d for d in SYNC_DEFINITIONS if d["dataset_id"] == "tick_trade")
|
||
assert tt["sort_order"] == 45
|
||
assert "stock_basic" in tt["dependency_ids"]
|
||
# longhubang 应在其中且 sort_order=85
|
||
lh = next(d for d in SYNC_DEFINITIONS if d["dataset_id"] == "longhubang")
|
||
assert lh["sort_order"] == 85
|
||
assert "stock_basic" in lh["dependency_ids"]
|
||
# stock_node 应在其中且 sort_order=21
|
||
sn = next(d for d in SYNC_DEFINITIONS if d["dataset_id"] == "stock_node")
|
||
assert sn["sort_order"] == 21
|
||
assert "stock_basic" in sn["dependency_ids"]
|
||
|
||
|
||
def test_build_default_registry():
|
||
"""不连接网络,只看是否能完成注册(部分源 may not available 不影响注册)。"""
|
||
from app.core.datasource.base import registry
|
||
from app.core.datasource.registry import build_default_registry
|
||
build_default_registry()
|
||
keys = [s.key for s in registry.all()]
|
||
assert "datasource_xinlang" in keys
|
||
assert "datasource_baostock" in keys
|
||
assert "datasource_mairui" in keys
|
||
# akshare:2026-07-01 决策更新——龙虎榜无替代源,烟测通过,可注册。
|
||
# 见 [[no-akshare]] 记忆:仅"无替代"+"akshare 烟测 OK"才允许用。
|
||
assert "datasource_akshare_lhb" in keys
|
||
assert "datasource_xueqiu" in keys
|
||
|
||
|
||
def test_data_source_abstract():
|
||
"""DataSource 抽象方法未实现时不应能被直接实例化。"""
|
||
from app.core.datasource.base import DataSource
|
||
with pytest.raises(TypeError):
|
||
DataSource() # 抽象方法未实现
|
||
|
||
|
||
def test_api_health_route():
|
||
"""FastAPI 加载 + /api/health 路由可访问。"""
|
||
from fastapi.testclient import TestClient
|
||
from app.api.main import app
|
||
|
||
client = TestClient(app)
|
||
resp = client.get("/api/health")
|
||
assert resp.status_code == 200
|
||
body = resp.json()
|
||
assert body.get("status") == "ok"
|
||
|
||
|
||
def test_effective_sync_end_format():
|
||
from app.core.sync.base import _effective_sync_end
|
||
s = _effective_sync_end()
|
||
# YYYY-MM-DD 共 10 字符
|
||
assert len(s) == 10
|
||
assert s[4] == "-"
|
||
assert s[7] == "-"
|