test: cover auth-on-request and close() in OpenCodeClient
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c86de1d31b
commit
b6c0273ee0
@@ -2,6 +2,7 @@
|
||||
|
||||
import json
|
||||
from io import BytesIO
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
import tornado.httpclient
|
||||
@@ -38,7 +39,9 @@ def base_config() -> OpenCodeConfig:
|
||||
)
|
||||
|
||||
|
||||
def _make_client(config: OpenCodeConfig, responses: list[tuple[int, object]]) -> tuple[OpenCodeClient, MockHTTPClient]:
|
||||
def _make_client(
|
||||
config: OpenCodeConfig, responses: list[tuple[int, object]]
|
||||
) -> tuple[OpenCodeClient, MockHTTPClient]:
|
||||
mock = MockHTTPClient()
|
||||
mock.responses = responses
|
||||
return OpenCodeClient(config, http_client=mock), mock
|
||||
@@ -68,22 +71,30 @@ async def test_create_session_posts_title(base_config: OpenCodeConfig) -> None:
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_auth_in_fetch_kwargs_when_password_set(base_config: OpenCodeConfig) -> None:
|
||||
async def test_auth_set_on_request_when_password_present(
|
||||
base_config: OpenCodeConfig,
|
||||
) -> None:
|
||||
"""Bug fix: auth must live on the HTTPRequest, not as fetch kwargs
|
||||
(tornado rejects fetch(request, **kwargs) for request-construction kwargs)."""
|
||||
config = base_config._replace(password="secret")
|
||||
client, mock = _make_client(config, [(200, {"status": "ok"})])
|
||||
await client.health()
|
||||
call = mock.calls[0]
|
||||
assert call["kwargs"].get("auth_username") == "opencode"
|
||||
assert call["kwargs"].get("auth_password") == "secret"
|
||||
# No kwargs forwarded to fetch.
|
||||
assert call["kwargs"] == {}
|
||||
# Auth is on the HTTPRequest.
|
||||
assert call["request"].auth_username == "opencode"
|
||||
assert call["request"].auth_password == "secret"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_auth_not_in_fetch_kwargs_when_password_empty(base_config: OpenCodeConfig) -> None:
|
||||
async def test_auth_absent_when_no_password(base_config: OpenCodeConfig) -> None:
|
||||
client, mock = _make_client(base_config, [(200, {"status": "ok"})])
|
||||
await client.health()
|
||||
call = mock.calls[0]
|
||||
assert "auth_username" not in call["kwargs"]
|
||||
assert "auth_password" not in call["kwargs"]
|
||||
assert call["kwargs"] == {}
|
||||
assert call["request"].auth_username is None
|
||||
assert call["request"].auth_password is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -149,3 +160,24 @@ async def test_non_2xx_response_raises_with_body(base_config: OpenCodeConfig) ->
|
||||
with pytest.raises(OpenCodeError) as exc_info:
|
||||
await client.health()
|
||||
assert "boom" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_close_is_idempotent() -> None:
|
||||
"""close() can be called multiple times safely."""
|
||||
client = OpenCodeClient(OpenCodeConfig(
|
||||
url="http://x", user="u", password="", request_timeout_seconds=10
|
||||
))
|
||||
client.close()
|
||||
client.close() # must not raise
|
||||
assert client._http_client is None
|
||||
|
||||
|
||||
def test_close_does_not_close_injected_client() -> None:
|
||||
"""close() must not call .close() on a client it didn't create."""
|
||||
injected = MagicMock()
|
||||
client = OpenCodeClient(OpenCodeConfig(
|
||||
url="http://x", user="u", password="", request_timeout_seconds=10
|
||||
), http_client=injected)
|
||||
client.close()
|
||||
injected.close.assert_not_called()
|
||||
assert client._http_client is None
|
||||
|
||||
Reference in New Issue
Block a user