100 lines
3.5 KiB
Python
100 lines
3.5 KiB
Python
"""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-<ISA13>``), 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 == []
|