Skip to content

MockECN

Part of Offline testing in the Python API reference.

Related guidance: getting-started/mock-setup.

Runnable examples: preflight.py.

from picogrid_ecn_client.testing import MockECN

Run a deterministic MQTT v5 test broker.

class MockECN: ...

Source · testing/mock_ecn.py

Use MockECN with async with to manage its asynchronous lifecycle.

Create a stopped offline mock.

def __init__(
*,
host: str = '127.0.0.1',
mqtt_port: int = 0,
tokens: Mapping[str, Iterable[str]] | None = None,
allow_external_bind: bool = False,
allow_unauthenticated: bool = False,
maximum_packet_size: int = 1024 * 1024,
) -> None
NameTypeDefaultDescription
hoststr‘127.0.0.1’Hostname or IP literal on which to listen; non-loopback values require the development/CI-only allow_external_bind opt-in.
mqtt_portint0Listener port, or 0 to select an available port.
tokensMapping[str, Iterable[str]] | NoneNoneSynthetic token-to-mock-ACL mappings, or built-in test mappings.
allow_external_bindboolFalseWhether this development/CI-only mock may bind a non-loopback address; defaults to false.
allow_unauthenticatedboolFalseWhether this development/CI-only mock accepts credential-free MQTT CONNECT packets; defaults to false.
maximum_packet_sizeint1024 * 1024MQTT packet-size bound in bytes.
ExceptionDescription
ValueErrorIf the endpoint, packet bound, token, or mock ACL label is invalid.

Source · testing/mock_ecn.py

Synchronization events for this mock instance.

events: MockEvents

Source · testing/mock_ecn.py

Mutable deterministic controls for this mock instance.

scenario: MockScenario

Source · testing/mock_ecn.py

Return the read-only validated loopback host the listener is bound to.

host: str

Source · testing/mock_ecn.py

Return the bound MQTT listener port.

mqtt_port: int

Source · testing/mock_ecn.py

Return whether the MQTT listener is running.

is_running: bool

Source · testing/mock_ecn.py

Return the number of currently accepted MQTT client connections.

active_connection_count: int

Source · testing/mock_ecn.py

Return the number of live asynchronous mock broker tasks.

active_task_count: int

Source · testing/mock_ecn.py

Return a defensive snapshot of entities observed by the mock.

entity_state: Mapping[str, Mapping[str, Any]]

Source · testing/mock_ecn.py

Return a defensive snapshot of locations observed by the mock.

location_state: Mapping[str, Mapping[str, Any]]

Source · testing/mock_ecn.py

Start the MQTT listener and wait until it accepts connections.

async def start() -> None
ExceptionDescription
OSErrorIf the configured port is occupied or the operating system otherwise refuses the loopback or explicitly allowed external bind.

Source · testing/mock_ecn.py

Close the listener and all accepted clients idempotently.

async def close() -> None

Source · testing/mock_ecn.py

Build a development/CI-only client configuration for this mock.

def client_config(
integration_name: str,
token: str = FULL_ACCESS_TOKEN,
*,
container_network: str | None = None,
) -> ECNConfig
NameTypeDefaultDescription
integration_namestrIntegration identity for the test client.
tokenstrFULL_ACCESS_TOKENSynthetic token understood only by a loopback mock.
container_networkstr | NoneNoneCaller-supplied reviewed container-network name, required for a non-loopback unauthenticated mock.
TypeDescription
ECNConfigA client configuration pinned to the running mock listener.
ExceptionDescription
RuntimeErrorIf the mock has not been started.
ValueErrorIf an external listener does not allow unauthenticated clients or lacks an explicit container-network attestation.

Source · testing/mock_ecn.py

Configure a deterministic publication-handling delay.

def set_delay(seconds: float, *, operation: str = 'all') -> None
NameTypeDefaultDescription
secondsfloatFinite non-negative delay in seconds; 0 removes it.
operationstr‘all’Mock operation to delay: all or mqtt.publish.
ExceptionDescription
ValueErrorIf the delay or operation is invalid.

Source · testing/mock_ecn.py

Configure upcoming publications to be suppressed.

def drop_next_messages(count: int = 1) -> None
NameTypeDefaultDescription
countint1Non-negative number of upcoming publications to suppress.
ExceptionDescription
ValueErrorIf count is negative.

Source · testing/mock_ecn.py

Configure upcoming publications to carry malformed payloads.

def malform_next_messages(count: int = 1) -> None
NameTypeDefaultDescription
countint1Non-negative number of upcoming publications to malform.
ExceptionDescription
ValueErrorIf count is negative.

Source · testing/mock_ecn.py

Toggle a synthetic mock-only ACL denial.

def set_authorization_failure(operation: str, *, enabled: bool = True) -> None
NameTypeDefaultDescription
operationstrMock-only ACL operation label: entity.read, entity.write, location.read, location.write, task.receive, or task.send.
enabledboolTrueWhether the operation is forced to deny.
ExceptionDescription
ValueErrorIf operation is not a supported mock label.

Source · testing/mock_ecn.py

Close upcoming valid MQTT CONNECT attempts without sending CONNACK.

def drop_next_connections(count: int = 1) -> None
NameTypeDefaultDescription
countint1Number of upcoming connection attempts to drop.
ExceptionDescription
ValueErrorIf count is outside the supported fault bound.

Source · testing/mock_ecn.py

Return a negative CONNACK for upcoming otherwise-valid credentials.

def reject_next_authentications(count: int = 1) -> None
NameTypeDefaultDescription
countint1Number of upcoming authentication attempts to reject.
ExceptionDescription
ValueErrorIf count is outside the supported fault bound.

Source · testing/mock_ecn.py

Return operation-specific authorization failures for upcoming ACKs.

def deny_next_acknowledgements(acknowledgement: str, count: int = 1) -> None
NameTypeDefaultDescription
acknowledgementstrMQTT acknowledgement family to deny: suback, puback, or unsuback.
countint1Number of upcoming acknowledgements to deny.
ExceptionDescription
ValueErrorIf the acknowledgement family or count is unsupported.

Source · testing/mock_ecn.py

Return one raw failure-reason byte in upcoming MQTT acknowledgements.

def return_next_acknowledgement_reason(
acknowledgement: str,
reason_code: int,
count: int = 1,
) -> None
NameTypeDefaultDescription
acknowledgementstrMQTT acknowledgement family to alter: suback, puback, or unsuback.
reason_codeintMQTT v5 failure-reason byte to return.
countint1Number of upcoming acknowledgements to alter.
ExceptionDescription
ValueErrorIf the family, reason code, or count is unsupported.

Source · testing/mock_ecn.py

Send an invalid MQTT v5 property length in upcoming responses.

def malform_next_protocol_responses(response: str, count: int = 1) -> None
NameTypeDefaultDescription
responsestrMQTT response family to malform: connack, suback, puback, or unsuback.
countint1Number of upcoming responses to malform.
ExceptionDescription
ValueErrorIf the response family or count is unsupported.

Source · testing/mock_ecn.py

Disconnect upcoming publications at one explicit QoS boundary.

def disconnect_next_publications(phase: str, count: int = 1) -> None
NameTypeDefaultDescription
phasestrPublication-delivery phase at which to disconnect: qos0_before_completion, before_puback, or after_puback.
countint1Number of upcoming publications to disconnect.
ExceptionDescription
ValueErrorIf the phase or count is unsupported.

Source · testing/mock_ecn.py

Disconnect live clients before the caller begins a publication.

async def disconnect_before_publish() -> None

Source · testing/mock_ecn.py

Reset fault controls and synchronization events in place.

def reset_scenario() -> None

Source · testing/mock_ecn.py

Disconnect all live clients while leaving the listener available.

async def disconnect_clients() -> None

Source · testing/mock_ecn.py

Version 0.2.0 · branch main