Skip to content

infra(test): add probe-based friend injection for server-private methods (Phase 2D of #1074)#1104

Merged
kcenon merged 1 commit into
developfrom
feat/issue-1074-phase-2d-network-test-friends
May 6, 2026
Merged

infra(test): add probe-based friend injection for server-private methods (Phase 2D of #1074)#1104
kcenon merged 1 commit into
developfrom
feat/issue-1074-phase-2d-network-test-friends

Conversation

@kcenon

@kcenon kcenon commented May 5, 2026

Copy link
Copy Markdown
Owner

What

Add friend-test injection so unit tests can drive two server-side private methods previously unreachable from public APIs. Plus probe classes and demo tests. No behavioral changes to src/.

Targets opened to friend access

Class (namespace) Method Header Line
messaging_quic_server (kcenon::network::core) handle_packet(span, endpoint) src/internal/experimental/quic_server.h 432
messaging_ws_server (kcenon::network::core) handle_new_connection(shared_ptr<tcp::socket>) src/internal/http/websocket_server.h 415

Change Type

  • Test infrastructure (one-line friend declaration + namespace forward-decl per header, both gated)
  • CMake gate symbol (test build only)
  • No public-API additions, no behavioral changes

Why

Part of #1074 (Phase 2D). Continues #1075 (2A), #1082 (2A.2), #1102 (2B), #1103 (2C).

Issue #1074 §"Out of scope" explicitly limits this work to friend declarations. Two private methods were called out as the remaining barriers to unit-test coverage of server-side QUIC and WebSocket reception logic. Without friend access, post-private-state branches in quic_server.cpp and websocket_server.cpp remain dead code from the test runner's perspective.

Related Issues

Where

File Change
cmake/network_system_targets.cmake +9 (gate symbol wiring inside if(BUILD_TESTS))
src/internal/experimental/quic_server.h +13 (forward-decl + friend, both gated)
src/internal/http/websocket_server.h +13 (same shape)
tests/support/network_test_friends.h new (+21)
tests/support/quic_server_probe.{h,cpp} new (+59)
tests/support/ws_server_probe.{h,cpp} new (+58)
tests/support/CMakeLists.txt +2 (probe sources)
tests/CMakeLists.txt +14 (2 test registrations)
tests/unit/quic_server_probe_test.cpp new (+58)
tests/unit/ws_server_probe_test.cpp new (+72)

Total: 12 files, 319 insertions, 0 deletions. PR size: M.

How

Implementation Highlights

Gate symbol — NETWORK_ENABLE_TEST_INJECTION. Defined as target_compile_definitions(network_system PUBLIC NETWORK_ENABLE_TEST_INJECTION) inside an if(BUILD_TESTS) block. PUBLIC propagation so probe TUs and test executables inherit the same define. When BUILD_TESTS=OFF, the production binary is byte-identical to the previous develop tip — friend blocks compile out entirely.

Production header pattern (mirrored in both):

#if defined(NETWORK_ENABLE_TEST_INJECTION)
namespace kcenon::network::tests::support
{
    class quic_server_probe;  // forward declaration only
} // namespace kcenon::network::tests::support
#endif

namespace kcenon::network::core
{
class messaging_quic_server : public ... {
    // ...
private:
#if defined(NETWORK_ENABLE_TEST_INJECTION)
    friend class kcenon::network::tests::support::quic_server_probe;
#endif
    // ...
};
}

The forward-decl block lives outside the production namespace, so the production header pulls in zero test types. Probe definitions live entirely in tests/support/.

Probe shape (pure forwarder):

class quic_server_probe {
public:
    static auto invoke_handle_packet(
        kcenon::network::core::messaging_quic_server& srv,
        std::span<const std::uint8_t> bytes,
        const asio::ip::udp::endpoint& from) -> void;
};

Static-method forwarders, no instance state, no fixture dependency. The probe exists solely to grant the friend bridge.

Testing Done

  • QuicServerProbeTest.HandlePacketEmptyBufferDoesNotCrash — passes
  • QuicServerProbeTest.HandlePacketGarbageBufferDoesNotCrash — passes
  • WsServerProbeTest.HandleNewConnectionEarlyReturnNoSessionManager — passes
  • WsServerProbeTest.HandleNewConnectionEmptySocketEarlyReturn — passes

The WebSocket tests exercise the session_mgr_ == nullptr early-return branch (server is never started). Reaching the started-server path requires a ws_session_manager and a connected loopback peer driving the WebSocket upgrade — that is the domain of network_websocket_server_loopback_test, not the probe wiring test. Phase 2D's job is proving the friend bridge works end-to-end and that the previously-private entry points are now reachable from tests.

Test Plan for Reviewers

cmake -S . -B build -DBUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
cmake --build build --target network_quic_server_probe_test network_ws_server_probe_test -j
ctest --test-dir build -R 'QuicServerProbe|WsServerProbe' --output-on-failure

Note: GTest test-case names are PascalCase (QuicServerProbeTest), CTest target names are snake_case (network_quic_server_probe_test) — the -R filter matches GTest names.

Off-by-default Verification

To confirm BUILD_TESTS=OFF produces a byte-identical production library:

cmake -B build-rel -DBUILD_TESTS=OFF
cmake --build build-rel --target network_system
nm build-rel/libnetwork_system.a | grep -i probe
# Should be empty.

Breaking Changes

None.

Rollback

Revert this PR. No data, no public-API impact. Production binary semantics unchanged.

Part of #1074

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
@github-actions

github-actions Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Metric Value
Line Coverage 68.9%
Branch Coverage 34.2%
Target 80% lines / 70% branches
Coverage Details

Full HTML report is available as a build artifact.

@kcenon kcenon merged commit 0ca0c4a into develop May 6, 2026
15 checks passed
@kcenon kcenon deleted the feat/issue-1074-phase-2d-network-test-friends branch May 6, 2026 01:01
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