- 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
77 lines
2.8 KiB
Python
77 lines
2.8 KiB
Python
"""Unit tests for crawler_core.qcwy.sign — Job51Sign.
|
|
|
|
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.qcwy.sign import Job51Sign, SIGN_KEY
|
|
|
|
|
|
class TestJob51SignInit:
|
|
def test_default_sign_key(self):
|
|
signer = Job51Sign()
|
|
assert signer.sign_key == SIGN_KEY
|
|
assert len(SIGN_KEY) == 64 # 64-char hex key
|
|
|
|
def test_custom_sign_key(self):
|
|
custom_key = "a" * 64
|
|
signer = Job51Sign(sign_key=custom_key)
|
|
assert signer.sign_key == custom_key
|
|
|
|
|
|
class TestJob51SignBuildSignPath:
|
|
def setup_method(self):
|
|
self.signer = Job51Sign()
|
|
|
|
def test_returns_tuple_of_two_strings(self):
|
|
result = self.signer.build_sign_path("open/test")
|
|
assert isinstance(result, tuple)
|
|
assert len(result) == 2
|
|
assert all(isinstance(s, str) for s in result)
|
|
|
|
def test_get_path_format(self):
|
|
path, sign = self.signer.build_sign_path("open/test", "GET")
|
|
assert path.startswith("/open/test?api_key=51job×tamp="), \
|
|
f"Path format wrong: {path}"
|
|
|
|
def test_sign_hex_length(self):
|
|
_, sign = self.signer.build_sign_path("open/test")
|
|
assert len(sign) == 64, f"Sign should be 64-char hex, got {len(sign)}: {sign}"
|
|
|
|
def test_sign_hex_format(self):
|
|
_, sign = self.signer.build_sign_path("open/test")
|
|
assert re.match(r'^[0-9a-f]{64}$', sign), f"Sign not hex: {sign}"
|
|
|
|
def test_get_vs_post_different_sign(self):
|
|
_, get_sign = self.signer.build_sign_path("open/test", "GET")
|
|
_, post_sign = self.signer.build_sign_path("open/test", "POST", body={"k": "v"})
|
|
assert get_sign != post_sign, "GET and POST should produce different signatures"
|
|
|
|
def test_get_with_params_includes_params_in_path(self):
|
|
path, _ = self.signer.build_sign_path("open/test", "GET", params={"city": "shanghai"})
|
|
assert "city" in path and "shanghai" in path, \
|
|
f"Params should appear in path: {path}"
|
|
|
|
def test_sign_key_in_path(self):
|
|
path, _ = self.signer.build_sign_path("open/jobs")
|
|
assert "api_key=51job" in path, f"api_key=51job missing from path: {path}"
|
|
|
|
|
|
class TestJob51SignGenerateUuid:
|
|
def test_generate_uuid_is_string(self):
|
|
uuid = Job51Sign.generate_uuid()
|
|
assert isinstance(uuid, str)
|
|
|
|
def test_generate_uuid_length(self):
|
|
uuid = Job51Sign.generate_uuid()
|
|
# 13-char ms timestamp + 10-char random int = 23 chars
|
|
assert len(uuid) == 23, f"Expected 23 chars, got {len(uuid)}: {uuid}"
|
|
|
|
def test_generate_uuid_numeric(self):
|
|
uuid = Job51Sign.generate_uuid()
|
|
assert uuid.isdigit(), f"UUID should be all digits: {uuid}"
|