Skip to content

feat(tests/support): add HEADERS+DATA reply for h2 mock peer (Phase 2A.2)#1082

Merged
kcenon merged 1 commit into
developfrom
feat/issue-1074-phase-2a2-h2-headers-data-reply
May 1, 2026
Merged

feat(tests/support): add HEADERS+DATA reply for h2 mock peer (Phase 2A.2)#1082
kcenon merged 1 commit into
developfrom
feat/issue-1074-phase-2a2-h2-headers-data-reply

Conversation

@kcenon

@kcenon kcenon commented Apr 29, 2026

Copy link
Copy Markdown
Owner

What

Summary

Phase 2A.2 of #1074. Extends mock_h2_server_peer with an opt-in reply_mode parameter so tests can exercise the http2_client response-success path against a hermetic loopback peer. The default mode (drain_only) is unchanged.

Change Type

  • Feature (test infrastructure addition)
  • Bugfix
  • Refactor
  • Documentation
  • Test

Affected Components

  • tests/support/mock_h2_server_peer.{h,cpp} -- new reply_mode::echo_one path
  • tests/unit/http2_client_branch_test.cpp -- new demo TEST_F
  • tests/support/README.md -- usage example + Phase 2 progress update

Why

Problem Solved

http2_client::handle_headers_frame and handle_data_frame success branches were only reachable via the DISABLED_ConnectToHttpbin integration test that requires an external network. The Phase 2A mock_h2_server_peer only performed the SETTINGS exchange and then drained client frames -- http2_client::get() always timed out, so the post-SETTINGS success paths were unreachable from CI.

Related Issues

Where

Files Changed

File Change
tests/support/mock_h2_server_peer.h new reply_mode enum, constructor parameter, three new getters
tests/support/mock_h2_server_peer.cpp echo_one branch in run() reads one request stream and writes HEADERS+DATA reply
tests/unit/http2_client_branch_test.cpp new GetSucceedsWhenPeerRepliesWithHeadersAndData TEST_F
tests/support/README.md usage example + Phase 2 progress table update

API Changes

  • mock_h2_server_peer constructor gains a defaulted reply_mode mode = reply_mode::drain_only parameter (backward compatible -- all existing callers compile unchanged)
  • New public getters: request_received(), response_sent(), last_request_stream_id()

How

Implementation Details

  1. New reply_mode enum with two values: drain_only (Phase 2A behavior, default) and echo_one (Phase 2A.2).
  2. After the SETTINGS exchange, run() checks the mode. In echo_one:
    • Loop reading client frames until a HEADERS frame opens a stream and END_STREAM is observed (either on HEADERS or on a subsequent DATA frame on the same stream_id).
    • Send response HEADERS frame with :status: 200 (HPACK indexed header field 0x88, RFC 7541 Appendix A static-table index 8) on the same stream_id.
    • Send response DATA frame with body "ok" and END_STREAM set.
    • Set request_received_ and response_sent_ atomic flags.
  3. The drain loop after the mode-specific block continues to absorb GOAWAY/PING frames emitted during disconnect().

Testing Done

  • Local build verification -- toolchain unavailable in dev environment; relying on CI
  • Static review of frame_type / frame_flags / frame_header members against src/internal/protocols/http2/frame.h
  • Backward compatibility verified by inspection: every existing mock_h2_server_peer peer(io()) call retains the Phase 2A drain_only behavior via the default argument

Test Plan for Reviewers

  1. CI must pass on Ubuntu / macOS / Windows (build, sanitizers, ctest)
  2. New test Http2ClientHermeticTransportTest.GetSucceedsWhenPeerRepliesWithHeadersAndData should pass
  3. All existing Phase 2A tests in http2_client_branch_test.cpp and grpc_client_branch_test.cpp should continue to pass unchanged

Breaking Changes

None -- reply_mode parameter has a default value matching prior behavior.

Extend mock_h2_server_peer with an opt-in reply_mode parameter. The
new echo_one mode reads one client request stream after the SETTINGS
exchange (HEADERS plus any DATA frames up to END_STREAM) and replies
on the same stream_id with a server HEADERS frame carrying
':status: 200' (HPACK static index 8 = 0x88) followed by a small
END_STREAM DATA frame. The default drain_only mode is unchanged so
existing Phase 2A timeout-path tests in http2_client_branch_test.cpp
continue to drive the same code paths.

Add a demo TEST_F that exercises http2_client::get against the new
success path, asserting status_code == 200 and the response body. The
test reaches handle_headers_frame and handle_data_frame branches that
were previously only covered by the DISABLED_ConnectToHttpbin
integration test the coverage workflow does not run.

Update tests/support/README.md with a copy-paste usage example for
reply_mode::echo_one and mark Phase 2A.2 as shipped in the Phase 2
progress table.
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report

Metric Value
Line Coverage 68.6%
Branch Coverage 34.0%
Target 80% lines / 70% branches
Coverage Details

Full HTML report is available as a build artifact.

@kcenon kcenon merged commit 9e67fbd into develop May 1, 2026
15 checks passed
@kcenon kcenon deleted the feat/issue-1074-phase-2a2-h2-headers-data-reply branch May 1, 2026 03:57
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
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.

1 participant