Files
gaokao-volunteer-system/data/orders/tests/test_models.py
2026-06-18 15:36:24 +08:00

173 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""models 模块集成测试Order dataclass + 加解密串联)。"""
import os
import json
os.environ.setdefault("GAOKAO_ORDERS_FERNET_KEY", "test-secret-for-unit-tests")
from data.orders.models import Order, generate_order_id, utc_now_iso
from data.orders.crypto import decrypt, hash_for_index
def setup_function(_):
from data.orders import crypto
crypto.get_fernet.cache_clear()
def test_generate_order_id_format():
oid = generate_order_id()
assert oid.startswith("GKO-")
parts = oid.split("-")
assert len(parts) == 3
assert len(parts[1]) == 8 # YYYYMMDD
assert len(parts[2]) == 4
def test_order_auto_derives_phone_hash():
order = Order(
id="GKO-20260612-AAAA",
source="web",
service_version="basic",
amount_cents=1000,
customer_phone="13800001234",
customer_email="parent@example.com",
)
assert order.customer_phone_hash == hash_for_index("13800001234")
def test_order_to_db_row_encrypts_phone():
order = Order(
id="GKO-20260612-AAAB",
source="web",
service_version="basic",
amount_cents=1000,
customer_phone="13800001234",
customer_email="parent@example.com",
)
row = order.to_db_row()
# 明文不出现在 DB 行
assert "customer_phone" not in row or row.get("customer_phone") is None
# 加密字段存在
assert "customer_phone_enc" in row
assert row["customer_phone_enc"] != "13800001234"
# hash 字段保留
assert row["customer_phone_hash"] == hash_for_index("13800001234")
assert row["customer_email"] != "parent@example.com"
# 密文可解
assert decrypt(row["customer_phone_enc"]) == "13800001234"
assert decrypt(row["customer_email"]) == "parent@example.com"
def test_customer_email_is_not_stored_as_plaintext():
order = Order(
id="GKO-20260612-EMAIL",
source="web",
service_version="basic",
amount_cents=1000,
customer_phone="13800001234",
customer_email="parent@example.com",
)
row = order.to_db_row()
assert row["customer_email"] != "parent@example.com"
assert row["customer_email"]
def test_order_to_db_row_encrypts_id_card():
order = Order(
id="GKO-20260612-AAAC",
source="web",
service_version="basic",
amount_cents=1000,
candidate_id_card="430102200501011234",
)
row = order.to_db_row()
assert "candidate_id_card_enc" in row
assert "candidate_id_card" not in row or row.get("candidate_id_card") is None
assert decrypt(row["candidate_id_card_enc"]) == "430102200501011234"
def test_order_from_db_row_decrypts():
"""模拟数据库往返to_db_row → 模拟 DB 读取 → from_db_row。"""
order_in = Order(
id="GKO-20260612-AAAD",
source="xianyu",
external_id="EXT-X",
service_version="standard",
amount_cents=9900,
status="pending",
customer_name="张*",
customer_phone="13800001234",
candidate_name="张同学",
candidate_province="湖南",
candidate_score=578,
candidate_subjects=["物理", "化学", "生物"],
tags=["高优", "VIP"],
)
row = order_in.to_db_row()
order_out = Order.from_db_row(row)
assert order_out.customer_phone == "13800001234"
assert order_out.customer_name == "张*"
assert order_out.candidate_province == "湖南"
assert order_out.candidate_subjects == ["物理", "化学", "生物"]
assert order_out.tags == ["高优", "VIP"]
def test_order_to_dict_decrypt_sensitive_true():
order = Order(
id="GKO-20260612-AAAE",
source="web",
service_version="basic",
customer_phone="13800001234",
candidate_id_card="430102200501011234",
)
d = order.to_dict(decrypt_sensitive=True)
assert d["customer_phone"] == "13800001234"
assert d["candidate_id_card"] == "430102200501011234"
def test_order_to_dict_decrypt_sensitive_false():
order = Order(
id="GKO-20260612-AAAF",
source="web",
service_version="basic",
customer_phone="13800001234",
candidate_id_card="430102200501011234",
)
d = order.to_dict(decrypt_sensitive=False)
assert "customer_phone" not in d
assert "candidate_id_card" not in d
assert "customer_phone_hash" in d
def test_order_default_timestamps():
order = Order(
id="GKO-20260612-AAAG",
source="web",
service_version="basic",
)
assert order.created_at is not None
assert order.status_updated_at == order.created_at
def test_order_tags_json_serializable():
"""to_db_row 后 tags 为 JSON 字符串。"""
order = Order(
id="GKO-20260612-AAAH",
source="web",
service_version="basic",
tags=["a", "b"],
)
row = order.to_db_row()
# 重新解析应能还原
parsed = json.loads(row["tags"])
assert parsed == ["a", "b"]
def test_utc_now_iso_is_iso8601():
ts = utc_now_iso()
assert "T" in ts
assert ts.endswith("+00:00") or ts.endswith("Z")