Files
selfrelease fad458b2a7 docs(uiux): UIUX 设计方案大改 + 5 份作业指导书对齐 + 开发任务文档
- UIUX 文档:填充 19 个缺口(多主体画像/健康度/AI+看板/增长域/洞察域/创始人端/OODA/助推/商密)
- UIUX 文档:插入 6 个新章节(十四~十九),旧章节重编号为二十~三十一,更新目录和交叉引用
- 作业指导书 x5:导航改为 6 域分组,新增 Context Bar/工作模式/Insight Rail/决策线程/多工作区等 UI 概念
- 新建 docs/2-task-uiux.md:50 个代码落地开发任务,按 P0-P6 分优先级 + 8 Sprint 规划
- 后端/前端:大量新增模型、路由、组件(来自之前 Phase 开发)
2026-07-19 11:53:38 +08:00

82 lines
2.6 KiB
Python

"""T4.14 数据安全 + 合规加固测试。"""
import pytest
from fastapi.testclient import TestClient
from app.core.data_masking import mask_phone, mask_email, mask_id_card, mask_pii
from app.core.encryption import encrypt_field, decrypt_field
from app.core.rate_limit import RateLimiter
class TestDataMasking:
"""PII 脱敏测试。"""
def test_mask_phone(self):
"""手机号脱敏。"""
assert mask_phone("13812345678") == "138****5678"
def test_mask_email(self):
"""邮箱脱敏。"""
result = mask_email("zhangsan@example.com")
assert "***" in result
assert "example.com" in result
def test_mask_id_card(self):
"""身份证脱敏。"""
result = mask_id_card("110101199001011234")
assert "110" in result
assert "1234" in result
assert "*" in result
def test_mask_pii_text(self):
"""文本自动脱敏。"""
text = "联系方式:13812345678,邮箱:test@example.com"
result = mask_pii(text)
assert "13812345678" not in result
assert "test@example.com" not in result
assert "****" in result
def test_mask_pii_empty(self):
"""空文本应返回空。"""
assert mask_pii("") == ""
class TestEncryption:
"""加密存储测试。"""
def test_encrypt_decrypt_roundtrip(self):
"""加密后解密应还原原值。"""
original = "sk-1234567890abcdef"
encrypted = encrypt_field(original)
assert encrypted != original
decrypted = decrypt_field(encrypted)
assert decrypted == original
def test_encrypt_different_values(self):
"""不同值应产生不同密文。"""
assert encrypt_field("key1") != encrypt_field("key2")
class TestRateLimiter:
"""限流器测试。"""
def test_under_limit(self):
"""未超限应允许。"""
limiter = RateLimiter()
for _ in range(5):
assert limiter.check("test_key", max_requests=5, window_seconds=60) is True
def test_over_limit(self):
"""超限应拒绝。"""
limiter = RateLimiter()
for _ in range(5):
limiter.check("test_key2", max_requests=5, window_seconds=60)
assert limiter.check("test_key2", max_requests=5, window_seconds=60) is False
def test_different_keys_independent(self):
"""不同 key 应独立计数。"""
limiter = RateLimiter()
for _ in range(5):
limiter.check("key_a", max_requests=5, window_seconds=60)
assert limiter.check("key_b", max_requests=5, window_seconds=60) is True