Skip to content

Commit 3a3bfb1

Browse files
Expand sentinel URL fallback normalization and wrapper diagnostics coverage
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent e11d18c commit 3a3bfb1

3 files changed

Lines changed: 102 additions & 1 deletion

File tree

hyperbrowser/transport/error_utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
_MAX_ERROR_MESSAGE_LENGTH = 2000
99
_MAX_REQUEST_URL_DISPLAY_LENGTH = 1000
1010
_MAX_REQUEST_METHOD_LENGTH = 50
11+
_INVALID_URL_SENTINELS = {"none", "null", "undefined", "nan"}
1112

1213

1314
def _normalize_request_method(method: Any) -> str:
@@ -35,7 +36,7 @@ def _normalize_request_url(url: Any) -> str:
3536
if not normalized_url:
3637
return "unknown URL"
3738
lowered_url = normalized_url.lower()
38-
if lowered_url in {"none", "null"} or normalized_url.isdigit():
39+
if lowered_url in _INVALID_URL_SENTINELS or normalized_url.isdigit():
3940
return "unknown URL"
4041
if any(character.isspace() for character in normalized_url):
4142
return "unknown URL"

tests/test_transport_error_utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import httpx
2+
import pytest
23

34
from hyperbrowser.transport.error_utils import (
45
extract_error_message,
@@ -255,6 +256,19 @@ def test_format_request_failure_message_normalizes_numeric_fallback_url_values()
255256
assert message == "Request GET unknown URL failed"
256257

257258

259+
@pytest.mark.parametrize("sentinel_url", ["none", "null", "undefined", "nan"])
260+
def test_format_request_failure_message_normalizes_sentinel_fallback_url_values(
261+
sentinel_url: str,
262+
):
263+
message = format_request_failure_message(
264+
httpx.RequestError("network down"),
265+
fallback_method="GET",
266+
fallback_url=sentinel_url,
267+
)
268+
269+
assert message == "Request GET unknown URL failed"
270+
271+
258272
def test_format_request_failure_message_supports_url_like_fallback_values():
259273
message = format_request_failure_message(
260274
httpx.RequestError("network down"),
@@ -283,6 +297,18 @@ def test_format_generic_request_failure_message_normalizes_numeric_url_values():
283297
assert message == "Request GET unknown URL failed"
284298

285299

300+
@pytest.mark.parametrize("sentinel_url", ["none", "null", "undefined", "nan"])
301+
def test_format_generic_request_failure_message_normalizes_sentinel_url_values(
302+
sentinel_url: str,
303+
):
304+
message = format_generic_request_failure_message(
305+
method="GET",
306+
url=sentinel_url,
307+
)
308+
309+
assert message == "Request GET unknown URL failed"
310+
311+
286312
def test_format_generic_request_failure_message_supports_url_like_values():
287313
message = format_generic_request_failure_message(
288314
method="GET",

tests/test_transport_response_handling.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,22 @@ def failing_get(*args, **kwargs):
394394
transport.close()
395395

396396

397+
def test_sync_transport_wraps_unexpected_errors_with_sentinel_url_fallback():
398+
transport = SyncTransport(api_key="test-key")
399+
original_get = transport.client.get
400+
401+
def failing_get(*args, **kwargs):
402+
raise RuntimeError("boom")
403+
404+
transport.client.get = failing_get # type: ignore[assignment]
405+
try:
406+
with pytest.raises(HyperbrowserError, match="Request GET unknown URL failed"):
407+
transport.get("null")
408+
finally:
409+
transport.client.get = original_get # type: ignore[assignment]
410+
transport.close()
411+
412+
397413
def test_async_transport_put_wraps_unexpected_errors_with_url_context():
398414
async def run() -> None:
399415
transport = AsyncTransport(api_key="test-key")
@@ -458,6 +474,27 @@ async def failing_put(*args, **kwargs):
458474
asyncio.run(run())
459475

460476

477+
def test_async_transport_wraps_unexpected_errors_with_sentinel_url_fallback():
478+
async def run() -> None:
479+
transport = AsyncTransport(api_key="test-key")
480+
original_put = transport.client.put
481+
482+
async def failing_put(*args, **kwargs):
483+
raise RuntimeError("boom")
484+
485+
transport.client.put = failing_put # type: ignore[assignment]
486+
try:
487+
with pytest.raises(
488+
HyperbrowserError, match="Request PUT unknown URL failed"
489+
):
490+
await transport.put("none")
491+
finally:
492+
transport.client.put = original_put # type: ignore[assignment]
493+
await transport.close()
494+
495+
asyncio.run(run())
496+
497+
461498
def test_sync_transport_request_error_without_request_uses_fallback_url():
462499
transport = SyncTransport(api_key="test-key")
463500
original_get = transport.client.get
@@ -526,6 +563,22 @@ def failing_get(*args, **kwargs):
526563
transport.close()
527564

528565

566+
def test_sync_transport_request_error_without_request_uses_unknown_url_for_sentinel_input():
567+
transport = SyncTransport(api_key="test-key")
568+
original_get = transport.client.get
569+
570+
def failing_get(*args, **kwargs):
571+
raise httpx.RequestError("network down")
572+
573+
transport.client.get = failing_get # type: ignore[assignment]
574+
try:
575+
with pytest.raises(HyperbrowserError, match="Request GET unknown URL failed"):
576+
transport.get("undefined")
577+
finally:
578+
transport.client.get = original_get # type: ignore[assignment]
579+
transport.close()
580+
581+
529582
def test_async_transport_request_error_without_request_uses_fallback_url():
530583
async def run() -> None:
531584
transport = AsyncTransport(api_key="test-key")
@@ -610,3 +663,24 @@ async def failing_delete(*args, **kwargs):
610663
await transport.close()
611664

612665
asyncio.run(run())
666+
667+
668+
def test_async_transport_request_error_without_request_uses_unknown_url_for_sentinel_input():
669+
async def run() -> None:
670+
transport = AsyncTransport(api_key="test-key")
671+
original_delete = transport.client.delete
672+
673+
async def failing_delete(*args, **kwargs):
674+
raise httpx.RequestError("network down")
675+
676+
transport.client.delete = failing_delete # type: ignore[assignment]
677+
try:
678+
with pytest.raises(
679+
HyperbrowserError, match="Request DELETE unknown URL failed"
680+
):
681+
await transport.delete("nan")
682+
finally:
683+
transport.client.delete = original_delete # type: ignore[assignment]
684+
await transport.close()
685+
686+
asyncio.run(run())

0 commit comments

Comments
 (0)