0ef5fcb1c5
Security / Dependency audit (pip-audit) (push) Has been cancelled
Security / CodeQL (javascript-typescript) (push) Has been cancelled
Security / CodeQL (python) (push) Has been cancelled
Security / Secret scan (gitleaks) (push) Has been cancelled
rust / test (ubuntu) (push) Has been cancelled
rust / simulator e2e (macos-latest) (push) Has been cancelled
rust / simulator e2e (ubuntu-latest) (push) Has been cancelled
rust / simulator e2e (windows-latest) (push) Has been cancelled
rust / wheels (aarch64-apple-darwin) (push) Has been cancelled
rust / wheels (x86_64-unknown-linux-gnu) (push) Has been cancelled
rust / wheels (x86_64-apple-darwin) (push) Has been cancelled
rust / audit (push) Has been cancelled
rust / parity (nightly, allowed to fail during Phase 0) (push) Has been cancelled
CI / commitlint (push) Has been skipped
Dev Containers / validate (.devcontainer/devcontainer.json, default) (push) Failing after 0s
Dev Containers / validate (.devcontainer/memory-stack/devcontainer.json, memory-stack) (push) Failing after 0s
Dev Containers / validate-worktree (push) Failing after 0s
CI / changes (push) Failing after 4s
Deploy Documentation / validate (push) Has been skipped
Deploy Documentation / deploy (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, claude) (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, codex) (push) Failing after 1s
Install Native E2E / install-native (ubuntu-latest) (push) Failing after 1s
OpenCode Plugin / typecheck + build + test (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, copilot) (push) Failing after 1s
Release Please / release-please (push) Failing after 1s
Wrap E2E / docker-wrap-e2e (push) Failing after 1s
Wrap Native E2E / wrap-native (ubuntu-latest) (push) Failing after 1s
Init E2E / docker-init-e2e (push) Failing after 4s
Merge Conflicts / merge-conflicts (push) Failing after 4s
CI / lint (push) Has been cancelled
CI / build-wheel (push) Has been cancelled
CI / build-wheel-windows (push) Has been cancelled
CI / prefetch-model (push) Has been cancelled
CI / test-dashboard-ui (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test-extras (push) Has been cancelled
CI / test-agno (push) Has been cancelled
CI / build (push) Has been cancelled
CI / workflow-validation (push) Has been cancelled
CI / docker-native-e2e (push) Has been cancelled
CI / windows-native-wrapper (push) Has been cancelled
CI / macos-native-wrapper (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / promote-latest (push) Has been cancelled
Init Native E2E / init-native (macos-latest, claude) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, codex) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, copilot) (push) Has been cancelled
Install Native E2E / install-native (macos-latest) (push) Has been cancelled
Wrap Native E2E / wrap-native (macos-latest) (push) Has been cancelled
242 lines
9.1 KiB
Python
242 lines
9.1 KiB
Python
"""Tests for :class:`headroom.proxy.image_compression_decision.ImageCompressionDecision`.
|
|
|
|
Image compression today is gated at two sites (``openai.py:1203`` +
|
|
``anthropic.py:868``) by inline conjunctions. Both already check
|
|
``_bypass`` (the drift problem CompressionDecision fixed is NOT
|
|
present here), but consolidating into a value type still pays off:
|
|
|
|
* test-lockable contract (no future site can forget bypass)
|
|
* ``apply_to_tags()`` surfaces ``image_skip_reason`` in
|
|
``RequestOutcome.tags`` — dashboards can slice image-skipped
|
|
traffic by cause (same observability surface as
|
|
``passthrough_reason`` and ``memory_skip_reason``)
|
|
* Rust-portable shape mirrors :class:`CompressionDecision` exactly
|
|
|
|
Precedence (highest first):
|
|
1. ``bypass_header`` — user opt-out
|
|
2. ``image_optimize_disabled`` — operator config off
|
|
3. ``no_messages`` — nothing to inspect
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import FrozenInstanceError
|
|
from types import SimpleNamespace
|
|
from typing import Any
|
|
|
|
from headroom.proxy.image_compression_decision import ImageCompressionDecision
|
|
|
|
# ── Helpers ───────────────────────────────────────────────────────────
|
|
|
|
|
|
def _config(*, image_optimize: bool = True) -> Any:
|
|
"""Minimal stand-in for ``HeadroomConfig`` — only the field the
|
|
decision reads."""
|
|
return SimpleNamespace(image_optimize=image_optimize)
|
|
|
|
|
|
def _msgs(n: int = 1) -> list[dict[str, str]]:
|
|
return [{"role": "user", "content": f"hi-{i}"} for i in range(n)]
|
|
|
|
|
|
# ── Value-type contract ───────────────────────────────────────────────
|
|
|
|
|
|
def test_decision_is_frozen() -> None:
|
|
d = ImageCompressionDecision.decide(headers={}, config=_config(), messages=_msgs())
|
|
try:
|
|
d.should_compress = False # type: ignore[misc]
|
|
except FrozenInstanceError:
|
|
pass
|
|
else:
|
|
raise AssertionError("ImageCompressionDecision must be frozen")
|
|
|
|
|
|
def test_decision_is_value_equal() -> None:
|
|
a = ImageCompressionDecision.decide(headers={}, config=_config(), messages=_msgs())
|
|
b = ImageCompressionDecision.decide(headers={}, config=_config(), messages=_msgs())
|
|
assert a == b
|
|
|
|
|
|
# ── Precedence ────────────────────────────────────────────────────────
|
|
|
|
|
|
def test_compresses_when_every_gate_open() -> None:
|
|
d = ImageCompressionDecision.decide(
|
|
headers={}, config=_config(image_optimize=True), messages=_msgs()
|
|
)
|
|
assert d.should_compress is True
|
|
assert d.passthrough_reason is None
|
|
|
|
|
|
def test_bypass_header_wins() -> None:
|
|
"""Bypass is the user's explicit "don't touch my bytes" signal —
|
|
image compression mutates bytes (tile-aligns / re-encodes), so
|
|
bypass must skip it. Mirror of CompressionDecision."""
|
|
d = ImageCompressionDecision.decide(
|
|
headers={"x-headroom-bypass": "true"},
|
|
config=_config(image_optimize=True),
|
|
messages=_msgs(),
|
|
)
|
|
assert d.should_compress is False
|
|
assert d.passthrough_reason == "bypass_header"
|
|
|
|
|
|
def test_passthrough_mode_header_also_triggers_bypass_skip() -> None:
|
|
"""``x-headroom-mode: passthrough`` alt spelling — mirrors
|
|
``_headroom_bypass_enabled`` semantics across all proxy gates."""
|
|
d = ImageCompressionDecision.decide(
|
|
headers={"x-headroom-mode": "passthrough"},
|
|
config=_config(image_optimize=True),
|
|
messages=_msgs(),
|
|
)
|
|
assert d.should_compress is False
|
|
assert d.passthrough_reason == "bypass_header"
|
|
|
|
|
|
def test_image_optimize_disabled_is_skip() -> None:
|
|
"""Operator config — ``config.image_optimize = False``. Distinct
|
|
reason from ``compression_disabled`` (text compression's gate);
|
|
operators can enable text + disable image independently."""
|
|
d = ImageCompressionDecision.decide(
|
|
headers={}, config=_config(image_optimize=False), messages=_msgs()
|
|
)
|
|
assert d.should_compress is False
|
|
assert d.passthrough_reason == "image_optimize_disabled"
|
|
|
|
|
|
def test_no_messages_is_skip() -> None:
|
|
"""Empty or missing messages — nothing to look at. Same shape as
|
|
CompressionDecision's no_messages reason."""
|
|
d = ImageCompressionDecision.decide(headers={}, config=_config(), messages=[])
|
|
assert d.should_compress is False
|
|
assert d.passthrough_reason == "no_messages"
|
|
|
|
|
|
def test_messages_none_is_skip() -> None:
|
|
"""``messages=None`` is treated identically to empty list."""
|
|
d = ImageCompressionDecision.decide(headers={}, config=_config(), messages=None)
|
|
assert d.should_compress is False
|
|
assert d.passthrough_reason == "no_messages"
|
|
|
|
|
|
# ── Precedence ordering ──────────────────────────────────────────────
|
|
|
|
|
|
def test_bypass_beats_image_optimize_disabled() -> None:
|
|
"""User signal beats operator signal — bypass is the more
|
|
informative dashboard slice."""
|
|
d = ImageCompressionDecision.decide(
|
|
headers={"x-headroom-bypass": "true"},
|
|
config=_config(image_optimize=False),
|
|
messages=_msgs(),
|
|
)
|
|
assert d.passthrough_reason == "bypass_header"
|
|
|
|
|
|
def test_bypass_beats_no_messages() -> None:
|
|
"""Bypass+no-messages surfaces bypass — user opted out, the
|
|
empty body is incidental."""
|
|
d = ImageCompressionDecision.decide(
|
|
headers={"x-headroom-bypass": "true"},
|
|
config=_config(),
|
|
messages=[],
|
|
)
|
|
assert d.passthrough_reason == "bypass_header"
|
|
|
|
|
|
def test_image_optimize_disabled_beats_no_messages() -> None:
|
|
"""When config is off AND messages empty, surface the operator
|
|
decision — more meaningful for dashboards."""
|
|
d = ImageCompressionDecision.decide(
|
|
headers={}, config=_config(image_optimize=False), messages=[]
|
|
)
|
|
assert d.passthrough_reason == "image_optimize_disabled"
|
|
|
|
|
|
# ── Observability fields ─────────────────────────────────────────────
|
|
|
|
|
|
def test_observability_booleans_populated_when_compressing() -> None:
|
|
d = ImageCompressionDecision.decide(
|
|
headers={}, config=_config(image_optimize=True), messages=_msgs(2)
|
|
)
|
|
assert d.bypass_header_set is False
|
|
assert d.image_optimize_enabled is True
|
|
assert d.has_messages is True
|
|
|
|
|
|
def test_observability_booleans_populated_when_passthrough() -> None:
|
|
d = ImageCompressionDecision.decide(
|
|
headers={"x-headroom-bypass": "true"},
|
|
config=_config(image_optimize=True),
|
|
messages=_msgs(),
|
|
)
|
|
assert d.bypass_header_set is True
|
|
assert d.image_optimize_enabled is True
|
|
assert d.has_messages is True
|
|
|
|
|
|
# ── apply_to_tags ────────────────────────────────────────────────────
|
|
|
|
|
|
def test_apply_to_tags_stamps_reason_when_passthrough() -> None:
|
|
d = ImageCompressionDecision.decide(
|
|
headers={"x-headroom-bypass": "true"}, config=_config(), messages=_msgs()
|
|
)
|
|
tags: dict[str, str] = {}
|
|
d.apply_to_tags(tags)
|
|
assert tags == {"image_skip_reason": "bypass_header"}
|
|
|
|
|
|
def test_apply_to_tags_is_a_noop_when_compressing() -> None:
|
|
d = ImageCompressionDecision.decide(headers={}, config=_config(), messages=_msgs())
|
|
tags: dict[str, str] = {"client": "codex"}
|
|
d.apply_to_tags(tags)
|
|
assert tags == {"client": "codex"}
|
|
|
|
|
|
def test_apply_to_tags_preserves_pre_existing_entries() -> None:
|
|
"""Image skip reason coexists with other slicing tags (client,
|
|
passthrough_reason, memory_skip_reason) — they all live in the
|
|
same RequestOutcome.tags dict."""
|
|
d = ImageCompressionDecision.decide(
|
|
headers={}, config=_config(image_optimize=False), messages=_msgs()
|
|
)
|
|
tags: dict[str, str] = {
|
|
"client": "claude-code",
|
|
"passthrough_reason": "compression_disabled",
|
|
"memory_skip_reason": "no_user_id",
|
|
}
|
|
d.apply_to_tags(tags)
|
|
assert tags["client"] == "claude-code"
|
|
assert tags["passthrough_reason"] == "compression_disabled"
|
|
assert tags["memory_skip_reason"] == "no_user_id"
|
|
assert tags["image_skip_reason"] == "image_optimize_disabled"
|
|
|
|
|
|
def test_apply_to_tags_for_every_skip_reason() -> None:
|
|
"""Every reason name round-trips cleanly into the tag dict."""
|
|
cases: dict[str, dict[str, Any]] = {
|
|
"bypass_header": {
|
|
"headers": {"x-headroom-bypass": "true"},
|
|
"config": _config(),
|
|
"messages": _msgs(),
|
|
},
|
|
"image_optimize_disabled": {
|
|
"headers": {},
|
|
"config": _config(image_optimize=False),
|
|
"messages": _msgs(),
|
|
},
|
|
"no_messages": {
|
|
"headers": {},
|
|
"config": _config(),
|
|
"messages": [],
|
|
},
|
|
}
|
|
for expected_reason, kwargs in cases.items():
|
|
d = ImageCompressionDecision.decide(**kwargs)
|
|
tags: dict[str, str] = {}
|
|
d.apply_to_tags(tags)
|
|
assert tags.get("image_skip_reason") == expected_reason, expected_reason
|