chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
import inspect
|
||||
import logging
|
||||
|
||||
import e2b_connect as connect
|
||||
from e2b import AsyncSandbox, ConnectionConfig, Sandbox
|
||||
from e2b.api import (
|
||||
ApiClient,
|
||||
make_async_logging_event_hooks,
|
||||
make_logging_event_hooks,
|
||||
)
|
||||
from e2b.connection_config import ApiParams
|
||||
from e2b.volume.connection_config import VolumeConnectionConfig
|
||||
|
||||
|
||||
def test_connection_config_stores_logger():
|
||||
custom = logging.getLogger("test.custom")
|
||||
config = ConnectionConfig(api_key="e2b_" + "0" * 40, logger=custom)
|
||||
assert config.logger is custom
|
||||
|
||||
|
||||
def test_connection_config_logger_defaults_to_none():
|
||||
config = ConnectionConfig(api_key="e2b_" + "0" * 40)
|
||||
assert config.logger is None
|
||||
|
||||
|
||||
def test_logger_is_not_a_public_per_request_api_param():
|
||||
# Matching the JS SDK, `logger` is a construction-time option (Sandbox.create
|
||||
# / connect), not a public per-request ApiParams field that control-plane
|
||||
# methods like kill/list/get_info accept from the caller.
|
||||
assert "logger" not in ApiParams.__annotations__
|
||||
|
||||
|
||||
def test_get_api_params_propagates_stored_logger():
|
||||
# Instance control-plane methods (kill, pause, set_timeout, get_info,
|
||||
# connect) rebuild a throwaway ConnectionConfig from these params, so the
|
||||
# logger the sandbox was created/connected with must survive the round-trip.
|
||||
custom = logging.getLogger("test.propagate")
|
||||
config = ConnectionConfig(api_key="e2b_" + "0" * 40, logger=custom)
|
||||
assert config.get_api_params()["logger"] is custom
|
||||
assert ConnectionConfig(**config.get_api_params()).logger is custom
|
||||
|
||||
no_logger = ConnectionConfig(api_key="e2b_" + "0" * 40)
|
||||
assert no_logger.get_api_params()["logger"] is None
|
||||
|
||||
|
||||
def test_logger_is_accepted_on_create_and_connect():
|
||||
for cls in (Sandbox, AsyncSandbox):
|
||||
assert "logger" in inspect.signature(cls.create).parameters
|
||||
# `logger` is a construction option, so it is accepted by the static
|
||||
# `Sandbox.connect(sandbox_id, ...)` form (which builds a fresh instance)
|
||||
# but not by instance `sandbox.connect()`, where the already-built clients
|
||||
# cannot adopt a new logger.
|
||||
assert "logger" not in inspect.signature(Sandbox.connect).parameters
|
||||
assert "logger" not in inspect.signature(AsyncSandbox.connect).parameters
|
||||
|
||||
|
||||
def test_volume_connection_config_stores_and_round_trips_logger():
|
||||
custom = logging.getLogger("test.volume")
|
||||
config = VolumeConnectionConfig(token="token", logger=custom)
|
||||
assert config.logger is custom
|
||||
assert config.get_api_params()["logger"] is custom
|
||||
|
||||
|
||||
def test_api_client_uses_config_logger():
|
||||
custom = logging.getLogger("test.api-client")
|
||||
config = ConnectionConfig(api_key="e2b_" + "0" * 40, logger=custom)
|
||||
client = ApiClient(config)
|
||||
try:
|
||||
assert client._logger is custom
|
||||
finally:
|
||||
client.get_httpx_client().close()
|
||||
|
||||
|
||||
def test_api_client_without_logger_emits_no_hooks():
|
||||
# With no logger supplied, nothing should be logged (matching the JS SDK,
|
||||
# which only attaches its logging middleware when a logger is given).
|
||||
config = ConnectionConfig(api_key="e2b_" + "0" * 40)
|
||||
client = ApiClient(config)
|
||||
try:
|
||||
assert client._logger is None
|
||||
assert client.get_httpx_client().event_hooks == {
|
||||
"request": [],
|
||||
"response": [],
|
||||
}
|
||||
finally:
|
||||
client.get_httpx_client().close()
|
||||
|
||||
|
||||
def test_rpc_client_without_logger_does_not_log(caplog):
|
||||
client = connect.Client(url="https://example.com", response_type=object)
|
||||
assert client._logger is None
|
||||
# The guarded helpers must be safe no-ops when no logger was supplied.
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
client._log_request()
|
||||
client._log_response(200)
|
||||
client._log_response(500)
|
||||
client._log_stream_message()
|
||||
assert caplog.records == []
|
||||
|
||||
|
||||
def test_rpc_client_uses_provided_logger(caplog):
|
||||
custom = logging.getLogger("test.rpc")
|
||||
client = connect.Client(
|
||||
url="https://example.com", response_type=object, logger=custom
|
||||
)
|
||||
assert client._logger is custom
|
||||
|
||||
with caplog.at_level(logging.DEBUG, logger="test.rpc"):
|
||||
client._log_request()
|
||||
client._log_response(200)
|
||||
client._log_response(500)
|
||||
client._log_stream_message()
|
||||
|
||||
levels = [(r.levelno, r.getMessage()) for r in caplog.records]
|
||||
assert (logging.INFO, "Request: POST https://example.com") in levels
|
||||
assert (logging.INFO, "Response: 200 https://example.com") in levels
|
||||
assert (logging.ERROR, "Response: 500 https://example.com") in levels
|
||||
assert (logging.DEBUG, "Response stream: https://example.com") in levels
|
||||
|
||||
|
||||
def test_logging_event_hooks_without_logger_are_empty():
|
||||
assert make_logging_event_hooks(None) == {}
|
||||
assert make_async_logging_event_hooks(None) == {}
|
||||
|
||||
|
||||
def test_sync_logging_event_hooks_emit_records(caplog):
|
||||
log = logging.getLogger("test.hooks.sync")
|
||||
hooks = make_logging_event_hooks(log)
|
||||
|
||||
class _Req:
|
||||
method = "GET"
|
||||
url = "https://example.com/foo"
|
||||
|
||||
class _Resp:
|
||||
def __init__(self, status_code):
|
||||
self.status_code = status_code
|
||||
|
||||
with caplog.at_level(logging.DEBUG, logger="test.hooks.sync"):
|
||||
hooks["request"][0](_Req())
|
||||
hooks["response"][0](_Resp(200))
|
||||
hooks["response"][0](_Resp(500))
|
||||
|
||||
levels = [(r.levelno, r.getMessage()) for r in caplog.records]
|
||||
assert (logging.INFO, "Request GET https://example.com/foo") in levels
|
||||
assert (logging.INFO, "Response 200") in levels
|
||||
assert (logging.ERROR, "Response 500") in levels
|
||||
|
||||
|
||||
def test_make_async_logging_event_hooks_shape():
|
||||
hooks = make_async_logging_event_hooks(logging.getLogger("test.hooks.async"))
|
||||
assert set(hooks) == {"request", "response"}
|
||||
assert len(hooks["request"]) == 1
|
||||
assert len(hooks["response"]) == 1
|
||||
Reference in New Issue
Block a user