Files
MeshCore/test/test_ethernet_kiss.py
T

81 lines
3.1 KiB
Python

"""Run the actual bounded Ethernet KISS codec and TCP service with fake sockets."""
from pathlib import Path
import os
import re
import subprocess
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[1]
FIXTURE = ROOT / "test" / "fixtures" / "ethernet_kiss"
class EthernetKissTests(unittest.TestCase):
def test_kiss_port_does_not_collide_with_companion_services(self):
companion = (ROOT / "examples/companion_radio/main.cpp").read_text(encoding="utf-8")
server = (ROOT / "src/helpers/esp32/EthernetKissServer.h").read_text(encoding="utf-8")
terminal = re.search(r"#define\s+OTA_CONSOLE_TCP_PORT\s+(\d+)", companion)
kiss = re.search(r"static constexpr uint16_t Port\s*=\s*(\d+)", server)
self.assertIsNotNone(terminal)
self.assertIsNotNone(kiss)
self.assertEqual(int(terminal.group(1)), 5002)
self.assertEqual(int(kiss.group(1)), 5003)
self.assertNotIn(int(kiss.group(1)), {5000, 5001, int(terminal.group(1))})
@classmethod
def setUpClass(cls):
cls.directory = tempfile.TemporaryDirectory()
cls.executable = Path(cls.directory.name) / "ethernet-kiss"
command = [
"g++", "-std=c++17", "-Wall", "-Wextra", "-Werror", "-g",
"-fsanitize=address,undefined", "-fno-omit-frame-pointer", "-no-pie",
"-I", str(FIXTURE), "-I", str(ROOT / "src"),
str(FIXTURE / "test_ethernet_kiss.cpp"), "-o", str(cls.executable),
]
result = subprocess.run(command, capture_output=True, text=True)
if result.returncode:
cls.directory.cleanup()
raise AssertionError(result.stdout + result.stderr)
@classmethod
def tearDownClass(cls):
cls.directory.cleanup()
def run_case(self, name):
environment = dict(os.environ, ASAN_OPTIONS="detect_leaks=1:halt_on_error=1")
result = subprocess.run([str(self.executable), name], env=environment,
capture_output=True, text=True, timeout=30)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
def test_every_ethernet_length_and_tcp_split(self):
self.run_case("codec-roundtrip")
def test_malformed_escapes_ports_short_and_oversized_frames(self):
self.run_case("codec-malformed")
def test_queue_backpressure_and_partial_output(self):
self.run_case("codec-backpressure")
def test_reset_and_bounded_random_input(self):
self.run_case("codec-reset-fuzz")
def test_station_only_binding_single_client_and_disable(self):
self.run_case("server-station")
def test_per_poll_budgets_and_tcp_backpressure(self):
self.run_case("server-budget-backpressure")
def test_nonblocking_writes_resume_without_duplicate_bytes(self):
self.run_case("server-partial-writes")
def test_disconnect_reconnect_address_change_discards_stale_work(self):
self.run_case("server-session-reset")
def test_listener_retry_eof_and_socket_errors(self):
self.run_case("server-failures")
if __name__ == "__main__":
unittest.main()