- 新增多个集成服务(Slack、Notion、Twilio、Microsoft365等)的元数据、常量、凭证、错误处理相关单元测试 - 新增持久化适配器、工作单元、健康检查仓储的单元测试 - 修复认证插件测试中缺失的凭证类型注册 - 修正密钥轮换调度器的异常类型匹配 - 完善审计日志测试用例,新增创建者/更新者字段校验 - 新增告警触发时持久化通知渠道的测试 - 精简核心模型测试代码,移除冗余的超时测试用例
209 lines
6.9 KiB
Python
209 lines
6.9 KiB
Python
"""integrations/discovery.py 自动发现单元测试。
|
||
|
||
覆盖 discover_integration_packages() 的黑名单跳过、非包跳过、下划线前缀跳过、
|
||
ImportError 容错与非 ImportError 异常透传。
|
||
|
||
通过 monkeypatch 模拟 pkgutil.iter_modules 与 importlib.import_module 返回值,
|
||
避免触发真实集成包导入副作用(auth_plugins 等会向全局注册表写入不同实例导致冲突)。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import logging
|
||
from types import ModuleType
|
||
|
||
import pytest
|
||
|
||
from yuxi.external_systems.integrations import discovery
|
||
|
||
|
||
# ─── 黑名单 ───────────────────────────────────────────────────────────────
|
||
|
||
|
||
@pytest.mark.unit
|
||
def test_blacklist_includes_infrastructure_modules():
|
||
# Arrange / Act / Assert - 框架自身模块应在黑名单中
|
||
assert "registry" in discovery._BLACKLIST
|
||
assert "schemas" in discovery._BLACKLIST
|
||
assert "discovery" in discovery._BLACKLIST
|
||
assert "operation_registry" in discovery._BLACKLIST
|
||
|
||
|
||
@pytest.mark.unit
|
||
def test_blacklist_excludes_real_integration_packages():
|
||
# Arrange / Act / Assert - 真实厂商集成包不应在黑名单中
|
||
assert "salesforce" not in discovery._BLACKLIST
|
||
assert "hubspot" not in discovery._BLACKLIST
|
||
assert "jira" not in discovery._BLACKLIST
|
||
assert "slack" not in discovery._BLACKLIST
|
||
|
||
|
||
# ─── discover_integration_packages ────────────────────────────────────────
|
||
|
||
|
||
@pytest.mark.unit
|
||
def test_discoverIntegrationPackages_skips_non_package_modules(monkeypatch):
|
||
# Arrange - 模拟 iter_modules 返回非包项
|
||
def _mock_iter_modules(_path):
|
||
yield (None, "not_a_package", False)
|
||
yield (None, "real_package", True)
|
||
|
||
monkeypatch.setattr(discovery.pkgutil, "iter_modules", _mock_iter_modules)
|
||
|
||
imported: list[str] = []
|
||
|
||
def _mock_import_module(name):
|
||
imported.append(name)
|
||
return ModuleType(name)
|
||
|
||
monkeypatch.setattr(discovery.importlib, "import_module", _mock_import_module)
|
||
|
||
# Act
|
||
result = discovery.discover_integration_packages()
|
||
|
||
# Assert - 非包项(ispkg=False)应被跳过
|
||
assert "yuxi.external_systems.integrations.not_a_package" not in imported
|
||
assert "yuxi.external_systems.integrations.real_package" in imported
|
||
assert "yuxi.external_systems.integrations.real_package" in result
|
||
|
||
|
||
@pytest.mark.unit
|
||
def test_discoverIntegrationPackages_skips_underscore_prefixed(monkeypatch):
|
||
# Arrange
|
||
def _mock_iter_modules(_path):
|
||
yield (None, "_private", True)
|
||
yield (None, "salesforce", True)
|
||
|
||
monkeypatch.setattr(discovery.pkgutil, "iter_modules", _mock_iter_modules)
|
||
|
||
imported: list[str] = []
|
||
|
||
def _mock_import_module(name):
|
||
imported.append(name)
|
||
return ModuleType(name)
|
||
|
||
monkeypatch.setattr(discovery.importlib, "import_module", _mock_import_module)
|
||
|
||
# Act
|
||
discovery.discover_integration_packages()
|
||
|
||
# Assert - 下划线前缀应被跳过
|
||
assert "yuxi.external_systems.integrations._private" not in imported
|
||
assert "yuxi.external_systems.integrations.salesforce" in imported
|
||
|
||
|
||
@pytest.mark.unit
|
||
def test_discoverIntegrationPackages_skips_blacklisted_modules(monkeypatch):
|
||
# Arrange
|
||
def _mock_iter_modules(_path):
|
||
yield (None, "registry", True)
|
||
yield (None, "schemas", True)
|
||
yield (None, "discovery", True)
|
||
yield (None, "operation_registry", True)
|
||
yield (None, "salesforce", True)
|
||
|
||
monkeypatch.setattr(discovery.pkgutil, "iter_modules", _mock_iter_modules)
|
||
|
||
imported: list[str] = []
|
||
|
||
def _mock_import_module(name):
|
||
imported.append(name)
|
||
return ModuleType(name)
|
||
|
||
monkeypatch.setattr(discovery.importlib, "import_module", _mock_import_module)
|
||
|
||
# Act
|
||
discovery.discover_integration_packages()
|
||
|
||
# Assert - 黑名单模块应被跳过
|
||
for bl in ("registry", "schemas", "discovery", "operation_registry"):
|
||
assert f"yuxi.external_systems.integrations.{bl}" not in imported
|
||
assert "yuxi.external_systems.integrations.salesforce" in imported
|
||
|
||
|
||
@pytest.mark.unit
|
||
def test_discoverIntegrationPackages_logs_warning_on_importError(monkeypatch, caplog):
|
||
# Arrange
|
||
def _mock_iter_modules(_path):
|
||
yield (None, "broken_pkg", True)
|
||
|
||
monkeypatch.setattr(discovery.pkgutil, "iter_modules", _mock_iter_modules)
|
||
|
||
def _mock_import_module(name):
|
||
raise ImportError(f"missing dependency for {name}")
|
||
|
||
monkeypatch.setattr(discovery.importlib, "import_module", _mock_import_module)
|
||
|
||
# Act
|
||
with caplog.at_level(logging.WARNING):
|
||
result = discovery.discover_integration_packages()
|
||
|
||
# Assert - ImportError 应被捕获并记录警告,不向上抛出;失败包不计入返回
|
||
assert any("broken_pkg" in r.message and "加载失败" in r.message for r in caplog.records)
|
||
assert result == []
|
||
|
||
|
||
@pytest.mark.unit
|
||
def test_discoverIntegrationPackages_propagates_non_import_errors(monkeypatch):
|
||
# Arrange
|
||
def _mock_iter_modules(_path):
|
||
yield (None, "bad_pkg", True)
|
||
|
||
monkeypatch.setattr(discovery.pkgutil, "iter_modules", _mock_iter_modules)
|
||
|
||
def _mock_import_module(name):
|
||
raise RuntimeError("unexpected metadata error")
|
||
|
||
monkeypatch.setattr(discovery.importlib, "import_module", _mock_import_module)
|
||
|
||
# Act / Assert - 非 ImportError 应向上抛出
|
||
with pytest.raises(RuntimeError, match="unexpected metadata error"):
|
||
discovery.discover_integration_packages()
|
||
|
||
|
||
@pytest.mark.unit
|
||
def test_discoverIntegrationPackages_returns_imported_module_names(monkeypatch):
|
||
# Arrange
|
||
def _mock_iter_modules(_path):
|
||
yield (None, "pkg_a", True)
|
||
yield (None, "pkg_b", True)
|
||
yield (None, "pkg_c", False) # 非包,跳过
|
||
|
||
monkeypatch.setattr(discovery.pkgutil, "iter_modules", _mock_iter_modules)
|
||
|
||
def _mock_import_module(name):
|
||
return ModuleType(name)
|
||
|
||
monkeypatch.setattr(discovery.importlib, "import_module", _mock_import_module)
|
||
|
||
# Act
|
||
result = discovery.discover_integration_packages()
|
||
|
||
# Assert - 返回成功导入的模块名列表
|
||
assert result == [
|
||
"yuxi.external_systems.integrations.pkg_a",
|
||
"yuxi.external_systems.integrations.pkg_b",
|
||
]
|
||
|
||
|
||
@pytest.mark.unit
|
||
def test_discoverIntegrationPackages_empty_when_all_skipped(monkeypatch):
|
||
# Arrange - 全部被跳过
|
||
def _mock_iter_modules(_path):
|
||
yield (None, "registry", True)
|
||
yield (None, "_private", True)
|
||
yield (None, "not_pkg", False)
|
||
|
||
monkeypatch.setattr(discovery.pkgutil, "iter_modules", _mock_iter_modules)
|
||
|
||
def _mock_import_module(name):
|
||
raise AssertionError(f"不应导入 {name}")
|
||
|
||
monkeypatch.setattr(discovery.importlib, "import_module", _mock_import_module)
|
||
|
||
# Act
|
||
result = discovery.discover_integration_packages()
|
||
|
||
# Assert
|
||
assert result == []
|