headroom/tests/test_project_policy.py
JD Davis 1c1e360112
refactor(proxy): isolate project attribution policy (#1957)
## Description

Extracts pure project attribution policy from the runtime project
context holder. Header classification, project path splitting, and
project-prefixed base URL construction now live in a policy module while
`project_context` keeps the ContextVar and ASGI scope adapter
responsibilities.

Closes #

## Type of Change

- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [x] Code refactoring (no functional changes)

## Changes Made

- Added `headroom.proxy.project_policy` for pure project attribution
header/path/base-URL helpers.
- Updated `headroom.proxy.project_context` to re-export the pure helpers
and retain only request context binding and ASGI scope mutation.
- Added direct tests for the extracted project attribution policy
boundary.
- Kept the LiteLLM callback compatibility shim required for repo-wide
type checking on fresh branches.

## Testing

- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check .`)
- [x] Type checking passes (`mypy headroom`)
- [x] New tests added for new functionality
- [ ] Manual testing performed

### Test Output

```text
python -m pytest tests/test_project_policy.py tests/test_proxy_project_savings.py tests/test_litellm_callback.py tests/test_compress_api.py::TestLiteLLMCallback -q
29 passed in 13.70s

python -m ruff check .
All checks passed!

python -m ruff format --check .
1095 files already formatted

python -m mypy headroom --ignore-missing-imports
Success: no issues found in 409 source files

gitleaks protect --staged --no-banner --redact
no leaks found
```

## Real Behavior Proof

- Environment: Windows, Python 3.13.13, local worktree based on
`headroomlabs/main`.
- Exact command / steps: ran focused project policy tests, project
savings tests, LiteLLM callback tests, Ruff lint/format checks, mypy
over `headroom`, and staged gitleaks scan.
- Observed result: all local checks passed; staged secret scan found no
leaks.
- Not tested: full CI matrix and deployment flows; those are covered by
GitHub Actions.

## Review Readiness

- [x] I have performed a self-review
- [x] This PR is ready for human review

## Checklist

- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable

## Screenshots (if applicable)

N/A

## Additional Notes

Documentation and changelog updates are not applicable for this internal
refactor. GitHub reported existing Dependabot alerts on the default
branch during push; this PR does not change dependencies, and the staged
secret scan is clean.
2026-07-10 23:50:27 -05:00

32 lines
1.3 KiB
Python

"""Tests for pure project attribution policy helpers."""
from __future__ import annotations
from headroom.proxy.project_policy import (
classify_project,
split_project_path,
with_project_prefix,
)
def test_classify_project_reads_project_header() -> None:
assert classify_project({"x-headroom-project": " frontend "}) == "frontend"
assert classify_project({"X-Headroom-Project": "api"}) == "api"
assert classify_project({"user-agent": "codex"}) is None
assert classify_project(object()) is None
def test_split_project_path_extracts_sanitized_project_and_path() -> None:
assert split_project_path("/p/frontend/v1/messages") == ("frontend", "/v1/messages")
assert split_project_path("/p/my%20repo/v1") == ("my repo", "/v1")
assert split_project_path("/p/frontend") == ("frontend", "/")
assert split_project_path("/v1/messages") == (None, "/v1/messages")
assert split_project_path("/p/%20%20/v1") == (None, "/p/%20%20/v1")
def test_with_project_prefix_round_trips_with_split_project_path() -> None:
url = with_project_prefix("http://127.0.0.1:8787/v1", "my repo")
assert url == "http://127.0.0.1:8787/p/my%20repo/v1"
assert split_project_path("/p/my%20repo/v1") == ("my repo", "/v1")
assert with_project_prefix("http://127.0.0.1:8787/v1", " ") == ("http://127.0.0.1:8787/v1")