fix(execution): KIS child cancel identity binding, sanitized logging, PG cancel SQL tests
Co-authored-by: genichin <4282227+genichin@users.noreply.github.com>
This commit is contained in:
co-authored by
genichin
parent
f0ac909958
commit
65df10542b
@@ -1,19 +1,22 @@
|
||||
"""Regression: execution loop exceptions must be logged, not silently swallowed.
|
||||
"""Regression: execution loop exceptions must be logged without leaking secrets.
|
||||
|
||||
dcy-031 / issue #81: exceptions from execution.run_once() were silently ignored
|
||||
via bare `continue`, making it impossible to observe repository or adapter errors.
|
||||
dcy-031 / issue #81 (Fix C):
|
||||
- Exceptions from execution.run_once() were silently ignored via bare `continue`.
|
||||
- Sanitized logging requirement: only type(exc).__name__ is emitted; the
|
||||
exception message, traceback, and exc_info must NOT appear in the log record
|
||||
so adapter exceptions containing credentials/DSN/raw payload are never exposed.
|
||||
- Worker must continue after the error (loop survives).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import threading
|
||||
import types
|
||||
|
||||
import pytest
|
||||
_SENTINEL = "SECRET-DSN-CREDENTIAL-RAWPAYLOAD-DO-NOT-LOG"
|
||||
|
||||
|
||||
def test_execution_loop_logs_exception(caplog):
|
||||
"""When execution.run_once() raises, the error is logged and the loop continues."""
|
||||
def test_execution_loop_logs_exception_without_leaking_secrets(caplog):
|
||||
"""Exception type is logged; secret sentinel in exc message is NOT logged."""
|
||||
import trex_core.runtime.daemon as daemon_mod
|
||||
|
||||
call_count = 0
|
||||
@@ -24,7 +27,8 @@ def test_execution_loop_logs_exception(caplog):
|
||||
nonlocal call_count
|
||||
call_count += 1
|
||||
if call_count == 1:
|
||||
raise RuntimeError("simulated repo error: IndeterminateDatatype")
|
||||
raise RuntimeError(f"dsn=postgresql://user:{_SENTINEL}@host/db")
|
||||
# Stop after second successful tick
|
||||
stop_event.set()
|
||||
|
||||
class _FakePublisher:
|
||||
@@ -34,8 +38,6 @@ def test_execution_loop_logs_exception(caplog):
|
||||
class _FakeConfig:
|
||||
execution_interval_sec = 0.001
|
||||
|
||||
# Build a minimal stub Daemon without invoking its real __init__, so we can
|
||||
# inject only the attributes _execution_loop reads.
|
||||
daemon = object.__new__(daemon_mod.Daemon)
|
||||
daemon.stop = stop_event
|
||||
daemon.config = _FakeConfig()
|
||||
@@ -48,6 +50,21 @@ def test_execution_loop_logs_exception(caplog):
|
||||
t.join(timeout=2.0)
|
||||
|
||||
assert not t.is_alive(), "execution loop did not exit cleanly"
|
||||
assert any(
|
||||
"execution loop error" in r.message for r in caplog.records
|
||||
), f"expected 'execution loop error' log, got: {[r.message for r in caplog.records]}"
|
||||
|
||||
error_records = [r for r in caplog.records if "execution loop error" in r.message]
|
||||
assert error_records, (
|
||||
f"expected 'execution loop error' log record, got: {[r.message for r in caplog.records]}"
|
||||
)
|
||||
|
||||
# Secret sentinel must NOT appear in any log record (message or exc_info output)
|
||||
for rec in caplog.records:
|
||||
assert _SENTINEL not in rec.getMessage(), (
|
||||
f"secret sentinel leaked into log: {rec.getMessage()}"
|
||||
)
|
||||
# exc_info must not be attached
|
||||
assert rec.exc_info is None or rec.exc_info == (None, None, None), (
|
||||
"exc_info must not be set on execution loop error record"
|
||||
)
|
||||
|
||||
# The loop continued: second call_count tick was reached
|
||||
assert call_count >= 2, "loop did not continue after exception"
|
||||
|
||||
Reference in New Issue
Block a user