Разработана первая версия приложений

This commit is contained in:
mi
2026-07-10 18:06:14 +03:00
parent aa8761d1b3
commit 8c7b4074c4
162 changed files with 12178 additions and 16 deletions
@@ -0,0 +1,80 @@
import uuid
import pytest
from pydantic import TypeAdapter, ValidationError
from app.auth import canonical_phone
from app.integrations import CircuitBreaker, RateLimiter
from app.schemas import (
FileMessageRequest,
MessageRequest,
TextMessageRequest,
canonical_fingerprint,
decode_cursor,
encode_cursor,
)
def test_phone_claim_priority_and_e164_validation() -> None:
claims = {"phone_number": "+74999591007", "preferred_username": "+12025550123"}
assert canonical_phone(claims) == "+74999591007"
assert canonical_phone({"phone_number": "89999999999"}) is None
def test_message_discriminated_union() -> None:
adapter = TypeAdapter(MessageRequest)
assert isinstance(
adapter.validate_python({"content_kind": "text", "text": "Здравствуйте"}),
TextMessageRequest,
)
assert isinstance(
adapter.validate_python(
{
"content_kind": "file",
"attachment_id": str(uuid.uuid4()),
"checksum": "sha256:" + "a" * 64,
}
),
FileMessageRequest,
)
with pytest.raises(ValidationError):
adapter.validate_python(
{"content_kind": "text", "text": "", "attachment_id": str(uuid.uuid4())}
)
def test_fingerprint_is_canonical_and_user_scoped() -> None:
user = uuid.uuid4()
first = canonical_fingerprint("post", "/dialogs/{id}", {"id": "1"}, {"b": 2, "a": 1}, user)
second = canonical_fingerprint("POST", "/dialogs/{id}", {"id": "1"}, {"a": 1, "b": 2}, user)
assert first == second
assert first != canonical_fingerprint(
"POST", "/dialogs/{id}", {"id": "1"}, {"a": 1, "b": 2}, uuid.uuid4()
)
def test_cursor_roundtrip_and_tamper_rejection() -> None:
secret = b"test-secret" * 4
cursor = encode_cursor({"id": str(uuid.uuid4()), "created_at": "2026-01-01"}, secret)
assert decode_cursor(cursor, secret)["created_at"] == "2026-01-01"
with pytest.raises(ValueError, match="invalid cursor"):
decode_cursor(cursor[:-2] + "aa", secret)
def test_rate_limit_keys_do_not_expose_identity() -> None:
key = RateLimiter.key("ip", "203.0.113.7", "public", 60)
assert "203.0.113.7" not in key
assert key.startswith("han:api:rl:ip:")
def test_circuit_breaker_opens_and_half_opens(monkeypatch: pytest.MonkeyPatch) -> None:
clock = [10.0]
monkeypatch.setattr("app.integrations.time.monotonic", lambda: clock[0])
breaker = CircuitBreaker(2, 30)
breaker.failure()
breaker.failure()
assert not breaker.allow()
clock[0] = 41.0
assert breaker.allow()
breaker.success()
assert breaker.allow()