Skip to content

Commit 6a1ce75

Browse files
test(cloud): deflake httpbin-dependent URL construction tests (#1075)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 5ba44a2 commit 6a1ce75

1 file changed

Lines changed: 35 additions & 16 deletions

File tree

tests/integration_tests/cloud/test_cloud_api_util.py

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77

88
from __future__ import annotations
99

10+
import re
1011
from typing import Literal
12+
from urllib.parse import parse_qs, urlparse
1113

1214
import pytest
15+
import responses
1316
from airbyte._util import api_util, text_util
1417
from airbyte._util.api_util import (
1518
CLOUD_API_ROOT,
@@ -305,22 +308,28 @@ def test_check_connector(
305308
pytest.fail(f"API call failed: {e}")
306309

307310

311+
@responses.activate
308312
def test_404_error_includes_request_url_context() -> None:
309313
"""Test that 404 API errors include the full request URL in context.
310314
311315
This test validates that when an API call fails with a 404, the error
312316
includes the full request URL that was attempted. This helps debug URL
313317
construction issues like those seen with custom API roots.
314318
315-
Uses httpbin.org which returns 404 for /sources endpoint, allowing us
316-
to verify the error context contains the expected URL information.
319+
The HTTP layer is mocked with `responses` so the assertions exercise the
320+
SDK's real URL construction without depending on a live external service.
317321
"""
318-
from urllib.parse import parse_qs, urlparse
319-
320-
api_root = "https://httpbin.org"
322+
api_root = "https://api.airbyte.example"
321323
workspace_id = "00000000-0000-0000-0000-000000000000"
322324
fake_bearer_token = SecretString("fake-token-for-testing")
323325

326+
responses.add(
327+
responses.GET,
328+
re.compile(r"https://api\.airbyte\.example/sources.*"),
329+
json={"message": "Not Found"},
330+
status=404,
331+
)
332+
324333
with pytest.raises(AirbyteError) as exc_info:
325334
api_util.list_sources(
326335
workspace_id=workspace_id,
@@ -348,8 +357,8 @@ def test_404_error_includes_request_url_context() -> None:
348357
request_url = str(error.context["request_url"])
349358
parsed = urlparse(request_url)
350359

351-
assert parsed.netloc == "httpbin.org", (
352-
f"Expected host 'httpbin.org', got '{parsed.netloc}'"
360+
assert parsed.netloc == "api.airbyte.example", (
361+
f"Expected host 'api.airbyte.example', got '{parsed.netloc}'"
353362
)
354363
assert parsed.path.endswith("/sources"), (
355364
f"Expected path ending with '/sources', got '{parsed.path}'"
@@ -363,20 +372,29 @@ def test_404_error_includes_request_url_context() -> None:
363372
)
364373

365374

375+
@responses.activate
366376
def test_url_construction_with_path_prefix() -> None:
367377
"""Test that the SDK correctly preserves path prefixes in the base URL.
368378
369-
This test uses httpbin.org/anything which echoes back the request details,
370-
allowing us to verify the actual URL that was constructed and sent.
371-
372379
This test validates that when using a custom API root with a path prefix
373380
(like https://host/api/public/v1), the SDK correctly appends endpoints
374381
to that path rather than replacing it.
382+
383+
The HTTP layer is mocked with `responses` so we can inspect the URL the
384+
SDK actually sent, verifying path-prefix preservation without depending
385+
on a live external service.
375386
"""
376-
base_url_with_path = "https://httpbin.org/anything/api/public/v1"
387+
base_url_with_path = "https://api.airbyte.example/api/public/v1"
377388
fake_bearer_token = SecretString("fake-token-for-testing")
378389
fake_workspace_id = "00000000-0000-0000-0000-000000000000"
379390

391+
responses.add(
392+
responses.GET,
393+
re.compile(r"https://api\.airbyte\.example/api/public/v1/sources.*"),
394+
json={"data": [], "next": None, "previous": None},
395+
status=200,
396+
)
397+
380398
result = api_util.list_sources(
381399
workspace_id=fake_workspace_id,
382400
api_root=base_url_with_path,
@@ -385,10 +403,11 @@ def test_url_construction_with_path_prefix() -> None:
385403
bearer_token=fake_bearer_token,
386404
)
387405

388-
print(f"\nBase URL with path prefix: {base_url_with_path}")
389-
print(f"Result type: {type(result)}")
390-
print(f"Result: {result}")
406+
assert result == [], f"Expected empty list, but got: {result}"
391407

392-
assert result == [], (
393-
f"Expected empty list from httpbin (no real sources), but got: {result}"
408+
assert len(responses.calls) == 1, "Expected exactly one request to be sent"
409+
sent_url = responses.calls[0].request.url
410+
sent_path = urlparse(sent_url).path
411+
assert sent_path == "/api/public/v1/sources", (
412+
f"Expected path '/api/public/v1/sources', got '{sent_path}'"
394413
)

0 commit comments

Comments
 (0)