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
- Start with pure request/response tests (send_ping, send_response)
- Test packet handling with constructed headers and events
- Test multi-response FINDNODE collection
- Test handshake trigger via dummy key
- Run
uvx tox -e all-checks to pass all quality checks
Summary
src/lean_spec/subspecs/networking/discovery/transport.pyhas 71% test coverage. Whiletest_transport.pyexists, many packet handling paths, the multi-response FINDNODE flow, and response sending are not covered.Coverage stats:
discovery/transport.pyUncovered 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/responsesend_ping()send_findnode()total=1totalreachedsend_talkreq()send_response()Packet handling
_handle_packet()_handle_message()_handle_whoareyou()_handle_handshake()_handle_whoareyou()_handle_handshake()_handle_message()_handle_decoded_message()_build_message_packet()Lifecycle
start(): Creates UDP endpoint, sets running flagstop(): Closes transport, cancels pending requestsregister_node_address()/get_node_address(): Address lookupregister_enr()/get_enr(): ENR cache delegationWhy this matters
How to test
Running tests with coverage
Target: ≥85% line coverage.
Test file location
Testing tips
asyncio.DatagramTransportfor send verificationSessionCachewith pre-populated sessions for message handling testsPacketHeaderand event instances directly for_handle_*methodsasyncio.Queueto simulate NODES arrivalsconftest.pyfixtures in the discovery test directoryUsing Claude Code subagents
1.
code-testeragent — Generate the testsWorkflow
uvx tox -e all-checksto pass all quality checks