headroom/tests/test_provider_copilot_wrap.py
Garm efd2ac1ca4 chore: renormalize line endings to LF
`.gitattributes` declares `*.py text eol=lf` and `*.sh text eol=lf`, but
74 files (73 .py, 1 .sh) are stored in the index with CRLF line endings,
violating that contract. Every macOS/Linux clone reports these files as
"modified" on fresh checkout because git's diff engine sees the stored
bytes don't match the attribute contract, even though the working tree
and index match byte-for-byte.

Running `git add --renormalize .` rewrites each affected blob so the
stored form matches the attribute declaration. No semantic changes —
every affected file's diff is "N insertions, N deletions" with inserts
and deletes being the same lines modulo line endings.

Follow-up commit adds `.git-blame-ignore-revs` so `git blame` / GitHub
blame skip this mechanical commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 15:33:30 +02:00

124 lines
4.7 KiB
Python

from __future__ import annotations
import io
import json
import urllib.error
from unittest.mock import patch
import click
import pytest
from headroom.providers.copilot.wrap import (
build_launch_env,
detect_running_proxy_backend,
model_configured,
provider_key_source,
query_proxy_config,
resolve_provider_type,
validate_configuration,
)
def test_query_proxy_config_handles_success_and_invalid_payload() -> None:
payload = io.BytesIO(json.dumps({"config": {"backend": "anyllm"}}).encode("utf-8"))
payload_missing = io.BytesIO(json.dumps({"status": "ok"}).encode("utf-8"))
with patch("urllib.request.urlopen", return_value=payload):
assert query_proxy_config(8787) == {"backend": "anyllm"}
with patch("urllib.request.urlopen", return_value=payload_missing):
assert query_proxy_config(8787) is None
with patch("urllib.request.urlopen", side_effect=urllib.error.URLError("down")):
assert query_proxy_config(8787) is None
def test_detect_running_proxy_backend_requires_string_backend(monkeypatch) -> None:
monkeypatch.setattr(
"headroom.providers.copilot.wrap.query_proxy_config",
lambda port: {"backend": 123} if port == 8787 else None,
)
assert detect_running_proxy_backend(8787) is None
assert detect_running_proxy_backend(9999) is None
def test_resolve_provider_type_prefers_explicit_and_env() -> None:
assert resolve_provider_type("anthropic", "openai") == "openai"
assert resolve_provider_type(None, "auto", {"HEADROOM_BACKEND": "anthropic"}) == "anthropic"
assert resolve_provider_type(None, "auto", {"HEADROOM_BACKEND": "anyllm"}) == "openai"
def test_validate_configuration_accepts_supported_combinations() -> None:
validate_configuration(provider_type="openai", wire_api="responses", backend=None)
validate_configuration(provider_type="openai", wire_api="completions", backend="anyllm")
def test_validate_configuration_rejects_invalid_combinations() -> None:
with pytest.raises(click.ClickException, match="--wire-api is only valid"):
validate_configuration(provider_type="anthropic", wire_api="responses", backend=None)
with pytest.raises(click.ClickException, match="not supported with translated backends"):
validate_configuration(provider_type="openai", wire_api="responses", backend="anyllm")
def test_provider_key_source_and_build_launch_env_cover_anthropic_and_openai() -> None:
assert provider_key_source("anthropic") == "ANTHROPIC_API_KEY"
assert provider_key_source("openai") == "OPENAI_API_KEY"
anthropic_env, anthropic_lines = build_launch_env(
port=8787,
provider_type="anthropic",
wire_api="responses",
environ={
"ANTHROPIC_API_KEY": "sk-ant-test",
"COPILOT_PROVIDER_WIRE_API": "stale",
},
)
openai_env, openai_lines = build_launch_env(
port=8787,
provider_type="openai",
wire_api=None,
environ={"OPENAI_API_KEY": "sk-proj-test"},
)
assert anthropic_env["COPILOT_PROVIDER_TYPE"] == "anthropic"
assert anthropic_env["COPILOT_PROVIDER_BASE_URL"] == "http://127.0.0.1:8787"
assert anthropic_env["COPILOT_PROVIDER_API_KEY"] == "sk-ant-test"
assert "COPILOT_PROVIDER_WIRE_API" not in anthropic_env
assert anthropic_lines == [
"COPILOT_PROVIDER_TYPE=anthropic",
"COPILOT_PROVIDER_BASE_URL=http://127.0.0.1:8787",
]
assert openai_env["COPILOT_PROVIDER_TYPE"] == "openai"
assert openai_env["COPILOT_PROVIDER_BASE_URL"] == "http://127.0.0.1:8787/v1"
assert openai_env["COPILOT_PROVIDER_WIRE_API"] == "completions"
assert openai_env["COPILOT_PROVIDER_API_KEY"] == "sk-proj-test"
assert openai_lines[-1] == "COPILOT_PROVIDER_WIRE_API=completions"
def test_build_launch_env_keeps_existing_provider_key_and_allows_missing_source_key() -> None:
existing_env, _existing_lines = build_launch_env(
port=8787,
provider_type="openai",
wire_api="responses",
environ={
"COPILOT_PROVIDER_API_KEY": "existing-provider-key",
"OPENAI_API_KEY": "sk-proj-test",
},
)
missing_env, _missing_lines = build_launch_env(
port=8787,
provider_type="openai",
wire_api="responses",
environ={},
)
assert existing_env["COPILOT_PROVIDER_API_KEY"] == "existing-provider-key"
assert "COPILOT_PROVIDER_API_KEY" not in missing_env
def test_model_configured_detects_env_and_cli_variants() -> None:
assert model_configured((), {"COPILOT_MODEL": "gpt-4o"}) is True
assert model_configured(("--model", "gpt-4o"), {}) is True
assert model_configured(("--model=gpt-4o",), {}) is True
assert model_configured(("--other", "value"), {}) is False