test(quic): expand branch coverage for quic_server.cpp#1058
Merged
Conversation
Add tests/unit/quic_server_branch_test.cpp complementing experimental_quic_server_test.cpp (Issue #989). Covers public-API surfaces of messaging_quic_server reachable without a live QUIC peer: - quic_server_config full-field round-trips: empty/1024-char/binary-byte cert/key paths, optional ca_cert_file present and absent, require_client_cert toggling, ALPN protocol vector growth (empty, single, four-with-empty-string, 32-entry), all six numeric settings at zero and std::numeric_limits boundaries, enable_retry toggle, retry_key vector growth (empty, 16, 256 bytes), full-config copy round-trip preserving every field - Construction with empty / 512-char / binary-byte server IDs, 16-iteration short-lived loops, server_id() reference stability - Default-state queries on a never-started server: is_running, session_count, connection_count, sessions, get_session - stop_server() rejection branch when never started, repeated rejection idempotency, i_quic_server::stop() interface delegation - disconnect_session() not_found branch for unknown/empty/long/binary ids and varied error codes - disconnect_all() empty-map no-op for varied error codes - broadcast() and multicast() empty-map ok-return for empty/small/64KiB payloads, repeated invocation, empty session_ids, many unknown ids - Legacy callback registration with empty std::function / triple replacement / shared_ptr capture for all five callback types - Interface (i_quic_server) callback adapters for all five callbacks with null callbacks, populated lambdas, triple replacement - Concurrent polling of is_running / session_count / server_id / sessions and concurrent legacy callback replacement under shared_ptr - Multi-instance independent default state across 8 servers - Destructor on never-started, after failed-stop, with callbacks registered The impl-level packet-driven paths (do_start_impl, do_stop_impl, start_receive, handle_packet, find_or_create_session, on_session_close, start_cleanup_timer, cleanup_dead_sessions, all five invoke_*_callback helpers, populated-map broadcast/multicast/disconnect_session/ disconnect_all branches) require a live QUIC client that completes a TLS handshake or a friend-declared injection point and remain uncovered. Register network_quic_server_branch_test in tests/CMakeLists.txt. Update CHANGELOG.md and docs/CHANGELOG.md. Closes #1052 Part of #953
…/if.h struct iface conflict
Contributor
Coverage Report
Coverage DetailsFull HTML report is available as a build artifact. |
This was referenced Apr 26, 2026
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
Summary
Adds hermetic branch-coverage tests for
src/experimental/quic_server.cppto raisethe file from the 2026-04-26 baseline (line 43.7%, branch 17.5%) toward the
acceptance bar (line >= 70%, branch >= 60%) defined in epic #953. Tests operate
purely on the public API of
messaging_quic_serverand onquic_server_config,covering field round-trips, default-state queries, error-path early-returns,
callback registration (legacy + interface adapters), concurrency invariants,
multi-instance independence, and destructor cleanup. No live QUIC peer or TLS
handshake is required.
Change Type
Why
Related Issues
Motivation
src/experimental/quic_server.cppsits among the lowest-coverage files in thenetwork_system source tree per the 2026-04-26 measurement on
develop @ 05c1b7bb(line 43.7%, branch 17.5%). The uncovered region concentrates in error and
boundary paths exactly the surfaces that regress during the ongoing
Result<T>migration and API stabilization. Bringing this file over the 70% line / 60%
branch bar contributes directly to the #953 acceptance criteria (80% line / 70%
branch ecosystem-wide). This PR is sub-issue 4 of 5 in the sequential batch
under #953 and follows the pattern established by #1054 (http2_client),
#1055 (grpc client), #1056 (http2_server), and #1057 (quic_socket).
Where
Files Changed
tests/unit/quic_server_branch_test.cpp(new, ~720 lines)tests/CMakeLists.txt(registersnetwork_quic_server_branch_test)CHANGELOG.md(Unreleased -> Added entry)docs/CHANGELOG.md(Unreleased -> Added entry, detailed)How
Implementation Highlights
The test file groups cases by surface:
QuicServerConfigRoundTrip(12 tests): full-field round-trips forquic_server_configincluding empty / 1024-character / binary-byte cert/keypaths, optional
ca_cert_filepresent (16-character / 2048-character) andabsent,
require_client_certtoggling, ALPN vector with empty / single /four-with-empty-string / 32-entry growth and
clear()-shrink, six numericsettings at zero and
std::numeric_limitsmax boundaries,enable_retrytoggle,
retry_keyvector growth, and full-config copy round-trip.QuicServerConstruction(4 tests): empty / 512-character / binary-byte serverIDs, 16-iteration short-lived loops,
server_id()reference stability.QuicServerDefaults(5 tests): never-started invariants foris_running,session_count,connection_count,sessions, andget_sessionforunknown / empty / 2048-character ids.
QuicServerStop(3 tests): rejection branch when never started, 5-iterationrepeated rejection idempotency, plus
i_quic_server::stop()interfacedelegation.
QuicServerDisconnect(6 tests):disconnect_session()not_foundbranchfor unknown / empty / long / binary-byte ids with varied error codes (0, 1,
42, max-uint64);
disconnect_all()empty-map no-op.QuicServerBroadcast/QuicServerMulticast(10 tests): empty-mapok()return for empty / small / 64 KiB payloads, repeated invocation, empty
session_ids, many unknown ids (3, 64), and empty-string id.QuicServerLegacyCallbacks(7 tests): default-constructedstd::function,triple replacement, and
shared_ptrcapture for all five legacy callbacktypes (connection / disconnection / receive / stream_receive / error).
QuicServerInterfaceCallbacks(12 tests): interface (i_quic_server)callback adapters for all five callbacks with populated lambdas, empty
std::function, and (for connection) triple replacement; combined-registration test setting all five together.
QuicServerConcurrency(5 tests): concurrent polling undershared_ptrlifetime with 4 threads x 100-200 iterations of
is_running,session_count,connection_count,server_id,sessions, plus a writer/reader pair onset_error_callback/is_running.QuicServerMultiInstance(2 tests): 8 servers with independent defaultstate, broadcast-on-one-does-not-affect-another sibling.
QuicServerDestructor(3 tests): never-started, after failed-stop, and withall five legacy callbacks registered.
Total: 69 hermetic test cases in 11 test suites.
Honest scope statement
The impl-level packet-driven paths in
messaging_quic_serverremain reachableonly with a UDP transport fixture and a TLS-1.3 client. Specifically the
following private surfaces stay uncovered without a live peer:
do_start_impl()success path pastasio::ip::udp::socketbind; thebind_failedbranches foraddress_in_use/access_deniedare reachableonly by binding to a privileged or in-use port and would not be hermetic.
do_stop_impl()(only reachable after a successful start; the success pathstarts an
io_contextloop that runs asynchronously and cannot be cleanlystopped from a unit test process).
start_receive()async UDP receive completion.handle_packet()header parsing, dcid extraction, and session dispatch.find_or_create_session()(session lookup, create, connection-limit-reachedbranch, UDP socket connect,
quic_socket::accept, session callback wiring,metrics reporting, monitor recording).
generate_session_id()(only invoked insidefind_or_create_session).on_session_close()(peer-driven close).start_cleanup_timer()andcleanup_dead_sessions()(periodic timer).invoke_*_callback()helpers (only invoked from packet-drivenpaths).
broadcast(),multicast(),disconnect_session(),and
disconnect_all()under a populated session map.Driving these would require either a live QUIC client that completes a TLS
handshake (with on-disk PEM cert/key) or a friend-declared test injection
point inside
messaging_quic_server. Both are out of scope for this PRfollowing the precedent established by #1054 / #1055 / #1056 / #1057.
Testing Done
Breaking Changes
None test-only additions. No production code changed.