2026-07-02 03:28:19 +08:00
|
|
|
|
"""yuxi.channels.adapters.masking_adapter 单元测试。
|
|
|
|
|
|
|
2026-07-08 12:58:43 +08:00
|
|
|
|
覆盖 ``MaskingAdapter`` 的 ``maskFull`` / ``maskPartial`` /
|
|
|
|
|
|
``isSensitiveKey`` 方法,使用 ``patch`` 替换 ``CryptoHelper``,
|
2026-07-02 03:28:19 +08:00
|
|
|
|
不依赖真实加解密配置。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
from yuxi.channels.adapters.masking_adapter import MaskingAdapter
|
|
|
|
|
|
|
|
|
|
|
|
pytestmark = pytest.mark.unit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _make_helper() -> MagicMock:
|
|
|
|
|
|
"""构造 CryptoHelper 桩。"""
|
|
|
|
|
|
helper = MagicMock()
|
|
|
|
|
|
helper.mask_full = MagicMock(return_value="***")
|
|
|
|
|
|
helper.mask_partial = MagicMock(return_value="abcd***")
|
2026-07-04 00:18:04 +08:00
|
|
|
|
helper.is_sensitive_key = MagicMock(return_value=True)
|
2026-07-02 03:28:19 +08:00
|
|
|
|
return helper
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.unit
|
|
|
|
|
|
class TestMaskingAdapterConstruction:
|
|
|
|
|
|
def test_init_loads_crypto_helper(self):
|
|
|
|
|
|
# Arrange
|
|
|
|
|
|
helper = _make_helper()
|
|
|
|
|
|
|
|
|
|
|
|
# Act
|
|
|
|
|
|
with patch(
|
|
|
|
|
|
"yuxi.channels.adapters.masking_adapter.get_crypto_helper",
|
|
|
|
|
|
return_value=helper,
|
|
|
|
|
|
):
|
|
|
|
|
|
adapter = MaskingAdapter()
|
|
|
|
|
|
|
|
|
|
|
|
# Assert
|
|
|
|
|
|
assert adapter._helper is helper
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.unit
|
|
|
|
|
|
class TestMaskingAdapterMaskFull:
|
|
|
|
|
|
def test_mask_full_delegates_to_helper(self):
|
|
|
|
|
|
# Arrange
|
|
|
|
|
|
helper = _make_helper()
|
|
|
|
|
|
with patch(
|
|
|
|
|
|
"yuxi.channels.adapters.masking_adapter.get_crypto_helper",
|
|
|
|
|
|
return_value=helper,
|
|
|
|
|
|
):
|
|
|
|
|
|
adapter = MaskingAdapter()
|
|
|
|
|
|
|
|
|
|
|
|
# Act
|
2026-07-08 12:58:43 +08:00
|
|
|
|
result = adapter.maskFull("secret-value")
|
2026-07-02 03:28:19 +08:00
|
|
|
|
|
|
|
|
|
|
# Assert
|
|
|
|
|
|
helper.mask_full.assert_called_once_with("secret-value")
|
|
|
|
|
|
assert result == "***"
|
|
|
|
|
|
|
|
|
|
|
|
def test_mask_full_passes_any_value_type(self):
|
|
|
|
|
|
# Arrange
|
|
|
|
|
|
helper = _make_helper()
|
|
|
|
|
|
helper.mask_full.return_value = {"masked": True}
|
|
|
|
|
|
with patch(
|
|
|
|
|
|
"yuxi.channels.adapters.masking_adapter.get_crypto_helper",
|
|
|
|
|
|
return_value=helper,
|
|
|
|
|
|
):
|
|
|
|
|
|
adapter = MaskingAdapter()
|
|
|
|
|
|
|
|
|
|
|
|
# Act
|
2026-07-08 12:58:43 +08:00
|
|
|
|
result = adapter.maskFull({"key": "value"})
|
2026-07-02 03:28:19 +08:00
|
|
|
|
|
|
|
|
|
|
# Assert
|
|
|
|
|
|
helper.mask_full.assert_called_once_with({"key": "value"})
|
|
|
|
|
|
assert result == {"masked": True}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.unit
|
|
|
|
|
|
class TestMaskingAdapterMaskPartial:
|
|
|
|
|
|
def test_mask_partial_delegates_to_helper(self):
|
|
|
|
|
|
# Arrange
|
|
|
|
|
|
helper = _make_helper()
|
|
|
|
|
|
with patch(
|
|
|
|
|
|
"yuxi.channels.adapters.masking_adapter.get_crypto_helper",
|
|
|
|
|
|
return_value=helper,
|
|
|
|
|
|
):
|
|
|
|
|
|
adapter = MaskingAdapter()
|
|
|
|
|
|
|
|
|
|
|
|
# Act
|
2026-07-08 12:58:43 +08:00
|
|
|
|
result = adapter.maskPartial("token-value")
|
2026-07-02 03:28:19 +08:00
|
|
|
|
|
|
|
|
|
|
# Assert
|
|
|
|
|
|
helper.mask_partial.assert_called_once_with("token-value")
|
|
|
|
|
|
assert result == "abcd***"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.unit
|
|
|
|
|
|
class TestMaskingAdapterIsSensitiveKey:
|
|
|
|
|
|
def test_is_sensitive_key_delegates_to_helper(self):
|
|
|
|
|
|
# Arrange
|
|
|
|
|
|
helper = _make_helper()
|
|
|
|
|
|
with patch(
|
|
|
|
|
|
"yuxi.channels.adapters.masking_adapter.get_crypto_helper",
|
|
|
|
|
|
return_value=helper,
|
|
|
|
|
|
):
|
|
|
|
|
|
adapter = MaskingAdapter()
|
|
|
|
|
|
|
|
|
|
|
|
# Act
|
2026-07-08 12:58:43 +08:00
|
|
|
|
result = adapter.isSensitiveKey("api_key")
|
2026-07-02 03:28:19 +08:00
|
|
|
|
|
|
|
|
|
|
# Assert
|
2026-07-04 00:18:04 +08:00
|
|
|
|
helper.is_sensitive_key.assert_called_once_with("api_key")
|
2026-07-02 03:28:19 +08:00
|
|
|
|
assert result is True
|
|
|
|
|
|
|
|
|
|
|
|
def test_is_sensitive_key_returns_false_for_non_sensitive(self):
|
|
|
|
|
|
# Arrange
|
|
|
|
|
|
helper = _make_helper()
|
2026-07-04 00:18:04 +08:00
|
|
|
|
helper.is_sensitive_key.return_value = False
|
2026-07-02 03:28:19 +08:00
|
|
|
|
with patch(
|
|
|
|
|
|
"yuxi.channels.adapters.masking_adapter.get_crypto_helper",
|
|
|
|
|
|
return_value=helper,
|
|
|
|
|
|
):
|
|
|
|
|
|
adapter = MaskingAdapter()
|
|
|
|
|
|
|
|
|
|
|
|
# Act
|
2026-07-08 12:58:43 +08:00
|
|
|
|
result = adapter.isSensitiveKey("display_name")
|
2026-07-02 03:28:19 +08:00
|
|
|
|
|
|
|
|
|
|
# Assert
|
|
|
|
|
|
assert result is False
|