| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- import pytest
- from datetime import date, timedelta
- from room_cal.service_api._homestay import _HomestayClient, HomestayAuthError, _fmt_date
- # ── helpers ────────────────────────────────────────────────────────────────────
- def _client(raw_data: dict) -> _HomestayClient:
- c = _HomestayClient(cookies='x', csrf_token='y', room_id='354616')
- c._calendar_data = raw_data
- return c
- # ── _fmt_date ──────────────────────────────────────────────────────────────────
- def test_fmt_date_single_digit_day():
- assert _fmt_date('2026-07-05') == '5 Jul 2026'
- def test_fmt_date_double_digit_day():
- assert _fmt_date('2026-12-27') == '27 Dec 2026'
- def test_fmt_date_jan():
- assert _fmt_date('2027-01-01') == '1 Jan 2027'
- # ── _build_day_map ─────────────────────────────────────────────────────────────
- _EMPTY = {'unavailabilities': [], 'room_price_overrides': [], 'leisure_bookings': []}
- def test_build_day_map_returns_all_dates_in_range():
- c = _client(_EMPTY)
- result = c._build_day_map(_EMPTY, '2026-08-01', '2026-08-03')
- assert set(result.keys()) == {'2026-08-01', '2026-08-02', '2026-08-03'}
- def test_build_day_map_default_state():
- c = _client(_EMPTY)
- day = c._build_day_map(_EMPTY, '2026-08-01', '2026-08-01')['2026-08-01']
- assert day.available is True
- assert day.booked is False
- assert day.price is None
- assert day.rooms_to_sell is None
- def test_build_day_map_unavailability_closed():
- data = {**_EMPTY, 'unavailabilities': [{'start_date': '2026-08-01', 'end_date': '2026-08-05'}]}
- c = _client(data)
- result = c._build_day_map(data, '2026-07-31', '2026-08-06')
- assert result['2026-07-31'].available is True
- assert result['2026-08-01'].available is False
- assert result['2026-08-01'].booked is False
- assert result['2026-08-05'].available is False
- assert result['2026-08-06'].available is True
- def test_build_day_map_price_cents_to_usd():
- data = {**_EMPTY, 'room_price_overrides': [
- {'date': '2026-08-10', 'nightly_rate': {'amount': 8300, 'currency': 'USD'}},
- ]}
- c = _client(data)
- day = c._build_day_map(data, '2026-08-10', '2026-08-10')['2026-08-10']
- assert day.price == 83
- assert day.available is True
- def test_build_day_map_booking_exclusive_end():
- data = {**_EMPTY, 'leisure_bookings': [{'start_date': '2026-09-01', 'end_date': '2026-09-03', 'id': 99}]}
- c = _client(data)
- result = c._build_day_map(data, '2026-08-31', '2026-09-04')
- assert result['2026-08-31'].booked is False
- assert result['2026-09-01'].booked is True
- assert result['2026-09-01'].available is False
- assert result['2026-09-02'].booked is True
- assert result['2026-09-03'].booked is False # checkout day — exclusive
- assert result['2026-09-04'].booked is False
- def test_build_day_map_booked_overrides_closed():
- data = {
- 'unavailabilities': [{'start_date': '2026-09-01', 'end_date': '2026-09-05'}],
- 'room_price_overrides': [],
- 'leisure_bookings': [{'start_date': '2026-09-02', 'end_date': '2026-09-04', 'id': 1}],
- }
- c = _client(data)
- result = c._build_day_map(data, '2026-09-01', '2026-09-05')
- assert result['2026-09-01'].available is False and result['2026-09-01'].booked is False
- assert result['2026-09-02'].booked is True
- assert result['2026-09-03'].booked is True
- assert result['2026-09-04'].booked is False # exclusive end — falls back to closed
- assert result['2026-09-04'].available is False
- async def test_get_reservations_always_empty():
- data = {**_EMPTY, 'leisure_bookings': [
- {'start_date': '2026-08-01', 'end_date': '2026-08-05', 'id': 1},
- ]}
- c = _client(data)
- assert await c.get_reservations('2026-08-01', '2026-09-01') == []
- # ── live tests (require homestay.env + config.json room_id) ───────────────────
- @pytest.fixture(scope='module')
- def live():
- try:
- return _HomestayClient.from_env()
- except (ValueError, KeyError):
- pytest.skip('homestay credentials not configured')
- async def test_get_calendar_returns_full_range(live):
- start = (date.today() + timedelta(days=1)).isoformat()
- end = (date.today() + timedelta(days=30)).isoformat()
- result = await live.get_calendar(start, end)
- assert len(result) == 30
- for ds, day in result.items():
- assert day.date == ds
- assert isinstance(day.available, bool)
- assert isinstance(day.booked, bool)
- assert day.price is None or isinstance(day.price, int)
- async def test_get_calendar_uses_cache(live):
- start = (date.today() + timedelta(days=1)).isoformat()
- end = (date.today() + timedelta(days=7)).isoformat()
- first = await live.get_calendar(start, end)
- second = await live.get_calendar(start, end)
- assert first == second
- async def test_set_price_roundtrip(live):
- start = date.today() + timedelta(days=1)
- end = start + timedelta(days=30)
- cal = await live.get_calendar(start.isoformat(), end.isoformat())
- target = next(
- (ds for ds, d in sorted(cal.items()) if d.available and not d.booked and d.price is not None),
- None,
- )
- if target is None:
- pytest.skip('no available priced date found in the next 30 days')
- original = cal[target].price
- await live.set_price(target, original - 1)
- assert (await live.get_calendar(target, target))[target].price == original - 1
- await live.set_price(target, original)
- assert (await live.get_calendar(target, target))[target].price == original
- async def test_set_availability_roundtrip(live):
- start = date.today() + timedelta(days=7)
- end = start + timedelta(days=30)
- cal = await live.get_calendar(start.isoformat(), end.isoformat())
- target = next(
- (ds for ds, d in sorted(cal.items()) if d.available and not d.booked),
- None,
- )
- if target is None:
- pytest.skip('no available unbooked date found in the next 30 days')
- await live.set_availability(target, False)
- assert (await live.get_calendar(target, target))[target].available is False
- await live.set_availability(target, True)
- assert (await live.get_calendar(target, target))[target].available is True
|