Skip to content

test: improve coverage for discovery v5 UDP transport (71%) #518

@tcoratger

Description

@tcoratger

Summary

src/lean_spec/subspecs/networking/discovery/transport.py has 71% test coverage. While test_transport.py exists, many packet handling paths, the multi-response FINDNODE flow, and response sending are not covered.

Coverage stats:

File Statements Covered Coverage
discovery/transport.py 299 72 uncovered 71%

Uncovered lines: 313, 349–350, 413, 417–430 (FINDNODE multi-response collection), 468, 547 (dummy key handshake trigger), 589–594 (connect flow), 621–699 (WHOAREYOU response handling), 714–737 (handshake response handling), 763–777 (message decryption failure → WHOAREYOU), 889–903 (send_response)

What needs testing

DiscoveryTransport — Request/response

send_ping()

  • Happy path: Sends PING, receives PONG, returns Pong
  • Timeout: No response within timeout, returns None
  • Non-PONG response: Unexpected message type, returns None

send_findnode()

  • Single NODES response: One response with total=1
  • Multi-response: Multiple NODES messages collected until total reached
  • Timeout during collection: Partial results returned
  • Empty results: NODES with empty ENR list

send_talkreq()

  • Happy path: Sends TALKREQ, receives TALKRESP
  • Timeout: Returns None

send_response()

  • Happy path: Encrypts and sends response using existing session
  • No session: Returns False
  • Transport not started: Returns False

Packet handling

_handle_packet()

  • MESSAGE packet: Routes to _handle_message()
  • WHOAREYOU packet: Routes to _handle_whoareyou()
  • HANDSHAKE packet: Routes to _handle_handshake()
  • Decode error: Logged and dropped gracefully

_handle_whoareyou()

  • Matching pending request: Finds request by nonce, creates handshake response
  • No matching request: Logs debug and returns
  • No cached ENR: Cannot complete handshake, returns
  • Handshake error: Logged and dropped

_handle_handshake()

  • Valid handshake: Completes handshake, decrypts message, dispatches
  • Handshake failure: Logged and dropped

_handle_message()

  • With session: Decrypts and dispatches message
  • No session: Sends WHOAREYOU challenge
  • Decryption failure: Sends WHOAREYOU challenge

_handle_decoded_message()

  • Pending single request: Resolves future with response
  • Pending multi request: Queues to response queue
  • Unsolicited message: Passed to message handler callback

_build_message_packet()

  • With session: Uses session send key for encryption
  • Without session: Uses dummy key to trigger handshake

Lifecycle

  • start(): Creates UDP endpoint, sets running flag
  • stop(): Closes transport, cancels pending requests
  • register_node_address() / get_node_address(): Address lookup
  • register_enr() / get_enr(): ENR cache delegation

Why this matters

  • Discovery reliability: This is how nodes find each other. Bugs here mean network isolation
  • Handshake correctness: The deliberate-failure handshake initiation is subtle and must work precisely
  • Multi-response handling: FINDNODE's split-response pattern is error-prone without tests

How to test

Running tests with coverage

uv run pytest tests/lean_spec/subspecs/networking/discovery/test_transport.py -v \
  --cov=src/lean_spec/subspecs/networking/discovery/transport --cov-report=term-missing

Target: ≥85% line coverage.

Test file location

tests/lean_spec/subspecs/networking/discovery/test_transport.py  (extend existing)

Testing tips

  • Mock asyncio.DatagramTransport for send verification
  • Use SessionCache with pre-populated sessions for message handling tests
  • Construct PacketHeader and event instances directly for _handle_* methods
  • For multi-response tests, use asyncio.Queue to simulate NODES arrivals
  • Use the existing conftest.py fixtures in the discovery test directory

Using Claude Code subagents

1. code-tester agent — Generate the tests

Extend tests in tests/lean_spec/subspecs/networking/discovery/test_transport.py. Cover send_findnode multi-response collection, send_response with/without session, _handle_whoareyou with matching/missing pending request, _handle_message with/without session (decryption failure path), _handle_decoded_message routing to single/multi/handler, and _build_message_packet with/without session.

Workflow

  1. Start with pure request/response tests (send_ping, send_response)
  2. Test packet handling with constructed headers and events
  3. Test multi-response FINDNODE collection
  4. Test handshake trigger via dummy key
  5. Run uvx tox -e all-checks to pass all quality checks

Metadata

Metadata

Assignees

Labels

good first issueGood for newcomerstestsScope: Changes to the spec tests

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions