Unify K1 discovery ownership and verification across enrollment paths
This commit is contained in:
@@ -198,6 +198,33 @@ def test_failure_locations_respects_suppression_and_bounds_cyclic_chains():
|
||||
assert failure_locations(first) == "RuntimeError[]"
|
||||
|
||||
|
||||
def test_native_failure_facts_keep_stage_and_write_boundary_without_messages():
|
||||
from bleak.exc import BleakDBusError
|
||||
|
||||
from k1link.device_plugins.xgrids_k1.node_bridge import failure_transport_facts
|
||||
|
||||
secret = secrets.token_hex(20)
|
||||
native = BleakDBusError("org.bluez.Error.InProgress", [secret])
|
||||
native.operation_stage = "resolution"
|
||||
native.device_write_attempted = False
|
||||
native.device_write_confirmed = False
|
||||
wrapper = RuntimeError(secret)
|
||||
wrapper.__cause__ = native
|
||||
facts = failure_transport_facts(wrapper)
|
||||
assert facts == (
|
||||
"stage=resolution bluez=org.bluez.Error.InProgress "
|
||||
"device_write_attempted=False device_write_confirmed=False"
|
||||
)
|
||||
assert secret not in facts
|
||||
native = BleakDBusError(secret, [secret])
|
||||
native.operation_stage = secret
|
||||
wrapper.__cause__ = native
|
||||
assert secret not in failure_transport_facts(wrapper)
|
||||
wrapper.__suppress_context__ = True
|
||||
wrapper.__cause__ = None
|
||||
assert failure_transport_facts(wrapper) == "unavailable"
|
||||
|
||||
|
||||
def test_node_scan_reaches_service_through_real_facade_with_runtime_fence():
|
||||
"""Exercise the actual admission boundary, replacing only the BLE service."""
|
||||
from k1link.device_plugins.xgrids_k1.facade import SnapshotRuntimeConflict
|
||||
@@ -640,6 +667,9 @@ def test_recheck_uses_only_exact_admitted_durable_bridge_target():
|
||||
assert result["source"] == "durable-configured-state"
|
||||
assert result["device_id"] == current["selected_device_id"]
|
||||
assert result["expected_mode_revision"] == current["desired_connection_mode_revision"]
|
||||
assert "source" not in verification_parameters(
|
||||
current, "synthetic-operation", requested_device_id="other-device",
|
||||
)
|
||||
for patch in [{"allowed": False}, {"requires_live_gatt_validation": True},
|
||||
{"required_connection_mode": "quick-connect"},
|
||||
{"required_transport_ref": "other"}]:
|
||||
@@ -648,3 +678,30 @@ def test_recheck_uses_only_exact_admitted_durable_bridge_target():
|
||||
decision.update(allowed=True, requires_live_gatt_validation=False,
|
||||
required_transport_ref=current["selected_device_id"],
|
||||
required_connection_mode="bridge")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("requires_gatt", [False, True])
|
||||
def test_enrollment_verify_and_detail_share_durable_target_admission(requires_gatt):
|
||||
async def run():
|
||||
device = bridge()
|
||||
current = device.facade.current
|
||||
current["connection_policy"] = {"actions": {"observe-configured-device-network": {
|
||||
"allowed": True, "requires_live_gatt_validation": requires_gatt,
|
||||
"required_connection_mode": "bridge",
|
||||
"required_transport_ref": current["selected_device_id"],
|
||||
}}}
|
||||
command = {
|
||||
"operation_id": "op_" + "d" * 32, "action": "verify", "runtime_id": "runtime-one",
|
||||
"deadline_at": (datetime.now(UTC) + timedelta(seconds=60)).isoformat(),
|
||||
"parameters": {"device_id": current["selected_device_id"],
|
||||
"discovery_generation": 1, "mode_revision": 0},
|
||||
}
|
||||
await device.execute(command)
|
||||
actions = [(a, p) for a, p in device.facade.actions if a != "state.read"]
|
||||
assert len(actions) == 1 and actions[0][0] == "connection.verify"
|
||||
payload = actions[0][1]
|
||||
assert (payload.get("source") == "durable-configured-state") is not requires_gatt
|
||||
assert payload["device_id"] == current["selected_device_id"]
|
||||
assert payload["expected_discovery_generation"] == 1
|
||||
assert "password" not in payload
|
||||
asyncio.run(run())
|
||||
|
||||
Reference in New Issue
Block a user