05/23 Add Pick 5, Millionair Balls, etc
This commit is contained in:
+144
-32
@@ -15,6 +15,9 @@ from core.fetcher import (
|
||||
fetch_megamillions_ny,
|
||||
fetch_megamillions_tx,
|
||||
fetch_powerball_ny,
|
||||
fetch_cash5_va,
|
||||
fetch_millionaireforlife_va,
|
||||
fetch_bankamillion_va,
|
||||
)
|
||||
from db.models import get_draw_count, get_draws, get_game_by_name, get_last_fetch_log
|
||||
|
||||
@@ -216,54 +219,163 @@ def test_mm_tx_no_header_row(tmp_db):
|
||||
assert result["added"] == 1
|
||||
|
||||
|
||||
# ── VA Lottery mock data ──────────────────────────────────────────────────────
|
||||
|
||||
CASH5_VA_TEXT = (
|
||||
"5/22/2026; 15,29,30,34,36\n"
|
||||
"5/21/2026; 1,2,5,38,44\n"
|
||||
)
|
||||
|
||||
MILLLIFE_VA_TEXT = (
|
||||
"Results for Millionaire for Life\n"
|
||||
"5/22/2026; 17,33,36,54,57; Millionaire Ball: 1\n"
|
||||
"5/21/2026; 3,15,16,24,28; Millionaire Ball: 4\n"
|
||||
)
|
||||
|
||||
BANKAMIL_VA_TEXT = (
|
||||
"Results for Bank a Million\n"
|
||||
"5/20/2026; 14,20,21,24,33,35; Bonus Ball: 18\n"
|
||||
"5/16/2026; 6,8,17,20,29,39; Bonus Ball: 38\n"
|
||||
)
|
||||
|
||||
|
||||
# ── Cash 5 VA ─────────────────────────────────────────────────────────────────
|
||||
|
||||
def test_cash5_va_inserts_records(tmp_db):
|
||||
with patch("core.fetcher.requests.get", return_value=_text_resp(CASH5_VA_TEXT)):
|
||||
result = fetch_cash5_va()
|
||||
assert result["status"] == "success"
|
||||
assert result["added"] == 2
|
||||
assert result["skipped"] == 0
|
||||
|
||||
|
||||
def test_cash5_va_skips_duplicates(tmp_db):
|
||||
for _ in range(2):
|
||||
with patch("core.fetcher.requests.get", return_value=_text_resp(CASH5_VA_TEXT)):
|
||||
result = fetch_cash5_va()
|
||||
assert result["added"] == 0
|
||||
assert result["skipped"] == 2
|
||||
|
||||
|
||||
def test_cash5_va_parses_date_and_numbers(tmp_db):
|
||||
with patch("core.fetcher.requests.get", return_value=_text_resp(CASH5_VA_TEXT)):
|
||||
fetch_cash5_va()
|
||||
from db.models import get_game_by_name, get_draws
|
||||
game = get_game_by_name("Cash 5")
|
||||
draws = get_draws(game["id"], order="ASC")
|
||||
assert draws[0]["draw_date"] == "2026-05-21"
|
||||
assert draws[0]["numbers"] == "1,2,5,38,44"
|
||||
assert draws[0]["bonus"] is None
|
||||
assert draws[0]["source"] == "cash5_va"
|
||||
|
||||
|
||||
def test_cash5_va_network_error(tmp_db):
|
||||
with patch("core.fetcher.requests.get", side_effect=req_lib.RequestException("timeout")):
|
||||
result = fetch_cash5_va()
|
||||
assert result["status"] == "error"
|
||||
assert "timeout" in result["message"]
|
||||
|
||||
|
||||
# ── Millionaire for Life VA ───────────────────────────────────────────────────
|
||||
|
||||
def test_milllife_va_inserts_records(tmp_db):
|
||||
with patch("core.fetcher.requests.get", return_value=_text_resp(MILLLIFE_VA_TEXT)):
|
||||
result = fetch_millionaireforlife_va()
|
||||
assert result["status"] == "success"
|
||||
assert result["added"] == 2
|
||||
|
||||
|
||||
def test_milllife_va_skips_header_line(tmp_db):
|
||||
with patch("core.fetcher.requests.get", return_value=_text_resp(MILLLIFE_VA_TEXT)):
|
||||
result = fetch_millionaireforlife_va()
|
||||
assert result["added"] == 2 # header not counted
|
||||
|
||||
|
||||
def test_milllife_va_parses_bonus(tmp_db):
|
||||
with patch("core.fetcher.requests.get", return_value=_text_resp(MILLLIFE_VA_TEXT)):
|
||||
fetch_millionaireforlife_va()
|
||||
from db.models import get_game_by_name, get_draws
|
||||
game = get_game_by_name("Millionaire for Life")
|
||||
draws = get_draws(game["id"], order="DESC")
|
||||
assert draws[0]["bonus"] == "1"
|
||||
assert draws[0]["numbers"] == "17,33,36,54,57"
|
||||
|
||||
|
||||
def test_milllife_va_network_error(tmp_db):
|
||||
with patch("core.fetcher.requests.get", side_effect=req_lib.RequestException("refused")):
|
||||
result = fetch_millionaireforlife_va()
|
||||
assert result["status"] == "error"
|
||||
|
||||
|
||||
# ── Bank a Million VA ─────────────────────────────────────────────────────────
|
||||
|
||||
def test_bankamil_va_inserts_records(tmp_db):
|
||||
with patch("core.fetcher.requests.get", return_value=_text_resp(BANKAMIL_VA_TEXT)):
|
||||
result = fetch_bankamillion_va()
|
||||
assert result["status"] == "success"
|
||||
assert result["added"] == 2
|
||||
|
||||
|
||||
def test_bankamil_va_parses_bonus_ball(tmp_db):
|
||||
with patch("core.fetcher.requests.get", return_value=_text_resp(BANKAMIL_VA_TEXT)):
|
||||
fetch_bankamillion_va()
|
||||
from db.models import get_game_by_name, get_draws
|
||||
game = get_game_by_name("Bank a Million")
|
||||
draws = get_draws(game["id"], order="DESC")
|
||||
assert draws[0]["bonus"] == "18"
|
||||
assert draws[0]["numbers"] == "14,20,21,24,33,35"
|
||||
|
||||
|
||||
def test_bankamil_va_skips_duplicates(tmp_db):
|
||||
for _ in range(2):
|
||||
with patch("core.fetcher.requests.get", return_value=_text_resp(BANKAMIL_VA_TEXT)):
|
||||
result = fetch_bankamillion_va()
|
||||
assert result["added"] == 0
|
||||
assert result["skipped"] == 2
|
||||
|
||||
|
||||
def test_bankamil_va_network_error(tmp_db):
|
||||
with patch("core.fetcher.requests.get", side_effect=req_lib.RequestException("connect")):
|
||||
result = fetch_bankamillion_va()
|
||||
assert result["status"] == "error"
|
||||
|
||||
|
||||
# ── fetch_all ─────────────────────────────────────────────────────────────────
|
||||
|
||||
def test_fetch_all_returns_three_sources(tmp_db):
|
||||
# Both NY APIs stop after 1 call (2 records < NY_API_LIMIT), so 3 calls total
|
||||
with patch("core.fetcher.requests.get", side_effect=[
|
||||
_json_resp(PB_NY_RECORDS),
|
||||
_json_resp(MM_NY_RECORDS),
|
||||
_text_resp(MM_TX_CSV),
|
||||
]):
|
||||
def test_fetch_all_returns_six_sources(tmp_db):
|
||||
with (
|
||||
patch("core.fetcher.fetch_powerball_ny", return_value={"source": "powerball_ny", "added": 2, "skipped": 0, "status": "success", "message": None}),
|
||||
patch("core.fetcher.fetch_megamillions_ny", return_value={"source": "megamillions_ny", "added": 2, "skipped": 0, "status": "success", "message": None}),
|
||||
patch("core.fetcher.fetch_megamillions_tx", return_value={"source": "megamillions_tx", "added": 2, "skipped": 0, "status": "success", "message": None}),
|
||||
patch("core.fetcher.fetch_cash5_va", return_value={"source": "cash5_va", "added": 2, "skipped": 0, "status": "success", "message": None}),
|
||||
patch("core.fetcher.fetch_millionaireforlife_va", return_value={"source": "millionaireforlife_va", "added": 2, "skipped": 0, "status": "success", "message": None}),
|
||||
patch("core.fetcher.fetch_bankamillion_va", return_value={"source": "bankamillion_va", "added": 2, "skipped": 0, "status": "success", "message": None}),
|
||||
):
|
||||
results = fetch_all()
|
||||
|
||||
assert len(results) == 3
|
||||
assert len(results) == 6
|
||||
sources = {r["source"] for r in results}
|
||||
assert sources == {"powerball_ny", "megamillions_ny", "megamillions_tx"}
|
||||
|
||||
|
||||
def test_fetch_all_aggregated_counts(tmp_db):
|
||||
with patch("core.fetcher.requests.get", side_effect=[
|
||||
_json_resp(PB_NY_RECORDS),
|
||||
_json_resp(MM_NY_RECORDS),
|
||||
_text_resp(MM_TX_CSV),
|
||||
]):
|
||||
results = fetch_all()
|
||||
|
||||
by_source = {r["source"]: r for r in results}
|
||||
assert by_source["powerball_ny"]["added"] == 2
|
||||
assert by_source["megamillions_ny"]["added"] == 2
|
||||
assert by_source["megamillions_tx"]["added"] == 2
|
||||
assert sources == {"powerball_ny", "megamillions_ny", "megamillions_tx",
|
||||
"cash5_va", "millionaireforlife_va", "bankamillion_va"}
|
||||
|
||||
|
||||
def test_fetch_all_continues_after_one_error(tmp_db):
|
||||
"""If one source errors, the remaining sources still complete."""
|
||||
error_result = {"source": "powerball_ny", "added": 0, "skipped": 0, "status": "error", "message": "timeout"}
|
||||
ny_result = {"source": "megamillions_ny", "added": 2, "skipped": 0, "status": "success", "message": None}
|
||||
tx_result = {"source": "megamillions_tx", "added": 2, "skipped": 0, "status": "success", "message": None}
|
||||
|
||||
with (
|
||||
patch("core.fetcher.fetch_powerball_ny", return_value=error_result),
|
||||
patch("core.fetcher.fetch_megamillions_ny", return_value=ny_result),
|
||||
patch("core.fetcher.fetch_megamillions_tx", return_value=tx_result),
|
||||
patch("core.fetcher.fetch_powerball_ny", return_value={"source": "powerball_ny", "added": 0, "skipped": 0, "status": "error", "message": "timeout"}),
|
||||
patch("core.fetcher.fetch_megamillions_ny", return_value={"source": "megamillions_ny", "added": 2, "skipped": 0, "status": "success", "message": None}),
|
||||
patch("core.fetcher.fetch_megamillions_tx", return_value={"source": "megamillions_tx", "added": 2, "skipped": 0, "status": "success", "message": None}),
|
||||
patch("core.fetcher.fetch_cash5_va", return_value={"source": "cash5_va", "added": 2, "skipped": 0, "status": "success", "message": None}),
|
||||
patch("core.fetcher.fetch_millionaireforlife_va", return_value={"source": "millionaireforlife_va", "added": 2, "skipped": 0, "status": "success", "message": None}),
|
||||
patch("core.fetcher.fetch_bankamillion_va", return_value={"source": "bankamillion_va", "added": 2, "skipped": 0, "status": "success", "message": None}),
|
||||
):
|
||||
results = fetch_all()
|
||||
|
||||
assert len(results) == 3
|
||||
assert len(results) == 6
|
||||
by_source = {r["source"]: r for r in results}
|
||||
assert by_source["powerball_ny"]["status"] == "error"
|
||||
assert by_source["megamillions_ny"]["status"] == "success"
|
||||
assert by_source["megamillions_tx"]["status"] == "success"
|
||||
assert by_source["cash5_va"]["status"] == "success"
|
||||
|
||||
|
||||
# ── Fetch log ─────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user