test(grpc): expand branch coverage for client.cpp#1055
Merged
Conversation
Add tests/unit/grpc_client_branch_test.cpp complementing grpc_client_test.cpp (Issue #994) and core_client_test.cpp (Issue #977) with hermetic public-API coverage targeting src/protocols/grpc/client.cpp. Surfaces covered: - grpc_channel_config full-field round-trip with zero/max boundary values, default verification, partial mutual-TLS configurations - call_options::set_timeout across seconds/milliseconds/microseconds/ nanoseconds, zero-timeout, deadline-overwrite, monotonicity - call_options metadata growth: empty key, empty value, 64 ordered entries, 8 KiB value, binary-flagged key, clear-resets-empty - grpc_client construction with long, IPv6 bracket, DNS, with-path, port-65535, and identical-target permutations - wait_for_connected budget verification at 0/1/50 ms, repeated-call idempotency - 32-iteration sequential and 4-thread concurrent disconnect(), 8-thread concurrent is_connected() polling, concurrent disconnect-while-querying - Move construction / move assignment / 4-step move chain - Extended malformed-target connect coverage: leading/trailing/only colon, multi-colon, space-in-port, negative-leading, > 63-char DNS label - call_raw guard variants: empty method, no-leading-slash, 64 KiB payload, pre-expired deadline, future deadline, wait_for_ready, compression, post-disconnect - Server / client / bidi streaming guard clauses: empty / no-slash methods, expired deadline, post-disconnect - call_raw_async 8-callback concurrent stress, null-callback safety - grpc_metadata copy / move / assignment-from-empty / erase semantics Honest scope statement: impl-level frame exchange paths (HTTP/2 POST after is_connected()==true, official UnaryCall, streaming send/receive loops, on_data/on_headers/on_complete callbacks driven by HTTP/2 trailers, tracing set_attribute/set_error inside successful call paths) require a live peer and remain uncovered by this hermetic suite. Closes #1049
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/protocols/grpc/client.cpp, exercising public-API surfaces that remained uncovered after the initial coverage work in #994. The new test filetests/unit/grpc_client_branch_test.cppadds 51 test cases across 12 test suites, complementing the existinggrpc_client_test.cppandcore_client_test.cpp.Change Type
Why
Related Issues
Motivation
src/protocols/grpc/client.cppwas measured at line 22.6% / branch 9.5% ondevelop @ 05c1b7bb(2026-04-26 baseline) and concentrates uncovered code in error and boundary paths — exactly the surfaces that regress during the ongoingResult<T>migration. Raising coverage of this file contributes directly to the #953 acceptance criteria (line >= 70% / branch >= 60% per file). This PR adds hermetic tests that exercise public-facing surfaces (config round-trip, call_options, lifecycle, guard clauses, async callbacks, metadata semantics) without requiring a live gRPC peer.Where
Files Changed
tests/unit/grpc_client_branch_test.cpp(new, 542 lines, 51 test cases)tests/CMakeLists.txt(registration ofnetwork_grpc_client_branch_test)CHANGELOG.md(one-line entry under[Unreleased] > Added)docs/CHANGELOG.md(multi-line detailed entry under[Unreleased] > Added)How
Implementation Highlights
Test groups in
grpc_client_branch_test.cpp:GrpcClientChannelConfigBoundary— full-field round-trip with all-zero / all-max / default / partial mutual-TLS configurationsGrpcClientCallOptionsSetTimeout—set_timeoutacrosschrono::seconds/milliseconds/microseconds/nanoseconds, zero-timeout, deadline overwrite, monotonicityGrpcClientCallOptionsMetadata— empty key / empty value / 64 ordered entries / 8 KiB value / binary-flagged key / clear-resets-emptyGrpcClientConstructionTargets— long, IPv6 bracket, DNS, with-path, port-65535, identical-target permutationsGrpcClientWaitForConnectedBudget— 0 / 1 / 50 ms timeouts, repeated-call idempotencyGrpcClientDisconnectIdempotency— 32 sequential disconnects, 4-thread concurrent disconnects, 8-thread is_connected polling (1600 observations), concurrent disconnect-while-queryingGrpcClientMoveSemantics— move construct / move assign / 4-step move chain / disconnect-after-moveGrpcClientConnectMalformed— leading / trailing / only colon, multi-colon, space-in-port, negative-leading port, > 63-char DNS label (default-transport build only)GrpcClientCallRawGuards— empty method, no-leading-slash, 64 KiB payload, pre-expired deadline, future deadline,wait_for_ready=true, compression algorithm set, post-disconnectGrpcClientStreamingGuards— server / client / bidi streaming with empty methods, missing-slash methods, expired deadline, post-disconnectGrpcClientCallRawAsyncStress— 8-callback concurrent stress with deterministic notification, null-callback safety with non-empty payload and with deadlineGrpcMetadataSemantics— copy / move / assignment-from-empty / eraseHonest scope statement
This PR covers the surfaces that are reachable via the public API without a live gRPC peer. The impl-level methods that physically exchange frames with a peer remain at zero hits and would require a transport fixture (or in-process loopback test peer) to drive:
grpc_client::impl::call_rawbody after theis_connected()==truebranch (HTTP/2post()round-trip in default transport,stub_->UnaryCallin official-grpcpp build)server_stream_reader_impl::on_data/on_headers/on_complete— invoked by HTTP/2 stream callbacksclient_stream_writer_impl::write/writes_done/finishround-trip — requires server responsebidi_stream_impl::read/write/writes_done/finish— requires bidi peergrpc_client::impl::server_stream_raw/client_stream_raw/bidi_stream_rawbody after theis_connected()==trueand method-validation guardsspan->set_attribute/span->set_errorcalls on successful call paths (only reachable when tracing is enabled and a call completes)The hermetic suite covers everything that returns synchronously without crossing the network boundary: config validation, option construction, lifecycle, guard clauses, async-callback delivery for the not-connected case, and value-type semantics. A separate sub-issue (or in-process gRPC test fixture work under #953) is required to push coverage of the frame-exchange paths above the line/branch thresholds.
Testing Done
Breaking Changes
None — test-only additions and CHANGELOG entries.