Files
xiaoxia-saas/tests/unit/test_feature_flags_infra.py
T
CI Bot 0c84ec2cf6 test(unit): P3-1 核心模块单元测试覆盖率提升 - 新增12个模块测试
- wechat_sync_use_case: 0% → 100%(14个测试)
- jwt_handler: 45% → 100%(8个测试)
- password_handler: 46% → 100%(6个测试)
- job领域模型: 0% → 96%(53个测试)
- quota配额系统: 0% → 100%(61个测试)
- generation_task领域模型: 0% → 97%(50个测试)
- feature_flags基础设施层: 0% → 100%(39个测试)
- subtitle字幕领域模型: 0% → 98%(48个测试)
- duplication查重记录: 0% → 100%(31个测试)
- tts_config配音配置: 0% → 100%(35个测试)
- edit_template剪辑模板: 0% → 93%(17个测试)
- voice_clone_profile音色克隆: 0% → 95%(51个测试)

全量单元测试:3026 passed, 8 skipped(0失败)
新增测试用例约391个
2026-07-21 00:16:43 +08:00

348 lines
14 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Feature Flags 基础设施层单元测试
"""
import pytest
from packages.infrastructure.feature_flags import (
FeatureFlag,
FeatureFlags,
FeatureScope,
feature_flags,
)
class TestFeatureFlag:
"""FeatureFlag 单个开关测试"""
def test_default_values(self):
"""测试默认值"""
flag = FeatureFlag(name="test_flag")
assert flag.name == "test_flag"
assert flag.description == ""
assert flag.global_enabled is True
assert flag.plan_overrides == {}
assert flag.user_overrides == {}
def test_is_enabled_global_true(self):
"""测试全局启用"""
flag = FeatureFlag(name="test", global_enabled=True)
assert flag.is_enabled() is True
def test_is_enabled_global_false(self):
"""测试全局禁用"""
flag = FeatureFlag(name="test", global_enabled=False)
assert flag.is_enabled() is False
def test_is_enabled_plan_override(self):
"""测试套餐级别覆盖"""
flag = FeatureFlag(
name="test",
global_enabled=True,
plan_overrides={"free": False, "premium": True},
)
# free 套餐被覆盖为 False
assert flag.is_enabled(user_plan="free") is False
# premium 套餐覆盖为 True
assert flag.is_enabled(user_plan="premium") is True
# 没有覆盖的套餐用全局值
assert flag.is_enabled(user_plan="basic") is True
def test_is_enabled_user_override_priority(self):
"""测试用户白名单优先级最高"""
flag = FeatureFlag(
name="test",
global_enabled=False,
plan_overrides={"premium": True},
user_overrides={"user-1": True, "user-2": False},
)
# 用户白名单 True → 全局禁用也能启用
assert flag.is_enabled(user_plan="free", user_id="user-1") is True
# 用户白名单 False → premium 套餐也禁用
assert flag.is_enabled(user_plan="premium", user_id="user-2") is False
# 没有用户白名单 → 走套餐级别
assert flag.is_enabled(user_plan="premium", user_id="user-3") is True
def test_is_enabled_no_params(self):
"""测试不传任何参数时使用全局值"""
flag = FeatureFlag(name="test", global_enabled=True)
assert flag.is_enabled() is True
def test_is_enabled_empty_strings_treated_as_none(self):
"""测试空字符串 user_id/user_plan 不触发覆盖"""
flag = FeatureFlag(
name="test",
global_enabled=True,
plan_overrides={"free": False},
user_overrides={"": True}, # 空字符串key
)
# 空字符串 user_id 被当作 falsy,不走用户白名单分支
assert flag.is_enabled(user_id="", user_plan="") is True
def test_plan_override_does_not_affect_other_plans(self):
"""测试套餐覆盖不影响其他套餐"""
flag = FeatureFlag(
name="test",
global_enabled=True,
plan_overrides={"free": False},
)
assert flag.is_enabled(user_plan="free") is False
assert flag.is_enabled(user_plan="basic") is True
assert flag.is_enabled(user_plan="premium") is True
def test_user_override_can_enable_for_disabled_plan(self):
"""测试用户白名单可以为被禁用的套餐用户单独启用"""
flag = FeatureFlag(
name="test",
global_enabled=False,
plan_overrides={"premium": True},
user_overrides={"special-user": True},
)
# free 套餐用户 + 白名单 → 启用
assert flag.is_enabled(user_plan="free", user_id="special-user") is True
def test_user_override_can_disable_for_enabled_plan(self):
"""测试用户白名单可以为启用套餐的用户单独禁用"""
flag = FeatureFlag(
name="test",
global_enabled=True,
user_overrides={"bad-user": False},
)
assert flag.is_enabled(user_id="bad-user") is False
class TestFeatureScope:
"""FeatureScope 常量测试"""
def test_scope_constants(self):
"""测试所有常量存在"""
assert FeatureScope.AI_VOICE_GENERATION == "ai_voice_generation"
assert FeatureScope.DEDUPLICATION_REPORT == "deduplication_report"
assert FeatureScope.BATCH_EXPORT == "batch_export"
assert FeatureScope.MULTI_PLATFORM_OUTPUT == "multi_platform_output"
assert FeatureScope.RECIPE_REUSE == "recipe_reuse"
class TestFeatureFlags:
"""FeatureFlags 管理器测试"""
@pytest.fixture
def flags(self):
"""创建新的 FeatureFlags 实例(不影响全局单例)"""
return FeatureFlags()
# ===== 初始化 =====
def test_default_flags_exist(self, flags):
"""测试默认 flags 已注册"""
all_flags = flags.list_flags()
assert FeatureScope.AI_VOICE_GENERATION in all_flags
assert FeatureScope.DEDUPLICATION_REPORT in all_flags
assert FeatureScope.BATCH_EXPORT in all_flags
assert FeatureScope.MULTI_PLATFORM_OUTPUT in all_flags
assert FeatureScope.RECIPE_REUSE in all_flags
def test_default_ai_voice_generation(self, flags):
"""测试 AI 配音功能默认配置"""
# free 套餐不可用
assert flags.is_enabled("ai_voice_generation", user_plan="free") is False
# basic 套餐可用
assert flags.is_enabled("ai_voice_generation", user_plan="basic") is True
# premium 套餐可用
assert flags.is_enabled("ai_voice_generation", user_plan="premium") is True
def test_default_deduplication_report(self, flags):
"""测试去重报告默认配置(仅 premium"""
assert flags.is_enabled("deduplication_report", user_plan="free") is False
assert flags.is_enabled("deduplication_report", user_plan="basic") is False
assert flags.is_enabled("deduplication_report", user_plan="premium") is True
def test_default_multi_platform_output(self, flags):
"""测试多平台输出默认配置(仅 premium"""
assert flags.is_enabled("multi_platform_output", user_plan="free") is False
assert flags.is_enabled("multi_platform_output", user_plan="basic") is False
assert flags.is_enabled("multi_platform_output", user_plan="premium") is True
def test_default_batch_export(self, flags):
"""测试批量导出默认配置"""
assert flags.is_enabled("batch_export", user_plan="free") is False
assert flags.is_enabled("batch_export", user_plan="basic") is True
assert flags.is_enabled("batch_export", user_plan="premium") is True
def test_default_recipe_reuse(self, flags):
"""测试配方复用默认配置"""
assert flags.is_enabled("recipe_reuse", user_plan="free") is False
assert flags.is_enabled("recipe_reuse", user_plan="basic") is True
assert flags.is_enabled("recipe_reuse", user_plan="premium") is True
# ===== 注册新 flag =====
def test_register_new_flag(self, flags):
"""测试注册新的 feature flag"""
new_flag = FeatureFlag(name="new_feature", description="新功能", global_enabled=False)
flags.register(new_flag)
assert flags.get("new_feature") is not None
assert flags.get("new_feature").description == "新功能"
assert flags.is_enabled("new_feature") is False
def test_register_overwrites_existing(self, flags):
"""测试注册同名 flag 会覆盖"""
flag1 = FeatureFlag(name="test", global_enabled=True, description="v1")
flags.register(flag1)
assert flags.get("test").description == "v1"
flag2 = FeatureFlag(name="test", global_enabled=False, description="v2")
flags.register(flag2)
assert flags.get("test").description == "v2"
assert flags.is_enabled("test") is False
# ===== get 方法 =====
def test_get_existing_flag(self, flags):
"""测试获取存在的 flag"""
flag = flags.get("ai_voice_generation")
assert flag is not None
assert flag.name == "ai_voice_generation"
def test_get_nonexistent_flag(self, flags):
"""测试获取不存在的 flag 返回 None"""
assert flags.get("nonexistent") is None
# ===== is_enabled 方法 =====
def test_is_enabled_nonexistent_flag_returns_false(self, flags):
"""测试不存在的 flag 返回 False"""
assert flags.is_enabled("nonexistent_flag") is False
def test_is_enabled_without_plan_or_user(self, flags):
"""测试不传套餐和用户ID"""
assert flags.is_enabled("ai_voice_generation") is True
# ===== set_global =====
def test_set_global_enable(self, flags):
"""测试设置全局启用"""
flags.set_global("ai_voice_generation", enabled=False)
assert flags.is_enabled("ai_voice_generation", user_plan="premium") is False
def test_set_global_disable(self, flags):
"""测试设置全局禁用"""
flags.set_global("deduplication_report", enabled=False)
assert flags.is_enabled("deduplication_report", user_plan="premium") is False
def test_set_global_nonexistent_raises(self, flags):
"""测试设置不存在的 flag 抛出异常"""
with pytest.raises(KeyError, match="not found"):
flags.set_global("nonexistent", enabled=True)
# ===== set_plan_override =====
def test_set_plan_override(self, flags):
"""测试设置套餐覆盖"""
# 先确认 basic 套餐默认是去重报告禁用
assert flags.is_enabled("deduplication_report", user_plan="basic") is False
flags.set_plan_override("deduplication_report", "basic", True)
assert flags.is_enabled("deduplication_report", user_plan="basic") is True
def test_set_plan_override_nonexistent_raises(self, flags):
"""测试设置不存在 flag 的套餐覆盖抛出异常"""
with pytest.raises(KeyError, match="not found"):
flags.set_plan_override("nonexistent", "free", True)
# ===== set_user_override =====
def test_set_user_override_enable(self, flags):
"""测试设置用户白名单启用"""
assert flags.is_enabled("deduplication_report", user_plan="free", user_id="user-1") is False
flags.set_user_override("deduplication_report", "user-1", True)
assert flags.is_enabled("deduplication_report", user_plan="free", user_id="user-1") is True
def test_set_user_override_disable(self, flags):
"""测试设置用户白名单禁用"""
assert flags.is_enabled("batch_export", user_plan="premium", user_id="user-2") is True
flags.set_user_override("batch_export", "user-2", False)
assert flags.is_enabled("batch_export", user_plan="premium", user_id="user-2") is False
def test_set_user_override_nonexistent_raises(self, flags):
"""测试设置不存在 flag 的用户覆盖抛出异常"""
with pytest.raises(KeyError, match="not found"):
flags.set_user_override("nonexistent", "user-1", True)
# ===== list_flags =====
def test_list_flags_returns_copy(self, flags):
"""测试 list_flags 返回副本"""
all_flags = flags.list_flags()
all_flags["fake"] = FeatureFlag(name="fake")
# 原注册表不应被修改
assert "fake" not in flags.list_flags()
def test_list_flags_count(self, flags):
"""测试默认 flag 数量"""
all_flags = flags.list_flags()
assert len(all_flags) == 5 # 5 个默认 flag
# ===== get_enabled_for_plan =====
def test_get_enabled_for_free_plan(self, flags):
"""测试 free 套餐启用的功能"""
enabled = flags.get_enabled_for_plan("free")
# free 套餐应该只有 0 个默认启用的功能?不对,让我看看...
# 所有5个默认功能 free 套餐都是 False 吗?
# AI_VOICE_GENERATION: free=False
# DEDUPLICATION_REPORT: free=False, basic=False
# BATCH_EXPORT: free=False
# MULTI_PLATFORM_OUTPUT: free=False, basic=False
# RECIPE_REUSE: free=False
# 所以 free 套餐一个都没有?
assert len(enabled) == 0
def test_get_enabled_for_premium_plan(self, flags):
"""测试 premium 套餐启用的功能"""
enabled = flags.get_enabled_for_plan("premium")
# premium 套餐所有功能都应该启用
assert len(enabled) == 5
assert "ai_voice_generation" in enabled
assert "deduplication_report" in enabled
assert "batch_export" in enabled
assert "multi_platform_output" in enabled
assert "recipe_reuse" in enabled
def test_get_enabled_for_basic_plan(self, flags):
"""测试 basic 套餐启用的功能"""
enabled = flags.get_enabled_for_plan("basic")
# basic: ai_voice=True, dedup=False, batch=True, multi=False, recipe=True
assert "ai_voice_generation" in enabled
assert "deduplication_report" not in enabled
assert "batch_export" in enabled
assert "multi_platform_output" not in enabled
assert "recipe_reuse" in enabled
assert len(enabled) == 3
class TestGlobalSingleton:
"""全局单例测试"""
def test_global_singleton_exists(self):
"""测试全局单例存在"""
assert feature_flags is not None
assert isinstance(feature_flags, FeatureFlags)
def test_global_singleton_has_defaults(self):
"""测试全局单例有默认配置"""
assert feature_flags.get("ai_voice_generation") is not None
assert feature_flags.get("deduplication_report") is not None
def test_global_singleton_independent_from_new_instance(self):
"""测试全局单例与新实例相互独立"""
new_flags = FeatureFlags()
new_flags.set_global("ai_voice_generation", False)
# 全局单例不应受影响
assert feature_flags.is_enabled("ai_voice_generation") is True