Skip to content

Commit a36bf91

Browse files
authored
Merge pull request #23 from saraswatayu/fix/canary-resilience
fix: stop the live canary from failing on Google's empty booking responses
2 parents e84368c + 0a64993 commit a36bf91

5 files changed

Lines changed: 47 additions & 24 deletions

File tree

.github/workflows/ci.yml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ jobs:
1414
matrix:
1515
python-version: ["3.10", "3.13"]
1616
steps:
17-
- uses: actions/checkout@v4
18-
- uses: actions/setup-python@v5
17+
- uses: actions/checkout@v5
18+
- uses: actions/setup-python@v6
1919
with:
2020
python-version: ${{ matrix.python-version }}
2121
- name: Install dependencies
@@ -26,8 +26,8 @@ jobs:
2626
build:
2727
runs-on: ubuntu-latest
2828
steps:
29-
- uses: actions/checkout@v4
30-
- uses: actions/setup-python@v5
29+
- uses: actions/checkout@v5
30+
- uses: actions/setup-python@v6
3131
with:
3232
python-version: "3.13"
3333
- name: Install build tools
@@ -55,8 +55,8 @@ jobs:
5555
id-token: write
5656
contents: write
5757
steps:
58-
- uses: actions/checkout@v4
59-
- uses: actions/setup-python@v5
58+
- uses: actions/checkout@v5
59+
- uses: actions/setup-python@v6
6060
with:
6161
python-version: "3.13"
6262
- name: Install build tools
@@ -71,10 +71,12 @@ jobs:
7171
id: changelog
7272
run: |
7373
VERSION="${GITHUB_REF_NAME#swoop-v}"
74+
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
7475
# Extract the section between this version's header and the next version header
7576
awk "/^## \\[${VERSION}\\]/{found=1; next} /^## \\[/{if(found) exit} found{print}" CHANGELOG.md > release-notes.md
7677
cat release-notes.md
7778
- name: Create GitHub Release
78-
run: gh release create "${{ github.ref_name }}" --notes-file release-notes.md
79+
run: gh release create "${{ github.ref_name }}" --title "v${VERSION}" --notes-file release-notes.md
7980
env:
8081
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
82+
VERSION: ${{ steps.changelog.outputs.version }}

.github/workflows/live-canary.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ jobs:
1010
runs-on: ubuntu-latest
1111
timeout-minutes: 15
1212
steps:
13-
- uses: actions/checkout@v4
14-
- uses: actions/setup-python@v5
13+
- uses: actions/checkout@v5
14+
- uses: actions/setup-python@v6
1515
with:
1616
python-version: "3.13"
1717
- name: Install dependencies
@@ -24,7 +24,7 @@ jobs:
2424
run: python -m pytest tests/test_live_contract.py -v -m live
2525
- name: Upload live canary artifacts
2626
if: always()
27-
uses: actions/upload-artifact@v4
27+
uses: actions/upload-artifact@v5
2828
with:
2929
name: live-canary-artifacts
3030
path: ${{ runner.temp }}/swoop-live-artifacts

.github/workflows/mutation.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ jobs:
77
mutmut:
88
runs-on: ubuntu-latest
99
steps:
10-
- uses: actions/checkout@v4
11-
- uses: actions/setup-python@v5
10+
- uses: actions/checkout@v5
11+
- uses: actions/setup-python@v6
1212
with:
1313
python-version: "3.13"
1414
- name: Install dependencies
@@ -21,7 +21,7 @@ jobs:
2121
run: mutmut results > mutmut-results.txt || true
2222
- name: Upload mutation results
2323
if: always()
24-
uses: actions/upload-artifact@v4
24+
uses: actions/upload-artifact@v5
2525
with:
2626
name: mutmut-results
2727
path: mutmut-results.txt

swoop/rpc.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,11 +621,18 @@ def get_booking_results(
621621
transport=transport,
622622
)
623623

624-
return _parse_booking_rpc_response(
624+
options = _parse_booking_rpc_response(
625625
res.text,
626626
registry_version=registry_version,
627627
required_keys=required_keys,
628628
)
629+
if not options:
630+
logger.warning(
631+
"get_booking_results %s->%s on %s returned 0 options "
632+
"(upstream RPC succeeded; token may be stale or itinerary unbookable)",
633+
origin, destination, date,
634+
)
635+
return options
629636

630637

631638
def get_trip_booking_results(

tests/test_live_contract.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,18 @@ def _record_booking_artifacts(case_id: str, rpc_captures: list[dict[str, str]],
235235
)
236236

237237

238-
def _find_bookable_itinerary(search_result: Any) -> Itinerary:
238+
def _bookable_candidates(search_result: Any, *, limit: int = 5) -> list[Itinerary]:
239+
candidates: list[Itinerary] = []
239240
for option in search_result.results:
240241
for leg in option.legs:
241242
itinerary = leg.itinerary
242243
if itinerary is None:
243244
continue
244245
if itinerary.booking_token and rpc._build_selected_legs(itinerary):
245-
return itinerary
246-
raise AssertionError("Expected at least one itinerary with booking token and selected legs")
246+
candidates.append(itinerary)
247+
if len(candidates) >= limit:
248+
return candidates
249+
return candidates
247250

248251

249252
class TestShoppingContract:
@@ -317,16 +320,27 @@ def test_booking_results_parseable_and_artifacted(self, monkeypatch: pytest.Monk
317320
)
318321
assert search_result.results, "Expected at least one itinerary before live booking lookup"
319322

320-
itinerary = _find_bookable_itinerary(search_result)
323+
candidates = _bookable_candidates(search_result)
324+
assert candidates, "Expected at least one itinerary with booking token and selected legs"
325+
321326
rpc_captures = _capture_rpc_texts(monkeypatch)
322-
options = rpc.get_booking_results(
323-
itinerary,
324-
registry_version=date.today().isoformat(),
325-
transport=TransportConfig(timeout=30, retries=1),
326-
)
327+
options: list[Any] = []
328+
itinerary: Itinerary | None = None
329+
for candidate in candidates:
330+
options = rpc.get_booking_results(
331+
candidate,
332+
registry_version=date.today().isoformat(),
333+
transport=TransportConfig(timeout=30, retries=1),
334+
)
335+
if options:
336+
itinerary = candidate
337+
break
327338

328339
assert rpc_captures, "Expected a live booking RPC capture"
329-
assert options, "Expected at least one booking option from live booking lookup"
340+
assert options and itinerary is not None, (
341+
f"Expected at least one booking option after trying {len(candidates)} "
342+
"itineraries (upstream returned empty for every candidate)"
343+
)
330344

331345
for option in options[:5]:
332346
assert option.price > 0

0 commit comments

Comments
 (0)