infra(test): add mock_quic_peer_loop for QUIC Initial loopback (Phase 2C of #1074)#1103
Merged
Merged
Conversation
…2C of #1074) Add server-side QUIC Initial echo peer to tests/support/. The peer receives one client Initial datagram, derives QUIC v1 initial keys from the original DCID (RFC 9001 Section 5.2), and replies with a header-protected server Initial carrying a stub crypto_frame (type 0x06). This makes quic_socket::process_crypto_frame reachable from a hermetic test for the first time, unblocking coverage expansion under #1062 / #1065. Phase 2A (#1075) and 2B (#1102) shipped HTTP/2 and gRPC peers; this follows the same RAII shape: shared io_context, dedicated worker thread, atomic state flags polled via wait_for. Phase 2D (friend- test injection) and 2E (frame_injector) remain open under #1074. Files: - tests/support/mock_quic_peer_loop.{h,cpp} (new) - tests/support/CMakeLists.txt (+1) - tests/support/README.md (+1) - tests/unit/quic_socket_branch_test.cpp (+46) -- one demo TEST_F Part of #1074
Contributor
Coverage Report
Coverage DetailsFull HTML report is available as a build artifact. |
This was referenced May 5, 2026
kcenon
added a commit
that referenced
this pull request
May 6, 2026
…#1104) Add friend-test injection so unit tests can drive two private server-side methods previously unreachable from public APIs: - messaging_quic_server::handle_packet (src/internal/experimental/quic_server.h:432) - messaging_ws_server::handle_new_connection (src/internal/http/websocket_server.h:415) Mechanism: new compile definition NETWORK_ENABLE_TEST_INJECTION gated behind BUILD_TESTS in cmake/network_system_targets.cmake. The two production headers gain a forward declaration block and a single 'friend class' line, all wrapped in '#if defined(NETWORK_ENABLE_TEST_INJECTION)'. When BUILD_TESTS=OFF the production binary is byte-identical to the previous develop tip. Probe types live entirely in tests/support/: - network_test_friends.h forward-declares the probes - quic_server_probe.{h,cpp} forwards to handle_packet - ws_server_probe.{h,cpp} forwards to handle_new_connection Demo tests verify end-to-end wiring: - QuicServerProbeTest.HandlePacket{Empty,Garbage}BufferDoesNotCrash - WsServerProbeTest.HandleNewConnectionEarlyReturnNoSessionManager - WsServerProbeTest.HandleNewConnectionEmptySocketEarlyReturn Per #1074 scope: no behavioral changes to src/. Phases 2A (#1075), 2A.2 (#1082), 2B (#1102), 2C (#1103) merged; 2E remains. Part of #1074
Merged
12 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Add
tests/support/mock_quic_peer_loop.{h,cpp}plus one demoTEST_F. The peer receives one client QUIC Initial datagram, derives QUIC v1 initial keys from the client's original DCID (RFC 9001 Section 5.2), and replies with a header-protected server Initial whose payload contains a stubcrypto_frame(type0x06). This makesquic_socket::process_crypto_framereachable from a hermetic test for the first time.Change Type
src/behavioral changes)Why
Part of #1074 (Phase 2C). Continues the work of #1075 (Phase 2A,
mock_h2_server_peer) and #1102 (Phase 2B,mock_grpc_server_peer).Without a peer that can pass the initial-keys gate at
quic_socket.cpp:527, the existingmock_udp_peer::make_quic_initial_packet_stubcannot drive any frame-dispatch branch inprocess_frame-- the entirecrypto_frame/stream_frame/ack_frameswitch sits behind that gate. This is the structural blocker for the>=80%line />=70%branch coverage targets in #1062 and #1065.Related Issues
http2_client.cpppost-connect coverage) and test(quic): expand internal/quic_socket.cpp coverage to 80% line / 70% branch #1065 (quic_socket.cpppost-keys coverage)Where
tests/support/mock_quic_peer_loop.htests/support/mock_quic_peer_loop.cpptests/support/CMakeLists.txttests/support/README.mdtests/unit/quic_socket_branch_test.cppTEST_F+ include)No
src/changes. No public-API additions. Phase 2D (friend-test injection forquic_server::handle_packet/websocket_server::handle_new_connection) and Phase 2E (frame_injector) remain open under #1074.How
Implementation Highlights
The peer mirrors the RAII shape of
mock_h2_server_peerandmock_grpc_server_peer:io_contextfromhermetic_transport_fixturestd::atomic<bool>state flags polled by tests viawait_for(...)127.0.0.1:0(kernel-assigned port), no DNS, no on-disk secretsCrypto path reuses production helpers -- no HKDF/AEAD reimplementation:
internal::quic::initial_keys::derive(dcid)for v1 initial-secret derivationinternal::quic::packet_builder::build_initial()for long-header constructioninternal::quic::packet_protection::protect()andprotect_header()for AEAD + header protectionThe reply payload is
PADDING + crypto_frame(0x06)carrying 8 zero bytes.process_crypto_framefires regardless of TLS parse outcome, which is the goal -- driving the branch, not completing the handshake.One implementation note:
packet_builder::build_initial()does not embed the payload-length varint, so the peer code computes ciphertext+tag size and inserts the varint manually before AEAD encryption. Reviewers may want to focus on this section inmock_quic_peer_loop.cpp.Testing Done
TEST_F:QuicSocketHermeticTransportTest::ProcessCryptoFrameReachableViaMockQuicPeerLooppeer.initial_sent()and!peer.io_failed()after the client connects. The test's value is that the previously unreachableprocess_crypto_framebranch executes -- coverage tooling picks that up. The client exposes no observable post-handshake state from outside (the TLS handshake does not complete with a stub crypto frame), so the test asserts peer-side state.ctest -R 'ProcessCryptoFrameReachableViaMockQuicPeerLoop'passes in 9 ms on macOS.Test Plan for Reviewers
Breaking Changes
None.
Rollback
Revert this PR. No data migration, no public-API impact.
Part of #1074