fix(sp37-followup): SubmitOutcome.UNEXPECTED_ERROR for non-typed failures
Followup #3 from the SP37 final-state tracker. The router's per-file try/except previously coerced every unexpected exception to SubmitOutcome.SFTP_FAILED — misleading because a RuntimeError from cycl_store.add has nothing to do with SFTP. Changes: * submission/result.py — add UNEXPECTED_ERROR = 'unexpected_error' enum value. Docstring distinguishes it from the typed SFTP_FAILED. * api_routers/submission.py — exception handler now returns UNEXPECTED_ERROR (was SFTP_FAILED). * test_api_submit_batch.py::test_submit_batch_unexpected_exception_recorded_in_results — updated assertion (was sftp_failed, now unexpected_error). * test_unexpected_error_outcome.py (new, 4 tests): - enum value exists - distinct from typed failure values - API surfaces 'unexpected_error' for uncaught exceptions - typed SFTP_FAILED path still surfaces 'sftp_failed' (regression lock) Tests: 40/40 pass in 1.41s (full SP37 chain + new file). Live curl: POST /api/submit-batch in stub mode → HTTP 409 (unchanged behavior, no regression on the config-level guards).
This commit is contained in:
@@ -213,11 +213,10 @@ def test_submit_batch_unexpected_exception_recorded_in_results(
|
||||
"""If submit_file raises, the file lands in results[] as a failed row.
|
||||
|
||||
The router catches the exception, builds a SubmitResult with
|
||||
``outcome=SubmitOutcome.SFTP_FAILED`` (per Task 6's instruction
|
||||
that "any enum value works as a marker; choose whichever is least
|
||||
misleading"), and counts it as ``failed``. The full error string
|
||||
(including exception class name) is in ``error`` so the operator
|
||||
can tell it was a real exception, not a typed failure path.
|
||||
``outcome=SubmitOutcome.UNEXPECTED_ERROR`` (followup #3 — distinct
|
||||
from the typed SFTP_FAILED path so operators can tell "real bug"
|
||||
from "SFTP server down"), and counts it as ``failed``. The full
|
||||
error string (including exception class name) is in ``error``.
|
||||
"""
|
||||
_stage_batch(tmp_path, 1)
|
||||
|
||||
@@ -235,10 +234,10 @@ def test_submit_batch_unexpected_exception_recorded_in_results(
|
||||
assert resp.status_code == 200, resp.text
|
||||
body = resp.json()
|
||||
assert body["failed"] == 1
|
||||
# The marker is the SFTP_FAILED enum value (per Task 6 design
|
||||
# choice). The full exception class+message is in ``error`` so the
|
||||
# operator can distinguish a real exception from a typed failure.
|
||||
assert body["results"][0]["outcome"] == "sftp_failed"
|
||||
# Followup #3: marker is UNEXPECTED_ERROR, NOT SFTP_FAILED — the
|
||||
# exception class+message in ``error`` tells the operator this
|
||||
# was a real exception (not a typed failure).
|
||||
assert body["results"][0]["outcome"] == SubmitOutcome.UNEXPECTED_ERROR.value
|
||||
assert "kaboom" in body["results"][0]["error"]
|
||||
assert "RuntimeError" in body["results"][0]["error"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user