"""Unit tests: ``app/core/http_cache.py`` (phase 167, task 03). The three pure helpers behind the catalogue reads' revalidation (LOCKED A4): the weak content-hash tag (shape, stability, the bytes-vs- str equality), the tolerant ``If-None-Match`` evaluator (``None`` / empty / ``*`` / single / comma-list / weak↔strong both directions / whitespace / the prefix-is-not-a-match pin), and the ONE header pair. """ from __future__ import annotations import re from app.core.http_cache import ( REVALIDATE_CACHE_CONTROL, etag_matches, revalidate_headers, weak_etag, ) _TAG_RE = re.compile(r'W/"[0-9a-f]{32}"') def test_weak_etag_shape_is_weak_32_hex() -> None: """``W/""`` — the prefix, the 32-hex-char body, the total 36-char length (the file's truncation convention).""" tag = weak_etag("hello") assert _TAG_RE.fullmatch(tag), tag assert len(tag) == 36 assert tag.startswith('W/"') and tag.endswith('"') def test_weak_etag_is_deterministic_and_content_sensitive() -> None: assert weak_etag("same body") == weak_etag("same body") assert weak_etag("same body") != weak_etag("same body!") assert weak_etag("") != weak_etag(" ") def test_weak_etag_bytes_and_str_forms_agree() -> None: """The hash is over the UTF-8 bytes either way — the endpoint may hash the ``str`` and serve its encoding without diverging.""" text = '{"tree": "héllo — ünïcode"}' assert weak_etag(text) == weak_etag(text.encode("utf-8")) def test_weak_etag_truncation_matches_the_sha256_prefix() -> None: import hashlib body = "exact served bytes" expected = hashlib.sha256(body.encode("utf-8")).hexdigest()[:32] assert weak_etag(body) == f'W/"{expected}"' def test_etag_matches_none_and_empty_never_match() -> None: """No conditional header (or an empty/whitespace-only one) is an unconditional GET → the route must answer 200.""" assert etag_matches(None, 'W/"x"') is False assert etag_matches("", 'W/"x"') is False assert etag_matches(" ", 'W/"x"') is False def test_etag_matches_star() -> None: """RFC 9110 §13.3.3: ``*`` matches anything the server holds.""" assert etag_matches("*", 'W/"x"') is True assert etag_matches(" * ", 'W/"anything"') is True def test_etag_matches_single_candidate() -> None: assert etag_matches('W/"x"', 'W/"x"') is True assert etag_matches('W/"x"', 'W/"y"') is False def test_etag_matches_comma_separated_list() -> None: header = 'W/"a", W/"b", W/"c"' assert etag_matches(header, 'W/"a"') is True assert etag_matches(header, 'W/"c"') is True assert etag_matches(header, 'W/"d"') is False # no space after the comma — a real client sends both shapes assert etag_matches('W/"a",W/"b"', 'W/"b"') is True def test_etag_matches_weak_strong_equivalence_both_directions() -> None: """``W/"x"`` matches ``"x"`` whichever side carries the weakness marker (the stored form must not decide the outcome).""" assert etag_matches('"x"', 'W/"x"') is True # client strong, ours weak assert etag_matches('W/"x"', '"x"') is True # client weak, ours strong def test_etag_matches_is_whitespace_tolerant() -> None: assert etag_matches(' W/"x" ', 'W/"x"') is True assert etag_matches('W/"a" , "x" ', 'W/"x"') is True assert etag_matches('W/ "x"', 'W/"x"') is True def test_etag_matches_prefix_is_not_a_match() -> None: """A tag that merely SHARES a prefix with ours is a mismatch — the comparison is the full 32-hex-char digest, not ``startswith``.""" ours = "abcdef0123456789abcdef0123456789" shorter = ours[:-1] assert etag_matches(f'W/"{shorter}"', f'W/"{ours}"') is False assert etag_matches(f'"{shorter}"', f'W/"{ours}"') is False def test_revalidate_headers_is_the_one_pair() -> None: """The 200 AND the 304 carry exactly this pair (A19's read-only API arm: private + must-revalidate beside the validator).""" assert revalidate_headers('W/"x"') == { "ETag": 'W/"x"', "Cache-Control": "private, must-revalidate", } assert REVALIDATE_CACHE_CONTROL == "private, must-revalidate"