Skip to content

test(ingestion): cover URL fallback in get_first_response - #5148

Merged
benhammondmusic merged 2 commits into
SatcherInstitute:mainfrom
snowyukitty:test/url-fallback-coverage
Aug 21, 2026
Merged

benhammondmusic merged 2 commits into
SatcherInstitute:mainfrom
snowyukitty:test/url-fallback-coverage

Conversation

@snowyukitty

Copy link
Copy Markdown
Contributor

Description and Motivation

Follow-up to #5142, at @benhammondmusic's request: port the missing URL-fallback coverage onto the merged #5143 code.

get_first_response promises to retry the next URL when one fails — for an HTTP error, and, with validate_json=True, for a non-JSON body. Neither promise was exercised:

  • MockResponse.raise_for_status() was a no-op, so the requests.HTTPError branch never ran.
  • Every test passed a single-URL list, so the loop never advanced past the first entry.

Tests only; no production change. (get_first_response already catches ValueError rather than a bare Exception, so there was nothing to tighten there.)

  • Give MockResponse an optional status_code (default 200) so raise_for_status() can raise a real requests.HTTPError.
  • testGetFirstResponse_HttpError_FallsBackToNextUrl — 503 on the first URL, valid response on the second.
  • testGetFirstResponse_JsonValidation_FallsBackToNextUrl — HTML body on the first URL, valid JSON on the second, under validate_json=True.

Both assert that the second response is returned and that requests.get was called twice.

Has this been tested? How?

Against main at 1761bfcd:

  • pytest python/tests/ingestion/test_url_file_to_gcs.py — 10 passed (8 pre-existing + 2 new).
  • black --check (line-length 120) and pylint --rcfile=pyproject.toml — both clean.

Mutation-checked so the new cases are load-bearing rather than decorative:

Mutation to get_first_response Result
remove except requests.HTTPError only testGetFirstResponse_HttpError_FallsBackToNextUrl fails
remove except ValueError testGetFirstResponse_JsonValidation_FallsBackToNextUrl fails, alongside the two pre-existing JSON tests

The second row is the point of the new JSON case: the pre-existing tests only prove a single-URL list returns None, not that the loop continues to the next URL.

status_code defaults to 200, so raise_for_status() stays a no-op for all eight pre-existing tests.

Types of Changes

  • Refactor / chore

get_first_response is documented to retry the next URL when one fails: for
an HTTP error, and, with validate_json=True, for a non-JSON body. Neither
path was exercised. MockResponse.raise_for_status was a no-op, so the
requests.HTTPError branch never ran, and every test passed a single-URL
list, so the loop never advanced past the first entry.

Give MockResponse an optional status_code (default 200) so raise_for_status
can raise a real requests.HTTPError, and add two cases that pass two URLs:
a 503 on the first, and a non-JSON body on the first under validate_json.
Both assert that the second response is returned and that requests.get was
called twice.

Tests only; no production change.
@coderabbitai

coderabbitai Bot commented Aug 20, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 302b77d1-c06b-43df-b813-3145aa0ad34a

📥 Commits

Reviewing files that changed from the base of the PR and between 35d27f3 and b6472c4.

📒 Files selected for processing (1)
  • python/tests/ingestion/test_url_file_to_gcs.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The test suite extends MockResponse with HTTP status handling and adds coverage for URL fallback, transient retries, retry exhaustion, and non-retryable JSON decode errors.

Changes

get_first_response retry and fallback tests

Layer / File(s) Summary
Mock response and fallback validation
python/tests/ingestion/test_url_file_to_gcs.py
MockResponse now raises requests.HTTPError for error status codes. Tests verify fallback after repeated 503 responses and invalid JSON.
Retry error classification
python/tests/ingestion/test_url_file_to_gcs.py
Tests verify retries for transient ConnectionError and ReadTimeout failures. They also verify retry exhaustion and no retry for JSONDecodeError.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to b6472

This PR adds focused coverage for URL fallback behavior without changing production code; no actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: benhammondmusic

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the test coverage added for URL fallback in get_first_response.
Description check ✅ Passed The description explains the motivation, changes, testing, and change type; the omitted screenshot section is non-critical for this test-only change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@benhammondmusic
benhammondmusic self-requested a review August 20, 2026 14:03

@benhammondmusic benhammondmusic left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome; thanks!

…erage

# Conflicts:
#	python/tests/ingestion/test_url_file_to_gcs.py
@benhammondmusic
benhammondmusic merged commit ccfbb1a into SatcherInstitute:main Aug 21, 2026
8 checks passed
@snowyukitty

Copy link
Copy Markdown
Contributor Author

Thanks for merging main and updating the assertions — max_retries=3, four calls, and two sleeps all look right.

One optional nit, not worth blocking on. Both fallback tests feed responses through side_effect by call order, so they pin how many requests happen rather than which URLs are asked for. A regression that requested badurl.com a fourth time instead of advancing would still consume the fourth response and still count four calls. Keying the mock by URL and asserting the sequence closes that:

by_url = {"https://badurl.com": error_response, "https://goodurl.com": ok_response}
with patch("requests.get", side_effect=lambda url, **kw: by_url[url]) as mock_get, ...
self.assertEqual(
    [c.args[0] for c in mock_get.call_args_list],
    ["https://badurl.com"] * 3 + ["https://goodurl.com"],
)

Verified locally: with that form, removing the fallback fails exactly the two fallback tests, and removing the same-URL retry also fails the HTTP fallback test and the two added in #5153. No need to hold this PR; I can send it as a follow-up if useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants