""" 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