tracksolid_timescale_grafan.../tests/unit/test_api_signing.py
David Kiania 6ed4d3a1e2 test: add test suite - unit tests, webhook endpoint tests, and CI workflow
57 unit tests covering clean helpers, API signing, and field mapping fixes
(FIX-E06, FIX-M16, BUG-01, BUG-03); integration tests for webhook endpoints
with mocked DB; Forgejo CI workflow with TimescaleDB service container.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 21:38:20 +03:00

60 lines
2.6 KiB
Python

"""Unit tests for Tracksolid API MD5 signature generation."""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
os.environ.setdefault("TRACKSOLID_APP_KEY", "test_key")
os.environ.setdefault("TRACKSOLID_APP_SECRET", "test_secret")
os.environ.setdefault("TRACKSOLID_USER_ID", "test_user")
os.environ.setdefault("TRACKSOLID_PWD_MD5", "test_md5")
os.environ.setdefault("DATABASE_URL", "postgresql://test:test@localhost:5432/test")
from ts_shared_rev import build_sign
class TestBuildSign:
def test_basic_signature(self):
"""Known input + secret produces expected MD5."""
params = {"method": "jimi.test", "app_key": "mykey", "v": "1.0"}
secret = "mysecret"
result = build_sign(params, secret)
# Verify it's a 32-char uppercase hex string
assert len(result) == 32
assert result == result.upper()
assert all(c in "0123456789ABCDEF" for c in result)
def test_sign_key_excluded(self):
"""The 'sign' key itself must be excluded from signing."""
params_with = {"method": "test", "sign": "old_sign", "v": "1.0"}
params_without = {"method": "test", "v": "1.0"}
secret = "secret"
assert build_sign(params_with, secret) == build_sign(params_without, secret)
def test_none_values_excluded(self):
"""Keys with None values are excluded from signing."""
params_with_none = {"method": "test", "optional": None, "v": "1.0"}
params_without_none = {"method": "test", "v": "1.0"}
secret = "secret"
assert build_sign(params_with_none, secret) == build_sign(params_without_none, secret)
def test_alphabetical_key_ordering(self):
"""Keys are sorted alphabetically for consistent signing."""
params_abc = {"a": "1", "b": "2", "c": "3"}
params_cba = {"c": "3", "b": "2", "a": "1"}
secret = "secret"
assert build_sign(params_abc, secret) == build_sign(params_cba, secret)
def test_different_secrets_produce_different_signs(self):
params = {"method": "test"}
assert build_sign(params, "secret1") != build_sign(params, "secret2")
def test_known_hash(self):
"""Verify against a manually computed hash."""
import hashlib
params = {"app_key": "ABC", "method": "test", "v": "1.0"}
secret = "XYZ"
sorted_keys = sorted(params.keys())
raw = secret + "".join(f"{k}{params[k]}" for k in sorted_keys) + secret
expected = hashlib.md5(raw.encode("utf-8")).hexdigest().upper()
assert build_sign(params, secret) == expected