aima_phone_catcher/tests/test_transport.py

124 lines
3.7 KiB
Python
Raw Normal View History

import can
import pytest
from lingkong_motor_service.config import Settings
from lingkong_motor_service.protocol import build_open_loop_frame
from lingkong_motor_service.transport import (
CanTransportError,
DisabledCanTransport,
PythonCanTransport,
)
class StubBus:
def __init__(self) -> None:
self.messages: list[can.Message] = []
self.timeouts: list[float | None] = []
self.shutdown_count = 0
self.received_messages: list[can.Message] = []
def send(self, message: can.Message, timeout: float | None = None) -> None:
self.messages.append(message)
self.timeouts.append(timeout)
def shutdown(self) -> None:
self.shutdown_count += 1
def recv(self, timeout: float | None = None) -> can.Message | None:
del timeout
if not self.received_messages:
return None
return self.received_messages.pop(0)
def test_canalystii_configuration_and_standard_frame(monkeypatch: pytest.MonkeyPatch) -> None:
captured: dict[str, object] = {}
bus = StubBus()
def open_bus(**kwargs: object) -> StubBus:
captured.update(kwargs)
return bus
monkeypatch.setattr(can, "Bus", open_bus)
transport = PythonCanTransport(Settings(hardware_enabled=True, can_channel=1, can_device=2))
try:
transport.send(build_open_loop_frame({1: 400, 2: -400}))
assert captured == {
"interface": "canalystii",
"channel": 1,
"device": 2,
"bitrate": 1_000_000,
"rx_queue_size": 256,
"receive_own_messages": False,
}
assert bus.timeouts == [None]
assert len(bus.messages) == 1
assert bus.messages[0].arbitration_id == 0x280
assert bus.messages[0].is_extended_id is False
assert bytes(bus.messages[0].data) == bytes.fromhex("90 01 70 FE 00 00 00 00")
finally:
transport.shutdown()
def test_disabled_transport_fails_closed() -> None:
with pytest.raises(CanTransportError, match="hardware access is disabled"):
DisabledCanTransport().send(build_open_loop_frame({1: 0}))
def test_canalystii_can_wait_for_the_hardware_tx_queue(
monkeypatch: pytest.MonkeyPatch,
) -> None:
bus = StubBus()
monkeypatch.setattr(can, "Bus", lambda **kwargs: bus)
transport = PythonCanTransport(Settings(hardware_enabled=True))
try:
transport.send(
build_open_loop_frame({}),
tx_queue_timeout_s=0.1,
)
assert bus.timeouts == [0.1]
finally:
transport.shutdown()
def test_shutdown_is_idempotent_and_send_after_shutdown_fails(
monkeypatch: pytest.MonkeyPatch,
) -> None:
bus = StubBus()
monkeypatch.setattr(can, "Bus", lambda **kwargs: bus)
transport = PythonCanTransport(Settings(hardware_enabled=True))
transport.shutdown()
transport.shutdown()
assert transport.is_open is False
assert bus.shutdown_count == 1
with pytest.raises(CanTransportError, match="CAN transport is closed"):
transport.send(build_open_loop_frame({1: 0}))
def test_canalystii_receives_standard_status_frame(monkeypatch: pytest.MonkeyPatch) -> None:
bus = StubBus()
bus.received_messages.append(
can.Message(
arbitration_id=0x141,
is_extended_id=False,
data=bytes.fromhex("9C 4F 64 00 0A 00 34 12"),
)
)
monkeypatch.setattr(can, "Bus", lambda **kwargs: bus)
transport = PythonCanTransport(Settings(hardware_enabled=True))
try:
frame = transport.receive(timeout_s=0.01)
assert frame is not None
assert frame.arbitration_id == 0x141
assert frame.data == bytes.fromhex("9C 4F 64 00 0A 00 34 12")
finally:
transport.shutdown()