b50495bebe
短信(SMS_MOCK 切 mock/real): - integrations/sms.py 重写: real 模式走极光短信 REST /v1/messages 自定义验证码(本服务 secrets 生成 6 位码 + 进程内存 + 本地校验一次性/防爆破), 鉴权复用极光一键登录 JG_APP_KEY/MASTER_SECRET (同一极光应用, 上线只需 SMS_MOCK=false); mock 仍"任意6位通过"不动其余测试 - 防刷四层: 单号冷却 + 单号每日上限 + 单IP rate_limit(/sms/send 10/min、/sms/login 20/min) + 单码失败次数作废; SmsError 带 status_code 映射 429/503/400 - config 增 SMS_SEND_ENDPOINT/SIGN_ID/TEMPLATE_ID/CODE_LENGTH/DAILY_LIMIT/MAX_VERIFY_ATTEMPTS; test_auth 加 real 模式单测; sms.md/后端技术实现/待办账本同步 admin 后台(app/admin/ 独立子应用, uvicorn app.admin.main:admin_app :8771): - 复用主仓 models/repositories/integrations + 同库, 鉴权完全隔离(ADMIN_JWT_SECRET≠JWT_SECRET_KEY + payload typ=admin + bcrypt 密码 + 可选 IP 白名单); 主 app 不 import 本包, admin 崩不影响主进程 - 路由: 登录 / 账号管理(RBAC: super_admin·finance·operator) / 用户列表+360详情+封禁+手动调币 / 钱包流水 / 提现重试对账 / 反馈工单 / 数据大盘; 全写操作落 admin_audit_log(涉钱与业务写同事务) - 涉钱逻辑(调微信/退款/对账)复用 app.repositories.wallet 不重写 - 新增 models/admin.py(AdminUser/AdminAuditLog) + admin_tables 迁移 + create_admin.py + deploy/shaguabijia-admin.service; 依赖加 bcrypt Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
60 lines
2.2 KiB
Python
60 lines
2.2 KiB
Python
"""测试用 fixtures。
|
|
|
|
测试 DB 用临时文件 SQLite。
|
|
- 不用 in-memory:in-memory 默认 per-connection,跨连接看不到表。
|
|
- 用临时文件保证 SessionLocal 每次新连都看到同一份 schema。
|
|
|
|
顺序:set env(必须在 import app.* 之前) → import app → 建表 → TestClient
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import tempfile
|
|
from collections.abc import Iterator
|
|
|
|
# 临时 db 文件路径,进程退出后清理
|
|
_tmp_db = tempfile.NamedTemporaryFile(suffix=".db", delete=False)
|
|
_tmp_db.close()
|
|
|
|
os.environ["DATABASE_URL"] = f"sqlite:///{_tmp_db.name}"
|
|
os.environ.setdefault("JWT_SECRET_KEY", "test-secret-please-ignore-this-is-only-for-pytest-not-real")
|
|
os.environ.setdefault("ADMIN_JWT_SECRET", "test-admin-secret-please-ignore-only-for-pytest-not-real")
|
|
os.environ.setdefault("JG_APP_KEY", "test-key")
|
|
os.environ.setdefault("JG_MASTER_SECRET", "test-secret")
|
|
os.environ.setdefault("SMS_MOCK", "true")
|
|
os.environ.setdefault("APP_ENV", "dev")
|
|
os.environ.setdefault("APP_DEBUG", "false") # 测试不打 SQL 日志
|
|
# 微信支付:填 dummy 让 wxpay_configured 为真(测试里 wxpay 的网络调用全 monkeypatch,不会真发)
|
|
os.environ.setdefault("WECHAT_APP_ID", "wxtest0000000000")
|
|
os.environ.setdefault("WECHAT_APP_SECRET", "test-secret")
|
|
os.environ.setdefault("WXPAY_MCH_ID", "test-mch")
|
|
os.environ.setdefault("WXPAY_MCH_SERIAL_NO", "test-serial")
|
|
os.environ.setdefault("WXPAY_PUBLIC_KEY_ID", "test-pubkey-id")
|
|
os.environ.setdefault("RATE_LIMIT_ENABLED", "false") # 限流内存计数会跨用例累加,测试关掉
|
|
# 穿山甲发奖回调:测试里开启 + 给个 mock 验签密钥,test 内自签自验闭环
|
|
os.environ.setdefault("PANGLE_CALLBACK_ENABLED", "true")
|
|
os.environ.setdefault("PANGLE_REWARD_SECRET", "test-pangle-secret-only-for-pytest")
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app.db.base import Base
|
|
from app.db.session import engine
|
|
from app.main import app
|
|
|
|
|
|
@pytest.fixture(scope="session", autouse=True)
|
|
def _setup_db() -> Iterator[None]:
|
|
Base.metadata.create_all(engine)
|
|
yield
|
|
Base.metadata.drop_all(engine)
|
|
try:
|
|
os.unlink(_tmp_db.name)
|
|
except OSError:
|
|
pass
|
|
|
|
|
|
@pytest.fixture()
|
|
def client() -> TestClient:
|
|
return TestClient(app)
|