Files
group_xinghuo_jinrong/tests/test_wave1_data_masker.py
T
zhanghongyu_0626 b841f68295 feat(visitor): Implement visitor chat functionality and enhance customer service interactions
- Added a new visitor chat API endpoint (`/api/chat/visitor`) to allow unauthenticated users to engage in conversations without requiring customer data.
- Introduced a visitor context dependency to manage visitor interactions seamlessly.
- Enhanced the chat API to support explicit session termination and improved response handling for customer service interactions.
- Updated the database configuration to include Redis client support for caching visitor data.
- Added a new customer note repository to persist user notes independently of the L1 profile slots.

This update significantly improves the customer service experience by enabling visitor interactions and ensuring efficient data handling for both registered and unregistered users.
2026-09-09 18:32:00 +08:00

180 lines
5.6 KiB
Python

"""Wave 1:信息脱敏模块单元测试(CS-C-12,纯函数无需 DB)。"""
from app.utils.data_masker import (
mask_bank_card,
mask_dict_fields,
mask_id_card,
mask_name,
mask_phone,
mask_text,
)
# ---------------------------------------------------------------------------
# 手机号
# ---------------------------------------------------------------------------
def test_mask_phone_standard():
assert mask_phone("13812345678") == "138****5678"
def test_mask_phone_already_masked_passthrough():
assert mask_phone("139****1001") == "139****1001"
def test_mask_phone_none_and_empty():
assert mask_phone(None) is None
assert mask_phone("") == ""
def test_mask_phone_invalid_format_untouched():
assert mask_phone("12345") == "12345" # 非 11 位手机号不强行处理
# ---------------------------------------------------------------------------
# 身份证
# ---------------------------------------------------------------------------
def test_mask_id_card_18_digits():
assert mask_id_card("110101199003071234") == "110***********1234"
def test_mask_id_card_18_with_tail_x():
assert mask_id_card("11010119900307123X") == "110***********123X"
assert mask_id_card("11010119900307123x") == "110***********123X" # 小写 x 归一
def test_mask_id_card_15_digits_legacy():
# 15 位老证:前 3 + 8 个 * + 后 4
assert mask_id_card("110101900307123") == "110********7123"
def test_mask_id_card_already_masked_passthrough():
assert mask_id_card("310101199903XXXXXX") == "310101199903XXXXXX"
# ---------------------------------------------------------------------------
# 姓名(只保留姓)
# ---------------------------------------------------------------------------
def test_mask_name_two_chars():
assert mask_name("张三") == "张*"
assert mask_name("李四") == "李*"
def test_mask_name_three_chars():
assert mask_name("张明明") == "张**"
def test_mask_name_four_or_more():
assert mask_name("欧阳修先生") == "欧****"
def test_mask_name_already_masked_passthrough():
assert mask_name("客户·王**") == "客户·王**"
assert mask_name("陈**兰") == "陈**兰"
def test_mask_name_none_and_single():
assert mask_name(None) is None
assert mask_name("张") == "张"
# ---------------------------------------------------------------------------
# 银行卡
# ---------------------------------------------------------------------------
def test_mask_bank_card_continuous():
assert mask_bank_card("6222021234567890") == "************7890"
def test_mask_bank_card_with_spaces():
assert mask_bank_card("6222 0212 3456 7890") == "**** **** **** 7890"
def test_mask_bank_card_with_hyphens():
assert mask_bank_card("6222-0212-3456-7890") == "****-****-****-7890"
def test_mask_bank_card_too_short_untouched():
assert mask_bank_card("12345") == "12345"
# ---------------------------------------------------------------------------
# 自由文本兜底扫描
# ---------------------------------------------------------------------------
def test_mask_text_mixed_pii():
text = "我的手机13812345678,身份证110101199003071234,卡号6222021234567890"
out = mask_text(text)
assert "138****5678" in out
assert "110***********1234" in out
assert "************7890" in out
def test_mask_text_spaced_bank_card():
out = mask_text("收款卡号 6222 0212 3456 7890 请查收")
assert "**** **** **** 7890" in out
def test_mask_text_legacy_id_card():
out = mask_text("老证号 110101900307123 已登记")
assert "110********7123" in out
def test_mask_text_no_pii_untouched():
text = "今天想了解一下货币基金的赎回规则"
assert mask_text(text) == text
def test_mask_text_amount_and_date_not_falsely_masked():
# 金额(小数点分隔)与日期不应被当作卡号/身份证
assert mask_text("金额520000.00元") == "金额520000.00元"
assert mask_text("到期日2026-09-08") == "到期日2026-09-08"
def test_mask_text_phone_not_cut_from_card():
# 16 位卡号中即便包含 1[3-9] 开头的片段,也不应被手机号规则误切
out = mask_text("6222138123456789")
assert out == "************6789"
# ---------------------------------------------------------------------------
# 结构化数据批量脱敏
# ---------------------------------------------------------------------------
def test_mask_dict_fields_single_row():
row = {
"customer_id": "CUST-1001",
"display_name": "李四",
"phone_mask": "139****1001", # 库中已脱敏 → 放行
"payer_name": "王五",
"amount": 5000.00, # 非字符串原样保留
}
out = mask_dict_fields(row)
assert out["display_name"] == "李*"
assert out["phone_mask"] == "139****1001"
assert out["payer_name"] == "王*"
assert out["amount"] == 5000.00
assert out["customer_id"] == "CUST-1001"
# 不入参修改
assert row["display_name"] == "李四"
def test_mask_dict_fields_list_of_rows():
rows = [
{"product_name": "现金宝货币", "counterparty_name": "张三"},
{"product_name": "稳健债基", "counterparty_name": "李四"},
]
out = mask_dict_fields(rows)
assert out[0]["counterparty_name"] == "张*"
assert out[1]["counterparty_name"] == "李*"
assert out[0]["product_name"] == "现金宝货币"
def test_mask_dict_fields_custom_mapping():
row = {"contact_mobile": "13812345678", "remark": "ok"}
out = mask_dict_fields(row, {"contact_mobile": "phone"})
assert out["contact_mobile"] == "138****5678"
assert out["remark"] == "ok"