Files
wehub-resource-sync 5296d0e97c
CI / Ban suppressions and legacy annotations (push) Has been cancelled
CI / pytest (push) Has been cancelled
CI / ruff-check (push) Has been cancelled
CI / ruff-format (push) Has been cancelled
CI / ty (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:44 +08:00

187 lines
5.7 KiB
Python

from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from fastapi.testclient import TestClient
from free_claude_code.api.dependencies import get_settings
from free_claude_code.api.ports import ApiServices
from free_claude_code.application.ports import StopResult
from free_claude_code.config.settings import Settings
from tests.api.support import create_test_app
app = create_test_app()
@pytest.fixture
def client():
return TestClient(app)
@pytest.fixture
def mock_settings():
settings = Settings()
settings.fast_prefix_detection = True
settings.enable_network_probe_mock = True
settings.enable_title_generation_skip = True
return settings
def test_create_message_fast_prefix_detection(client, mock_settings):
app.dependency_overrides[get_settings] = lambda: mock_settings
payload = {
"model": "claude-3-sonnet",
"max_tokens": 100,
"messages": [{"role": "user", "content": "What is the prefix?"}],
}
with (
patch(
"free_claude_code.api.optimization_handlers.is_prefix_detection_request",
return_value=(True, "/ask"),
),
patch(
"free_claude_code.api.optimization_handlers.extract_command_prefix",
return_value="/ask",
),
):
response = client.post("/v1/messages", json=payload)
assert response.status_code == 200
data = response.json()
assert "/ask" in data["content"][0]["text"]
app.dependency_overrides.clear()
def test_create_message_quota_check_mock(client, mock_settings):
app.dependency_overrides[get_settings] = lambda: mock_settings
payload = {
"model": "claude-3-sonnet",
"max_tokens": 100,
"messages": [{"role": "user", "content": "quota check"}],
}
with patch(
"free_claude_code.api.optimization_handlers.is_quota_check_request",
return_value=True,
):
response = client.post("/v1/messages", json=payload)
assert response.status_code == 200
assert "Quota check passed" in response.json()["content"][0]["text"]
app.dependency_overrides.clear()
def test_create_message_title_generation_skip(client, mock_settings):
app.dependency_overrides[get_settings] = lambda: mock_settings
payload = {
"model": "claude-3-sonnet",
"max_tokens": 100,
"messages": [{"role": "user", "content": "generate title"}],
}
with patch(
"free_claude_code.api.optimization_handlers.is_title_generation_request",
return_value=True,
):
response = client.post("/v1/messages", json=payload)
assert response.status_code == 200
assert "Conversation" in response.json()["content"][0]["text"]
app.dependency_overrides.clear()
def test_create_message_empty_messages_returns_400(client):
"""POST /v1/messages with messages: [] returns 400 invalid_request_error."""
payload = {
"model": "claude-3-sonnet",
"max_tokens": 100,
"messages": [],
}
response = client.post("/v1/messages", json=payload)
assert response.status_code == 400
data = response.json()
assert data.get("type") == "error"
assert data.get("error", {}).get("type") == "invalid_request_error"
assert "cannot be empty" in data.get("error", {}).get("message", "")
def test_count_tokens_empty_messages_returns_400(client):
"""POST /v1/messages/count_tokens with messages: [] matches messages validation."""
payload = {"model": "claude-3-sonnet", "messages": []}
response = client.post("/v1/messages/count_tokens", json=payload)
assert response.status_code == 400
data = response.json()
assert data.get("type") == "error"
assert data.get("error", {}).get("type") == "invalid_request_error"
assert "cannot be empty" in data.get("error", {}).get("message", "")
def test_count_tokens_endpoint(client):
payload = {
"model": "claude-3-sonnet",
"messages": [{"role": "user", "content": "hello"}],
}
with patch("free_claude_code.api.routes.get_token_count", return_value=5):
response = client.post("/v1/messages/count_tokens", json=payload)
assert response.status_code == 200
assert response.json()["input_tokens"] == 5
def test_count_tokens_error_returns_500(client):
"""When get_token_count raises, count_tokens returns 500."""
payload = {
"model": "claude-3-sonnet",
"messages": [{"role": "user", "content": "hello"}],
}
with patch(
"free_claude_code.api.routes.get_token_count",
side_effect=RuntimeError("token error"),
):
response = client.post("/v1/messages/count_tokens", json=payload)
assert response.status_code == 500
assert "token error" in response.json()["detail"]
def test_stop_cli_with_messaging_workflow(client):
session_control = MagicMock()
session_control.stop_all = AsyncMock(return_value=StopResult(cancelled_count=3))
services = app.state.services
app.state.services = ApiServices(
requests=services.requests,
admin=services.admin,
tasks=session_control,
)
response = client.post("/stop")
assert response.status_code == 200
assert response.json()["cancelled_count"] == 3
session_control.stop_all.assert_awaited_once()
def test_stop_cli_fallback_to_manager(client):
session_control = MagicMock()
session_control.stop_all = AsyncMock(return_value=StopResult(source="cli_manager"))
services = app.state.services
app.state.services = ApiServices(
requests=services.requests,
admin=services.admin,
tasks=session_control,
)
response = client.post("/stop")
assert response.status_code == 200
assert response.json()["source"] == "cli_manager"
session_control.stop_all.assert_awaited_once()