fix(sp41): trailing newlines + edge-case tests for rebill admin endpoints

This commit is contained in:
Nora
2026-07-07 23:02:52 -06:00
parent a15547fb0e
commit adb8dcb137
2 changed files with 37 additions and 5 deletions
+2 -3
View File
@@ -38,6 +38,7 @@ from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel, ConfigDict, Field, field_validator
from cyclone.auth.deps import matrix_gate
from cyclone.rebill.run import run_rebill
log = logging.getLogger(__name__)
@@ -133,8 +134,6 @@ def post_rebill(req: RebillRequest) -> dict[str, Any]:
envelope with CORS headers. Per-file failures land in the summary
CSV (and the ``counts`` dict) rather than raising here.
"""
from cyclone.rebill.run import run_rebill # local import — keeps --help fast
start_str, end_str = req.window.split("..", 1)
# Validator already proved these parse cleanly.
window_start = date.fromisoformat(start_str)
@@ -212,7 +211,7 @@ def get_rebill_status(
counts: dict[str, int] = {}
with summary_path.open(newline="") as f:
for row in csv.DictReader(f):
disp = (row.get("disposition") or "UNKNOWN").strip() or "UNKNOWN"
disp = (row.get("disposition", "UNKNOWN") or "").strip() or "UNKNOWN"
counts[disp] = counts.get(disp, 0) + 1
recent.append({
"as_of": d.name,
+33
View File
@@ -191,3 +191,36 @@ def test_get_rebill_status_returns_recent_runs(client, tmp_path, monkeypatch):
# Each disposition surfaced exactly once — matches the 2-row CSV.
assert counts.get("REBILLED_B") == 1, counts
assert counts.get("EXCLUDED_TIMELY_FILING") == 1, counts
def test_post_rebill_rejects_malformed_window(client):
"""Pydantic window validator should 422 on bad shapes (no `..`, non-dates, reversed)."""
bad_windows = [
"2026-01-01", # no `..` separator
"foo..bar", # non-ISO dates
"2026-12-01..2026-01-01", # start after end
]
for w in bad_windows:
resp = client.post(
"/api/admin/rebill-from-835",
json={"window": w},
)
assert resp.status_code == 422, (
f"expected 422 for window={w!r}, got {resp.status_code}: {resp.text}"
)
def test_get_rebill_status_returns_empty_when_no_runs(client, tmp_path, monkeypatch):
"""GET /status on an empty rebills dir must return {"recent_runs": []}, not 500.
Monkeypatches REBILLS_DIR to a fresh tmp_path subdir so the test
doesn't depend on (or pollute) any pre-existing dev/rebills/ tree.
"""
from cyclone.api_routers import rebill
monkeypatch.setattr(rebill, "REBILLS_DIR", tmp_path / "rebills_empty")
resp = client.get("/api/admin/rebill-from-835/status")
assert resp.status_code == 200, resp.text
assert resp.json() == {"recent_runs": []}