Skip to content

test(integration): MCUboot raw serial recovery (SMPSerialRawTransport)#119

Open
JPHutchins wants to merge 1 commit into
mainfrom
feature/118-raw-serial-recovery
Open

test(integration): MCUboot raw serial recovery (SMPSerialRawTransport)#119
JPHutchins wants to merge 1 commit into
mainfrom
feature/118-raw-serial-recovery

Conversation

@JPHutchins

@JPHutchins JPHutchins commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds the integration test for MCUboot raw (non-console) serial recovery — the raw-framing analog of the existing base64 tests/integration/test_serial_recovery.py. A fully-featured app reboots into MCUboot serial recovery via os reset boot_mode=BOOTLOADER, and the bootloader's SMP server — built with MCUboot's raw recovery protocol (BOOT_SERIAL_RAW_PROTOCOL, mcu-tools/mcuboot#2755) — reassembles a fragmented image upload over SMPSerialRawTransport.

Closes #118. Unblocked by intercreate/smp-server-fixtures#9 (closes smp-server-fixtures#8), which built the fixture for mps2_an385 (emulated) — so this PR also adds the socket-backed raw transport the issue anticipated.

Test-only: no production (src/) changes — everything lives under tests/.

Harness

  • servers.py — add QemuSocketSerialRawTransport, the raw counterpart of QemuSocketSerialTransport: an SMPSerialRawTransport whose byte pipe is the emulator's socket:// chardev (sidesteps the PTY held-byte quirk of an emulated UART). Both socket fixtures override only connect — framing, fragmentation, send, and receive are inherited from the real transports unchanged, so the suite exercises the real send rather than a copy of it. The shared socket-connect retry loop is factored out of both into _connect_socket_chardev, which also gives the socket conn an out_waiting of 0 (pyserial's socket:// backend omits it) so the inherited send's _drain_tx poll is a no-op. The accommodation lives entirely in the test backend; the production transport is untouched.
  • conftest._build_transportSocketSerialEndpoint now branches on fixture.transport, routing serial_raw to the new transport (exhaustive match with assert_never).

Tests

  • test_serial_recovery_raw.py (new) — reboot → reconnect raw → upload → assert the bootloader reassembles the fragmented upload + assert_chunks_maximized. Raw recovery carries the whole SMP message in its receive buffer with no base64/length/CRC framing, so the transport's mtu is the per-message cap (the recovery server advertises no MCUmgr params → max_unencoded_size falls back to mtu). Parametrized at mtu 384 (the raw default) and 1024 (fills MCUboot's recovery buffer).
  • test_image_management.test_dfu_upload — now accepts the raw transport too (the new fixture is the first serial_raw fixture with the img group). The encoded-only line-packet burst skip stays gated behind isinstance(transport, SMPSerialTransport); encoded behavior is unchanged.
  • Consolidated a duplicated _signed_image helper into conftest.signed_image.

The new fixture also joins the generic connected_server suite, so the socket-backed raw transport now runs echo / enumeration / params / fs round-trips and DFU-to-app, in addition to the dedicated recovery test.

Fixtures (additive vendoring)

Only the one new fixture is vendored — the existing 0eae053d set is left untouched, per the request to add rather than replace:

  • Vendors zephyr_f33aa2bc4a43_smp_server_c8f44c41_mps2_an385_serial_recovery_raw.{hex,signed.bin} from the pinned c8f44c41 release (sha256-verified).
  • The artifact prefix (…c8f44c41…) differs from the 0eae053d set, so there's no collision. manifest.json and SHA256SUMS are merged additively (the manifest.json digest line was refreshed to keep SHA256SUMS internally consistent).
  • VERSION documents the mixed provenance: BOOT_SERIAL_RAW_PROTOCOL merged after 4.4.0's MCUboot pin, so this one fixture is built from a post-4.4.0 Zephyr main commit (f33aa2bc); re-vendor the whole set from one release once that lands in a tagged Zephyr.

Test plan

  • camas test_integration219 passed, 96 skipped, 0 failed (qemu mps2 + native_sim). The new fixture: 12 passed (raw DFU to app + to bootloader recovery, echo, enum, params, fs, buf-sizing), 5 skipped (encoded-only fragmentation + UDP).
  • test_serial_recovery_raw.py — both mtu-384 and mtu-1024 pass; the bootloader's raw recovery buffer accommodates 1024-byte messages.
  • camas check — ruff + pydoclint + mypy + unit tests pass.
  • Existing test_serial_recovery.py (encoded) still passes after the signed_image consolidation.
  • Full CI green (incl. the integration (native_sim + qemu) job and the lint-and-test matrix across macOS/ubuntu/ubuntu-arm/windows × Python 3.10–3.14).

Related

🤖 Generated with Claude Code

https://claude.ai/code/session_01KKXy7L2Udjw929nie2c363

Copilot AI review requested due to automatic review settings June 23, 2026 21:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

JPHutchins added a commit that referenced this pull request Jun 23, 2026
…s no out_waiting

The socket-backed fixtures (QemuSocketSerialTransport / QemuSocketSerialRawTransport)
overrode send() solely to skip _drain_tx() -- pyserial's socket:// backend has no
out_waiting. That re-implemented the parent's framing/fragmentation, which can silently
drift from the real transport (the encoded copy duplicated the smppacket.encode loop).

Root-cause it instead: _drain_tx() is now a no-op when the byte pipe has no out_waiting
(a socket:// chardev has no host-side TX buffer to drain), so both send() overrides are
dropped. The fixtures inherit the real send() verbatim and override only connect() (the
byte pipe). No behavior change for a real serial port, whose out_waiting always exists.

Addresses review feedback on #119.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKXy7L2Udjw929nie2c363
Comment thread src/smpclient/transport/serial/common.py
Comment thread src/smpclient/transport/serial/common.py Outdated

@JPHutchins JPHutchins left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment

…nsport)

The raw-framing analog of test_serial_recovery.py: an app reboots into MCUboot
serial recovery and the bootloader's raw (non-console) recovery server
(BOOT_SERIAL_RAW_PROTOCOL, mcu-tools/mcuboot#2755) reassembles a fragmented image
upload over SMPSerialRawTransport.

- servers.py: add QemuSocketSerialRawTransport, the socket-backed raw transport for
  the emulated mps2 fixture. Both socket fixtures override only connect() (via the
  shared _connect_socket_chardev) and inherit send()/receive()/framing from the real
  transports, so the suite exercises the real send rather than a copy of it. pyserial's
  socket chardev exposes no out_waiting, so connect supplies one (0) -- keeping the
  inherited send's _drain_tx a no-op without touching the production transport.
- conftest._build_transport: route serial_raw socket endpoints to the new transport
  (exhaustive match with assert_never).
- test_serial_recovery_raw.py: reboot -> reconnect raw -> upload -> assert reassembly
  + chunk maximization, at mtu 384 and 1024.
- test_image_management.test_dfu_upload: accept the raw transport (first img-group raw
  fixture); the line-packet burst skip stays encoded-only.
- consolidate the duplicated _signed_image into conftest.signed_image.
- vendor only the new mps2_an385 serial_recovery_raw fixture from smp-server-fixtures
  c8f44c41 (distinct artifact prefix; the 0eae053d set is untouched). manifest.json +
  SHA256SUMS merged additively; VERSION documents the mixed provenance.

Closes #118

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKXy7L2Udjw929nie2c363
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Integration test: MCUboot raw serial recovery (SMPSerialRawTransport)

2 participants