"""Direct tests for the ``handle_ta1`` handler (SP27 Task 3). Locks the handler's contract independent of the scheduler lifecycle so a regression in the scheduler wiring doesn't hide a regression in the handler. """ from __future__ import annotations import pytest from cyclone import db from cyclone.handlers.handle_ta1 import handle from cyclone.parsers.exceptions import CycloneParseError ACCEPTED = ( "ISA*00* *00* *ZZ*SENDER *ZZ*RECEIVER " "*260520*1750*^*00501*000000001*0*P*:~" "TA1*000000001*20260520*1750*A*000*20260520~" "IEA*1*000000001~" ) REJECTED = ( "ISA*00* *00* *ZZ*COMEDASSISTPROG*ZZ*TP11525703 " "*260520*1750*^*00501*000000001*0*P*:~" "TA1*320293557*260520*2338*R*006~" "IEA*0*000000001~" ) def test_handle_ta1_persists_row_and_returns_count(): """Accepted TA1 → parse_ta1, claim_count=1, persists ack row with ack_code=A.""" parser_used, claim_count = handle(ACCEPTED, source_file="accepted.ta1") assert parser_used == "parse_ta1" assert claim_count == 1 # Lock the persistence half: a row was added to ta1_acks. with db.SessionLocal()() as session: rows = ( session.query(db.Ta1Ack) .filter_by(source_batch_id="TA1-000000001") .all() ) assert len(rows) == 1 assert rows[0].ack_code == "A" assert rows[0].note_code == "000" assert rows[0].control_number == "000000001" def test_handle_ta1_rejected_persists_with_rejected_ack_code(): """Rejected TA1 (R ack_code, non-zero note_code) → persists row, R ack_code. Note: source_batch_id is derived from the ISA control number (``TA1-``), not the TA1 segment's internal ICN. Both fixtures share ISA13=000000001, so source_batch_id is the same string — but ack_code + note_code differentiate the two rows. """ parser_used, claim_count = handle(REJECTED, source_file="rejected.ta1") assert parser_used == "parse_ta1" assert claim_count == 1 # Lock the rejection half: ack_code="R" + note_code="006" persisted. # (DB is reset per-test, so this fixture owns exactly one row.) with db.SessionLocal()() as session: rows = ( session.query(db.Ta1Ack) .filter_by(source_batch_id="TA1-000000001") .all() ) assert len(rows) == 1 assert rows[0].ack_code == "R" assert rows[0].note_code == "006" def test_handle_ta1_missing_segment_raises(): """No TA1 segment → handler raises ValueError (wraps CycloneParseError).""" text = ( "ISA*00* *00* *ZZ*SENDER *ZZ*RECEIVER " "*260520*1750*^*00501*000000001*0*P*:~" "IEA*0*000000001~" ) with pytest.raises((CycloneParseError, ValueError)): handle(text, source_file="empty.ta1") def test_handle_ta1_does_not_create_batches_row(): """TA1 is an envelope-only ack; no ``batches`` row should be created (only ``ta1_acks``).""" parser_used, claim_count = handle(ACCEPTED, source_file="accepted.ta1") with db.SessionLocal()() as session: # Confirm no batch was created. Source_batch_id starts with # "TA1-" — search the batches table (which uses UUIDs) for any # row that starts with "TA1-". from sqlalchemy import select stmt = select(db.Batch.__table__.c.id).where( db.Batch.__table__.c.id.like("TA1-%") ) rows = session.execute(stmt).all() assert rows == []