d855fc30ba
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 26s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m28s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m23s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m3s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m11s
AI Code Review / AI Code Review (pull_request) Successful in 6m49s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m42s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Failing after 14m49s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m30s
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
- scripts_ai.py: 支持通过 DOUYIN_COOKIES_FILE 指定 Netscape cookies 文件;
cookies 缺失/过期类错误('fresh cookies' 等)返回 503 + 友好文案
('抖音链接解析暂时不可用,请稍后重试或手动输入文案'),
不再暴露 yt-dlp 原始错误;普通下载失败统一文案,不带内部异常文本
- ci_staging_deploy.sh: API 容器挂载 /var/lib/xiaoxia-saas-staging/configs/douyin_cookies.txt
到 /app/configs/douyin_cookies.txt;自动 mkdir + 空占位兜底
- infra/docker/compose.yml: API 服务挂载 ../../deploy/configs:/app/configs:ro
- deploy/configs/.env.{staging,production}: 新增 DOUYIN_COOKIES_FILE 环境变量
- deploy/configs/douyin_cookies.txt: Netscape 格式占位文件(真实 cookies 部署时替换)
- 新增 test_helpers_get_user_plan.py 覆盖 _helpers.get_user_plan 旧档位归一化分支
- 新增 test_subscription_routes_legacy.py 覆盖 _build_subscription_info 旧档位归一化/
cancel_subscription 免费用户分支/change_plan 参数校验/toggle-auto-renew 等
- 扩展 test_extract_from_douyin_errors.py: 新增 5 个 cookies 场景测试(503 友好文案/
cookiefile 注入/错误信息脱敏等)
- 增量覆盖率从 59% 提升到 60%+,解决 CI Gate 阻塞
73 lines
2.0 KiB
Python
73 lines
2.0 KiB
Python
"""验证 _helpers.get_user_plan 档位归一化逻辑(#1894 旧档位兼容)"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from unittest import mock
|
||
|
||
import pytest
|
||
from app.api.routes import _helpers
|
||
|
||
|
||
class _FakeUser:
|
||
def __init__(self, plan):
|
||
self.subscription_plan = plan
|
||
|
||
|
||
class _FakeUserNoPlan:
|
||
pass
|
||
|
||
|
||
class _FakeRepo:
|
||
def __init__(self, user=None):
|
||
self._user = user
|
||
|
||
def find_by_id(self, uid):
|
||
return self._user
|
||
|
||
|
||
def test_user_not_found_returns_free():
|
||
"""用户不存在时返回 free(覆盖 _helpers.py 第 41 行 user is None 分支)"""
|
||
repo = _FakeRepo(user=None)
|
||
assert _helpers.get_user_plan("u-missing", repo) == "free"
|
||
|
||
|
||
def test_user_plan_none_returns_free():
|
||
"""用户 plan 属性为 None 时返回 free"""
|
||
repo = _FakeRepo(user=_FakeUser(None))
|
||
assert _helpers.get_user_plan("u1", repo) == "free"
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"legacy,expected",
|
||
[
|
||
("standard", "monthly"),
|
||
("basic", "monthly"),
|
||
("pro", "quarterly"),
|
||
("premium", "quarterly"),
|
||
("enterprise", "quarterly"),
|
||
],
|
||
)
|
||
def test_legacy_plans_normalized(legacy, expected):
|
||
"""旧档位值正确归一化到新体系"""
|
||
repo = _FakeRepo(user=_FakeUser(legacy))
|
||
assert _helpers.get_user_plan("u1", repo) == expected
|
||
|
||
|
||
def test_unknown_plan_returns_free():
|
||
"""未知 plan 值(非新旧任一档位)→ 回落到 free(覆盖第 47 行)"""
|
||
repo = _FakeRepo(user=_FakeUser("totally_unknown_plan_xyz"))
|
||
assert _helpers.get_user_plan("u1", repo) == "free"
|
||
|
||
|
||
def test_user_without_subscription_plan_attr_returns_free():
|
||
"""user 对象没有 subscription_plan 属性时返回 free(getattr 默认值分支)"""
|
||
repo = _FakeRepo(user=_FakeUserNoPlan())
|
||
assert _helpers.get_user_plan("u1", repo) == "free"
|
||
|
||
|
||
@pytest.mark.parametrize("plan", ["free", "monthly", "quarterly", "yearly"])
|
||
def test_valid_new_plans_passthrough(plan):
|
||
"""新档位直接透传"""
|
||
repo = _FakeRepo(user=_FakeUser(plan))
|
||
assert _helpers.get_user_plan("u1", repo) == plan
|