test: add unit tests for signing, bypass, and hook
This commit is contained in:
parent
cd790313e1
commit
047094759d
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
36
tests/conftest.py
Normal file
36
tests/conftest.py
Normal file
@ -0,0 +1,36 @@
|
||||
# pyright: reportMissingImports=false, reportUnknownMemberType=false, reportUntypedFunctionDecorator=false, reportUnknownParameterType=false, reportMissingParameterType=false, reportUnknownVariableType=false, reportUnknownArgumentType=false
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def simple_messages():
|
||||
return [{"role": "user", "content": "hello world"}]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def complex_messages():
|
||||
return [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image", "source": {"type": "base64", "data": "abc"}},
|
||||
{"type": "text", "text": "hello world"},
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def basic_api_kwargs(simple_messages):
|
||||
return {
|
||||
"system": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "You are Claude Code, Anthropic's official CLI for Claude.\nStay helpful.",
|
||||
},
|
||||
{"type": "text", "text": "Extra system guidance"},
|
||||
],
|
||||
"messages": [dict(message) for message in simple_messages],
|
||||
"model": "claude-opus-4-6-20260101",
|
||||
}
|
||||
95
tests/test_bypass.py
Normal file
95
tests/test_bypass.py
Normal file
@ -0,0 +1,95 @@
|
||||
# pyright: reportPrivateUsage=false, reportUnknownParameterType=false, reportMissingParameterType=false, reportUnknownArgumentType=false, reportUnknownVariableType=false, reportUnknownMemberType=false, reportArgumentType=false
|
||||
|
||||
import copy
|
||||
|
||||
from anthropic_billing_bypass import (
|
||||
_SYSTEM_IDENTITY,
|
||||
_fix_temperature_for_oauth_adaptive,
|
||||
apply_claude_code_bypass,
|
||||
)
|
||||
|
||||
|
||||
def test_apply_claude_code_bypass_injects_billing_header_and_preserves_identity(
|
||||
basic_api_kwargs,
|
||||
):
|
||||
apply_claude_code_bypass(basic_api_kwargs, "2.1.90")
|
||||
|
||||
system = basic_api_kwargs["system"]
|
||||
assert system[0]["text"].startswith("x-anthropic-billing-header: ")
|
||||
assert system[1]["text"] == _SYSTEM_IDENTITY
|
||||
|
||||
|
||||
def test_apply_claude_code_bypass_relocates_non_identity_system_text_to_first_user_message(
|
||||
basic_api_kwargs,
|
||||
):
|
||||
apply_claude_code_bypass(basic_api_kwargs, "2.1.90")
|
||||
|
||||
user_content = basic_api_kwargs["messages"][0]["content"]
|
||||
assert isinstance(user_content, list)
|
||||
text = user_content[0]["text"]
|
||||
assert "<system-reminder>\nStay helpful.\n</system-reminder>" in text
|
||||
assert "<system-reminder>\nExtra system guidance\n</system-reminder>" in text
|
||||
assert text.endswith("hello world")
|
||||
|
||||
|
||||
def test_apply_claude_code_bypass_is_idempotent(basic_api_kwargs):
|
||||
apply_claude_code_bypass(basic_api_kwargs, "2.1.90")
|
||||
once = copy.deepcopy(basic_api_kwargs)
|
||||
|
||||
apply_claude_code_bypass(basic_api_kwargs, "2.1.90")
|
||||
|
||||
assert len(basic_api_kwargs["system"]) == 2
|
||||
assert basic_api_kwargs["system"][0]["text"].startswith(
|
||||
"x-anthropic-billing-header: "
|
||||
)
|
||||
assert basic_api_kwargs["system"][1]["text"] == _SYSTEM_IDENTITY
|
||||
assert basic_api_kwargs["messages"] == once["messages"]
|
||||
|
||||
|
||||
def test_apply_claude_code_bypass_normalizes_string_system(simple_messages):
|
||||
api_kwargs = {
|
||||
"system": "plain system",
|
||||
"messages": [dict(message) for message in simple_messages],
|
||||
"model": "claude-opus-4-6-20260101",
|
||||
}
|
||||
|
||||
apply_claude_code_bypass(api_kwargs, "2.1.90")
|
||||
|
||||
assert isinstance(api_kwargs["system"], list)
|
||||
assert api_kwargs["system"][1]["text"] == _SYSTEM_IDENTITY
|
||||
assert (
|
||||
"<system-reminder>\nplain system\n</system-reminder>"
|
||||
in api_kwargs["messages"][0]["content"][0]["text"]
|
||||
)
|
||||
|
||||
|
||||
def test_apply_claude_code_bypass_without_messages_is_noop():
|
||||
api_kwargs = {"system": "plain system", "model": "claude-opus-4-6-20260101"}
|
||||
|
||||
apply_claude_code_bypass(api_kwargs, "2.1.90")
|
||||
|
||||
assert api_kwargs == {"system": "plain system", "model": "claude-opus-4-6-20260101"}
|
||||
|
||||
|
||||
def test_fix_temperature_for_oauth_adaptive_removes_non_default_temperature():
|
||||
api_kwargs = {"model": "claude-opus-4-6-20260101", "temperature": 0.2}
|
||||
_fix_temperature_for_oauth_adaptive(api_kwargs, site="test")
|
||||
assert "temperature" not in api_kwargs
|
||||
|
||||
|
||||
def test_fix_temperature_for_oauth_adaptive_keeps_temperature_one():
|
||||
api_kwargs = {"model": "claude-opus-4-6-20260101", "temperature": 1}
|
||||
_fix_temperature_for_oauth_adaptive(api_kwargs, site="test")
|
||||
assert api_kwargs["temperature"] == 1
|
||||
|
||||
|
||||
def test_fix_temperature_for_oauth_adaptive_keeps_temperature_for_other_models():
|
||||
api_kwargs = {"model": "claude-3-7-sonnet", "temperature": 0.2}
|
||||
_fix_temperature_for_oauth_adaptive(api_kwargs, site="test")
|
||||
assert api_kwargs["temperature"] == 0.2
|
||||
|
||||
|
||||
def test_fix_temperature_for_oauth_adaptive_without_temperature_is_noop():
|
||||
api_kwargs = {"model": "claude-opus-4-6-20260101"}
|
||||
_fix_temperature_for_oauth_adaptive(api_kwargs, site="test")
|
||||
assert api_kwargs == {"model": "claude-opus-4-6-20260101"}
|
||||
101
tests/test_hook.py
Normal file
101
tests/test_hook.py
Normal file
@ -0,0 +1,101 @@
|
||||
# pyright: reportMissingImports=false, reportUnknownMemberType=false, reportUntypedFunctionDecorator=false, reportUnknownParameterType=false, reportMissingParameterType=false, reportUnusedParameter=false, reportArgumentType=false, reportCallIssue=false, reportUnknownVariableType=false, reportUnknownArgumentType=false, reportAttributeAccessIssue=false
|
||||
|
||||
import importlib
|
||||
import importlib.machinery
|
||||
import importlib.util
|
||||
import sys
|
||||
import types
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def _clear_bypass_finders():
|
||||
sys.meta_path[:] = [
|
||||
finder
|
||||
for finder in sys.meta_path
|
||||
if finder.__class__.__name__ != "_ClaudeCodeBypassFinder"
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def hook_module(monkeypatch):
|
||||
_clear_bypass_finders()
|
||||
module = importlib.import_module("sitecustomize_hook")
|
||||
module = importlib.reload(module)
|
||||
_clear_bypass_finders()
|
||||
yield module
|
||||
_clear_bypass_finders()
|
||||
|
||||
|
||||
def test_install_hook_registers_finder(hook_module):
|
||||
hook_module._install_hook()
|
||||
|
||||
assert any(
|
||||
finder.__class__.__name__ == "_ClaudeCodeBypassFinder"
|
||||
for finder in sys.meta_path
|
||||
)
|
||||
|
||||
|
||||
def test_finder_only_targets_agent_anthropic_adapter(hook_module, monkeypatch):
|
||||
calls = []
|
||||
|
||||
class Loader:
|
||||
def exec_module(self, module):
|
||||
module.loaded = True
|
||||
|
||||
spec = importlib.machinery.ModuleSpec(hook_module._TARGET_MODULE, Loader())
|
||||
|
||||
def fake_find_spec(fullname):
|
||||
calls.append(fullname)
|
||||
return spec if fullname == hook_module._TARGET_MODULE else None
|
||||
|
||||
monkeypatch.setattr(importlib.util, "find_spec", fake_find_spec)
|
||||
hook_module._install_hook()
|
||||
finder = next(
|
||||
finder
|
||||
for finder in sys.meta_path
|
||||
if finder.__class__.__name__ == "_ClaudeCodeBypassFinder"
|
||||
)
|
||||
|
||||
assert finder.find_spec("some.other.module") is None
|
||||
found_spec = finder.find_spec(hook_module._TARGET_MODULE)
|
||||
|
||||
assert found_spec is spec
|
||||
assert calls == [hook_module._TARGET_MODULE]
|
||||
|
||||
|
||||
def test_finder_sets_patched_flag_and_stops_repatching(hook_module, monkeypatch):
|
||||
applied = []
|
||||
|
||||
class Loader:
|
||||
def exec_module(self, module):
|
||||
module.loaded = True
|
||||
|
||||
spec = importlib.machinery.ModuleSpec(hook_module._TARGET_MODULE, Loader())
|
||||
|
||||
def fake_find_spec(fullname):
|
||||
return spec if fullname == hook_module._TARGET_MODULE else None
|
||||
|
||||
bypass_module = types.SimpleNamespace(
|
||||
apply_patches=lambda module: applied.append(module.__name__)
|
||||
)
|
||||
|
||||
monkeypatch.setattr(importlib.util, "find_spec", fake_find_spec)
|
||||
monkeypatch.setitem(sys.modules, "anthropic_billing_bypass", bypass_module)
|
||||
|
||||
hook_module._install_hook()
|
||||
finder = next(
|
||||
finder
|
||||
for finder in sys.meta_path
|
||||
if finder.__class__.__name__ == "_ClaudeCodeBypassFinder"
|
||||
)
|
||||
|
||||
found_spec = finder.find_spec(hook_module._TARGET_MODULE)
|
||||
assert found_spec is spec
|
||||
|
||||
module = types.ModuleType(hook_module._TARGET_MODULE)
|
||||
found_spec.loader.exec_module(module)
|
||||
|
||||
assert finder._patched is True
|
||||
assert applied == [hook_module._TARGET_MODULE]
|
||||
assert finder.find_spec(hook_module._TARGET_MODULE) is None
|
||||
76
tests/test_signing.py
Normal file
76
tests/test_signing.py
Normal file
@ -0,0 +1,76 @@
|
||||
# pyright: reportPrivateUsage=false, reportUnknownParameterType=false, reportMissingParameterType=false, reportUnknownArgumentType=false, reportUnknownVariableType=false
|
||||
|
||||
import hashlib
|
||||
|
||||
from anthropic_billing_bypass import (
|
||||
_build_billing_header_value,
|
||||
_compute_cch,
|
||||
_compute_version_suffix,
|
||||
_extract_first_user_message_text,
|
||||
)
|
||||
|
||||
|
||||
def test_extract_first_user_message_text_with_string_content(simple_messages):
|
||||
assert _extract_first_user_message_text(simple_messages) == "hello world"
|
||||
|
||||
|
||||
def test_extract_first_user_message_text_with_text_block(complex_messages):
|
||||
assert _extract_first_user_message_text(complex_messages) == "hello world"
|
||||
|
||||
|
||||
def test_extract_first_user_message_text_with_image_block_only_returns_empty_string():
|
||||
messages = [{"role": "user", "content": [{"type": "image", "source": {}}]}]
|
||||
assert _extract_first_user_message_text(messages) == ""
|
||||
|
||||
|
||||
def test_extract_first_user_message_text_with_no_user_message_returns_empty_string():
|
||||
messages = [{"role": "assistant", "content": "hello"}]
|
||||
assert _extract_first_user_message_text(messages) == ""
|
||||
|
||||
|
||||
def test_extract_first_user_message_text_uses_first_user_message_only():
|
||||
messages = [
|
||||
{"role": "user", "content": "first"},
|
||||
{"role": "user", "content": "second"},
|
||||
]
|
||||
assert _extract_first_user_message_text(messages) == "first"
|
||||
|
||||
|
||||
def test_extract_first_user_message_text_with_empty_messages_returns_empty_string():
|
||||
assert _extract_first_user_message_text([]) == ""
|
||||
|
||||
|
||||
def test_compute_cch_known_values():
|
||||
assert _compute_cch("hello world") == "b94d2"
|
||||
assert _compute_cch("") == "e3b0c"
|
||||
|
||||
|
||||
def test_compute_version_suffix_pads_short_text():
|
||||
expected = hashlib.sha256(b"59cf53e54c78e002.1.90").hexdigest()[:3]
|
||||
assert _compute_version_suffix("abcde", "2.1.90") == expected
|
||||
|
||||
|
||||
def test_compute_version_suffix_samples_long_enough_text():
|
||||
text = "abcdefghijklmnopqrstuvwxyz"
|
||||
sampled = f"{text[4]}{text[7]}{text[20]}"
|
||||
expected = hashlib.sha256(
|
||||
f"59cf53e54c78{sampled}2.1.90".encode("utf-8")
|
||||
).hexdigest()[:3]
|
||||
assert _compute_version_suffix(text, "2.1.90") == expected
|
||||
|
||||
|
||||
def test_compute_version_suffix_known_value_for_hello_world():
|
||||
expected = hashlib.sha256(b"59cf53e54c78oo02.1.90").hexdigest()[:3]
|
||||
assert _compute_version_suffix("hello world", "2.1.90") == expected
|
||||
|
||||
|
||||
def test_build_billing_header_value_format(simple_messages):
|
||||
version = "2.1.90"
|
||||
entrypoint = "cli"
|
||||
suffix = _compute_version_suffix("hello world", version)
|
||||
cch = _compute_cch("hello world")
|
||||
|
||||
assert _build_billing_header_value(simple_messages, version, entrypoint) == (
|
||||
f"x-anthropic-billing-header: cc_version={version}.{suffix}; "
|
||||
f"cc_entrypoint={entrypoint}; cch={cch};"
|
||||
)
|
||||
Loading…
x
Reference in New Issue
Block a user