ForcePilot/backend/test/unit/external_systems/integrations/test_discovery.py

209 lines
6.9 KiB
Python
Raw Normal View History

"""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 == []