JobData/tests/crawler_core/test_boss_sign.py
win 333a6d155e test(01-02): write sign algorithm unit tests for crawler_core
- Add tests/crawler_core/test_boss_sign.py: 13 tests for BossSign, _compute_checksum, _generate_uuid
- Add tests/crawler_core/test_qcwy_sign.py: 10 tests for Job51Sign and SIGN_KEY
- Add tests/crawler_core/test_zhilian_sign.py: 13 tests for ZhilianSign
- Add conftest.py at project root to add project root to sys.path
- Update pyproject.toml with [tool.pytest.ini_options] pythonpath config
- Fix crawler_core/__init__.py: wrap heavy-dep imports in try/except so sign subpackages are importable in lightweight envs without requests_go installed
- Remove tests/crawler_core/__init__.py to prevent namespace shadowing of crawler_core package
2026-03-21 18:20:43 +08:00

85 lines
3.0 KiB
Python

"""Unit tests for crawler_core.boss.sign — BossSign and helper functions.
All tests are pure function assertions: no HTTP, no network, no mocks.
"""
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
import re
import pytest
from crawler_core.boss.sign import BossSign, _compute_checksum, _generate_uuid, _CHARS
class TestBossSignGenerateTraceid:
def test_traceid_format(self):
tid = BossSign.generate_traceid()
assert re.match(r'^M-W[0-9a-f]{13}[0-9a-zA-Z]{6}[0-9a-zA-Z]{3}$', tid), \
f"Traceid format wrong: {tid}"
def test_traceid_length(self):
tid = BossSign.generate_traceid()
assert len(tid) == 25, f"Expected 25 chars, got {len(tid)}: {tid}"
def test_traceid_custom_prefix(self):
tid = BossSign.generate_traceid(prefix="X-Y")
assert tid.startswith("X-Y"), f"Expected X-Y prefix, got: {tid}"
def test_traceid_uniqueness(self):
t1 = BossSign.generate_traceid()
t2 = BossSign.generate_traceid()
assert t1 != t2, "Two calls should return different traceids"
def test_bosssign_init_defaults(self):
sign = BossSign()
assert sign.mpt == ""
assert sign.wt2 == ""
def test_bosssign_init_with_tokens(self):
sign = BossSign(mpt="mpt_token", wt2="wt2_token")
assert sign.mpt == "mpt_token"
assert sign.wt2 == "wt2_token"
class TestComputeChecksum:
def test_checksum_length(self):
checksum = _compute_checksum("1234567890abc456789") # 19 chars
assert len(checksum) == 3, f"Expected 3 chars, got {len(checksum)}"
def test_checksum_chars_in_base62(self):
checksum = _compute_checksum("1234567890abc456789")
for ch in checksum:
assert ch in _CHARS, f"Char {ch!r} not in base62 set"
def test_checksum_deterministic(self):
uuid_str = "1234567890abc456789"
c1 = _compute_checksum(uuid_str)
c2 = _compute_checksum(uuid_str)
assert c1 == c2, "Same input must produce same checksum"
def test_checksum_differs_for_different_input(self):
# Different inputs should (almost always) produce different checksums
c1 = _compute_checksum("1234567890abc456789")
c2 = _compute_checksum("9876543210xyz456789")
# Not guaranteed to differ but extremely likely
# We test at least that they are valid 3-char strings
assert len(c1) == 3 and len(c2) == 3
class TestGenerateUuid:
def test_generate_uuid_length(self):
uuid = _generate_uuid()
assert len(uuid) == 19, f"Expected 19 chars, got {len(uuid)}: {uuid}"
def test_generate_uuid_hex_prefix(self):
uuid = _generate_uuid()
hex_part = uuid[:13]
assert re.match(r'^[0-9a-f]{13}$', hex_part), \
f"First 13 chars should be hex: {hex_part}"
def test_generate_uuid_base62_suffix(self):
uuid = _generate_uuid()
rand_part = uuid[13:]
for ch in rand_part:
assert ch in _CHARS, f"Char {ch!r} in random suffix not in base62"