fix(k1): record redacted acceptance failures
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
from collections.abc import Collection, Sequence
|
||||
|
||||
import pytest
|
||||
@@ -11,6 +12,7 @@ from k1link.device_plugins.xgrids_k1.protocol.application_acceptance import (
|
||||
PhysicalAcceptancePermit,
|
||||
)
|
||||
from k1link.device_plugins.xgrids_k1.protocol.application_bootstrap import (
|
||||
DEVICE_CONFIG_RESPONSE_TOPIC,
|
||||
ApplicationControlAuthority,
|
||||
ShadowApplicationBootstrapOrchestrator,
|
||||
)
|
||||
@@ -186,10 +188,71 @@ def test_start_acceptance_requires_full_bootstrap_and_consumes_one_short_permit(
|
||||
assert permit.snapshot()["consumed"] is True
|
||||
assert executor.snapshot()["bootstrap_complete"] is True
|
||||
assert executor.snapshot()["command_complete"] is True
|
||||
response_evidence = executor.snapshot()["response_evidence"]
|
||||
assert isinstance(response_evidence, tuple)
|
||||
assert len(response_evidence) == 10
|
||||
assert response_evidence[0]["operation_key"] == "bootstrap:1:DeviceInfoRequest"
|
||||
assert response_evidence[-1]["operation_key"] == "modeling:start"
|
||||
assert all("payload" not in item for item in response_evidence)
|
||||
assert APPLICATION_KEY not in str(executor.snapshot())
|
||||
assert VENDOR_DEVICE_ID not in str(executor.snapshot())
|
||||
with pytest.raises(ApplicationAcceptanceError, match="already attempted"):
|
||||
executor.execute_modeling(command)
|
||||
|
||||
|
||||
def test_bootstrap_correlation_failure_records_only_redacted_response_evidence() -> None:
|
||||
class CorruptDeviceConfigTransport(SyntheticAcceptanceTransport):
|
||||
def exchange_batch_once(
|
||||
self,
|
||||
envelopes: Sequence[OneShotPublishEnvelope],
|
||||
*,
|
||||
required_response_topics: Collection[str],
|
||||
) -> dict[str, bytes]:
|
||||
responses = super().exchange_batch_once(
|
||||
envelopes,
|
||||
required_response_topics=required_response_topics,
|
||||
)
|
||||
if DEVICE_CONFIG_RESPONSE_TOPIC in responses:
|
||||
responses[DEVICE_CONFIG_RESPONSE_TOPIC] = _generic_response(
|
||||
f"{VENDOR_DEVICE_ID}:wrong-session"
|
||||
)
|
||||
return responses
|
||||
|
||||
executor = PhysicalAcceptanceDialogueExecutor(
|
||||
CorruptDeviceConfigTransport(),
|
||||
PhysicalAcceptancePermit(_checklist(ModelingAction.START)),
|
||||
)
|
||||
orchestrator = ShadowApplicationBootstrapOrchestrator(
|
||||
ApplicationControlAuthority(openapi_key=APPLICATION_KEY),
|
||||
epoch_seconds=1_752_680_000,
|
||||
timezone_name="Europe/Moscow",
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
ApplicationAcceptanceError,
|
||||
match=r"ordinal 4 \(DeviceConfigRequest\).*session correlation",
|
||||
):
|
||||
executor.run_bootstrap(orchestrator)
|
||||
|
||||
snapshot = executor.snapshot()
|
||||
failure = snapshot["correlation_failure"]
|
||||
assert failure == {
|
||||
"phase": "bootstrap",
|
||||
"operation_key": "bootstrap:4:DeviceConfigRequest",
|
||||
"response_topic": DEVICE_CONFIG_RESPONSE_TOPIC,
|
||||
"reason": "application response session correlation failed",
|
||||
}
|
||||
evidence = snapshot["response_evidence"]
|
||||
assert isinstance(evidence, tuple)
|
||||
assert evidence[-1]["payload_sha256"] == hashlib.sha256(
|
||||
_generic_response(f"{VENDOR_DEVICE_ID}:wrong-session")
|
||||
).hexdigest()
|
||||
assert evidence[-1]["payload_bytes"] > 0
|
||||
assert all("payload" not in item for item in evidence)
|
||||
assert APPLICATION_KEY not in str(snapshot)
|
||||
assert VENDOR_DEVICE_ID not in str(snapshot)
|
||||
|
||||
|
||||
def test_start_cannot_skip_bootstrap_and_stop_uses_a_separate_action_permit() -> None:
|
||||
transport = SyntheticAcceptanceTransport()
|
||||
start = PhysicalAcceptanceDialogueExecutor(
|
||||
|
||||
Reference in New Issue
Block a user