"""SP25: integration tests for ``cyclone recover-ingest`` (parse + DB-write recovery). Fixtures used (all real production EDI from the test fixture corpus): - ``co_medicaid_837p.txt`` — 1-claim 837P fixture (small, fast). - ``co_medicaid_835.txt`` — minimal 835 fixture (real CO Medicaid). These tests do NOT cover the operator's full ingest/ batch — that's Task 6 in the plan and runs against the live DB after these unit tests are green. """ from __future__ import annotations from pathlib import Path import pytest from click.testing import CliRunner from cyclone import db, store from cyclone.cli import main as cli_main from cyclone.db import Batch, Claim, ProcessedInboundFile, Remittance FIX_837P = Path(__file__).parent / "fixtures" / "co_medicaid_837p.txt" FIX_835 = Path(__file__).parent / "fixtures" / "co_medicaid_835.txt" @pytest.fixture def runner(): return CliRunner() # --- helpers -------------------------------------------------------------- def _count_claims() -> int: s = db.SessionLocal()() try: return s.query(Claim).count() finally: s.close() def _count_remittances() -> int: s = db.SessionLocal()() try: return s.query(Remittance).count() finally: s.close() def _count_batches() -> int: s = db.SessionLocal()() try: return s.query(Batch).count() finally: s.close() # --- tests ---------------------------------------------------------------- def test_recover_ingest_837p_persists_claims(runner): """One 837P ingest via the CLI lands a Batch + ≥1 Claim row + a dedup row.""" pre_claims = _count_claims() pre_batches = _count_batches() result = runner.invoke( cli_main, ["recover-ingest", "--file", str(FIX_837P), "--sftp-block-name", "test-recover-837p"], catch_exceptions=False, ) assert result.exit_code == 0, result.stderr or result.stdout out = (result.stdout or "") + (result.stderr or "") assert "ok" in out assert FIX_837P.name in out assert _count_claims() > pre_claims, "expected new Claim rows" assert _count_batches() > pre_batches, "expected new Batch row" # Dedup row created. s = db.SessionLocal()() try: row = s.query(ProcessedInboundFile).filter_by( sftp_block_name="test-recover-837p", name=FIX_837P.name, ).first() finally: s.close() assert row is not None, "expected processed_inbound_files row" assert row.status == "ok" assert row.file_type == "837p" def test_recover_ingest_835_persists_remittance(runner): """One 835 ingest via the CLI lands a Batch + Remittance row + dedup row.""" pre_batches = _count_batches() pre_remits = _count_remittances() result = runner.invoke( cli_main, ["recover-ingest", "--file", str(FIX_835), "--sftp-block-name", "test-recover-835"], catch_exceptions=False, ) assert result.exit_code == 0, result.stderr or result.stdout assert "ok" in (result.stdout or "") + (result.stderr or "") assert _count_batches() > pre_batches assert _count_remittances() > pre_remits s = db.SessionLocal()() try: row = s.query(ProcessedInboundFile).filter_by( sftp_block_name="test-recover-835", name=FIX_835.name, ).first() finally: s.close() assert row is not None assert row.status == "ok" assert row.file_type == "835" assert row.claim_count >= 1 def test_recover_ingest_is_idempotent(runner): """Second invocation with the same (block, file) is a no-op (duplicate).""" # First call — must ingest. r1 = runner.invoke( cli_main, ["recover-ingest", "--file", str(FIX_837P), "--sftp-block-name", "test-recover-idem"], catch_exceptions=False, ) assert r1.exit_code == 0, r1.stderr or r1.stdout pre_claims = _count_claims() pre_batches = _count_batches() # Second call — must skip. r2 = runner.invoke( cli_main, ["recover-ingest", "--file", str(FIX_837P), "--sftp-block-name", "test-recover-idem"], catch_exceptions=False, ) assert r2.exit_code == 0, r2.stderr or r2.stdout assert "skipped" in (r2.stdout or "") + (r2.stderr or "") # No new rows on second call. assert _count_claims() == pre_claims assert _count_batches() == pre_batches def test_recover_ingest_missing_file_returns_failed(runner, tmp_path): """Missing file → Click rejects with usage error (the CLI uses exists=True).""" missing = tmp_path / "does-not-exist.837" pre_claims = _count_claims() result = runner.invoke( cli_main, ["recover-ingest", "--file", str(missing), "--sftp-block-name", "test-recover-missing"], catch_exceptions=False, ) # Click rejects up-front; usage error exits with code 2. assert result.exit_code == 2 out = (result.stdout or "") + (result.stderr or "") assert "does not exist" in out or "Invalid value" in out assert _count_claims() == pre_claims