diff --git a/CMakeLists.txt b/CMakeLists.txt index dc45fc53edb..d9ce279bfbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1083,6 +1083,7 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx hpack_parser_test) add_dependencies(buildtests_cxx hpack_size_test) add_dependencies(buildtests_cxx http2_client) + add_dependencies(buildtests_cxx http2_stats_test) add_dependencies(buildtests_cxx http_proxy_mapper_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx httpcli_test) @@ -14251,6 +14252,50 @@ target_link_libraries(http2_client ) +endif() +if(gRPC_BUILD_TESTS) + +add_executable(http2_stats_test + test/core/end2end/cq_verifier.cc + test/core/end2end/end2end_test_main.cc + test/core/end2end/end2end_test_suites.cc + test/core/end2end/end2end_tests.cc + test/core/end2end/fixtures/http_proxy_fixture.cc + test/core/end2end/fixtures/local_util.cc + test/core/end2end/fixtures/proxy.cc + test/core/end2end/tests/http2_stats.cc + test/core/event_engine/event_engine_test_utils.cc + test/core/util/test_lb_policies.cc +) +target_compile_features(http2_stats_test PUBLIC cxx_std_14) +target_include_directories(http2_stats_test + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + third_party/googletest/googletest/include + third_party/googletest/googletest + third_party/googletest/googlemock/include + third_party/googletest/googlemock + ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(http2_stats_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + grpc_authorization_provider + grpc_unsecure + grpc_test_util +) + + endif() if(gRPC_BUILD_TESTS) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 8fb45ae1351..bb72ff4450b 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -9898,6 +9898,42 @@ targets: deps: - grpc++_test_config - grpc++_test_util +- name: http2_stats_test + gtest: true + build: test + language: c++ + headers: + - test/core/end2end/cq_verifier.h + - test/core/end2end/end2end_tests.h + - test/core/end2end/fixtures/h2_oauth2_common.h + - test/core/end2end/fixtures/h2_ssl_cred_reload_fixture.h + - test/core/end2end/fixtures/h2_ssl_tls_common.h + - test/core/end2end/fixtures/h2_tls_common.h + - test/core/end2end/fixtures/http_proxy_fixture.h + - test/core/end2end/fixtures/inproc_fixture.h + - test/core/end2end/fixtures/local_util.h + - test/core/end2end/fixtures/proxy.h + - test/core/end2end/fixtures/secure_fixture.h + - test/core/end2end/fixtures/sockpair_fixture.h + - test/core/end2end/tests/cancel_test_helpers.h + - test/core/event_engine/event_engine_test_utils.h + - test/core/util/test_lb_policies.h + src: + - test/core/end2end/cq_verifier.cc + - test/core/end2end/end2end_test_main.cc + - test/core/end2end/end2end_test_suites.cc + - test/core/end2end/end2end_tests.cc + - test/core/end2end/fixtures/http_proxy_fixture.cc + - test/core/end2end/fixtures/local_util.cc + - test/core/end2end/fixtures/proxy.cc + - test/core/end2end/tests/http2_stats.cc + - test/core/event_engine/event_engine_test_utils.cc + - test/core/util/test_lb_policies.cc + deps: + - gtest + - grpc_authorization_provider + - grpc_unsecure + - grpc_test_util - name: http_proxy_mapper_test gtest: true build: test diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index ebfecb9153a..86753e7724c 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -1597,6 +1597,11 @@ static void perform_stream_op_locked(void* stream_op, frame_hdr[3] = static_cast(len >> 8); frame_hdr[4] = static_cast(len); + if (grpc_core::IsHttp2StatsFixEnabled()) { + s->stats.outgoing.framing_bytes += GRPC_HEADER_SIZE_IN_BYTES; + s->stats.outgoing.data_bytes += + op_payload->send_message.send_message->Length(); + } s->next_message_end_offset = s->flow_controlled_bytes_written + static_cast(s->flow_controlled_buffer.length) + diff --git a/src/core/ext/transport/chttp2/transport/frame_data.cc b/src/core/ext/transport/chttp2/transport/frame_data.cc index 0cead5912de..e10dea34134 100644 --- a/src/core/ext/transport/chttp2/transport/frame_data.cc +++ b/src/core/ext/transport/chttp2/transport/frame_data.cc @@ -29,6 +29,7 @@ #include #include "src/core/ext/transport/chttp2/transport/internal.h" +#include "src/core/lib/experiments/experiments.h" #include "src/core/lib/gprpp/status_helper.h" #include "src/core/lib/slice/slice.h" #include "src/core/lib/slice/slice_buffer.h" @@ -77,7 +78,9 @@ void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer* inbuf, grpc_slice_buffer_move_first_no_ref(inbuf, write_bytes, outbuf); stats->framing_bytes += header_size; - stats->data_bytes += write_bytes; + if (!grpc_core::IsHttp2StatsFixEnabled()) { + stats->data_bytes += write_bytes; + } } grpc_core::Poll grpc_deframe_unprocessed_incoming_frames( diff --git a/src/core/lib/experiments/experiments.cc b/src/core/lib/experiments/experiments.cc index 373b942aa0e..8f7ca123ebf 100644 --- a/src/core/lib/experiments/experiments.cc +++ b/src/core/lib/experiments/experiments.cc @@ -62,6 +62,9 @@ const char* const additional_constraints_event_engine_listener = "{}"; const char* const description_free_large_allocator = "If set, return all free bytes from a \042big\042 allocator"; const char* const additional_constraints_free_large_allocator = "{}"; +const char* const description_http2_stats_fix = + "Fix on HTTP2 outgoing data stats reporting"; +const char* const additional_constraints_http2_stats_fix = "{}"; const char* const description_keepalive_fix = "Allows overriding keepalive_permit_without_calls. Refer " "https://github.com/grpc/grpc/pull/33428 for more information."; @@ -227,6 +230,8 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_event_engine_listener, false, true}, {"free_large_allocator", description_free_large_allocator, additional_constraints_free_large_allocator, false, true}, + {"http2_stats_fix", description_http2_stats_fix, + additional_constraints_http2_stats_fix, true, true}, {"keepalive_fix", description_keepalive_fix, additional_constraints_keepalive_fix, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, @@ -343,6 +348,9 @@ const char* const additional_constraints_event_engine_listener = "{}"; const char* const description_free_large_allocator = "If set, return all free bytes from a \042big\042 allocator"; const char* const additional_constraints_free_large_allocator = "{}"; +const char* const description_http2_stats_fix = + "Fix on HTTP2 outgoing data stats reporting"; +const char* const additional_constraints_http2_stats_fix = "{}"; const char* const description_keepalive_fix = "Allows overriding keepalive_permit_without_calls. Refer " "https://github.com/grpc/grpc/pull/33428 for more information."; @@ -508,6 +516,8 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_event_engine_listener, true, true}, {"free_large_allocator", description_free_large_allocator, additional_constraints_free_large_allocator, false, true}, + {"http2_stats_fix", description_http2_stats_fix, + additional_constraints_http2_stats_fix, true, true}, {"keepalive_fix", description_keepalive_fix, additional_constraints_keepalive_fix, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, @@ -624,6 +634,9 @@ const char* const additional_constraints_event_engine_listener = "{}"; const char* const description_free_large_allocator = "If set, return all free bytes from a \042big\042 allocator"; const char* const additional_constraints_free_large_allocator = "{}"; +const char* const description_http2_stats_fix = + "Fix on HTTP2 outgoing data stats reporting"; +const char* const additional_constraints_http2_stats_fix = "{}"; const char* const description_keepalive_fix = "Allows overriding keepalive_permit_without_calls. Refer " "https://github.com/grpc/grpc/pull/33428 for more information."; @@ -789,6 +802,8 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_event_engine_listener, true, true}, {"free_large_allocator", description_free_large_allocator, additional_constraints_free_large_allocator, false, true}, + {"http2_stats_fix", description_http2_stats_fix, + additional_constraints_http2_stats_fix, true, true}, {"keepalive_fix", description_keepalive_fix, additional_constraints_keepalive_fix, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, diff --git a/src/core/lib/experiments/experiments.h b/src/core/lib/experiments/experiments.h index d79cb83891b..f8d644ec6ac 100644 --- a/src/core/lib/experiments/experiments.h +++ b/src/core/lib/experiments/experiments.h @@ -83,6 +83,8 @@ inline bool IsEventEngineClientEnabled() { return false; } inline bool IsEventEngineDnsEnabled() { return false; } inline bool IsEventEngineListenerEnabled() { return false; } inline bool IsFreeLargeAllocatorEnabled() { return false; } +#define GRPC_EXPERIMENT_IS_INCLUDED_HTTP2_STATS_FIX +inline bool IsHttp2StatsFixEnabled() { return true; } inline bool IsKeepaliveFixEnabled() { return false; } inline bool IsKeepaliveServerFixEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_LAZIER_STREAM_UPDATES @@ -159,6 +161,8 @@ inline bool IsEventEngineDnsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_LISTENER inline bool IsEventEngineListenerEnabled() { return true; } inline bool IsFreeLargeAllocatorEnabled() { return false; } +#define GRPC_EXPERIMENT_IS_INCLUDED_HTTP2_STATS_FIX +inline bool IsHttp2StatsFixEnabled() { return true; } inline bool IsKeepaliveFixEnabled() { return false; } inline bool IsKeepaliveServerFixEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_LAZIER_STREAM_UPDATES @@ -235,6 +239,8 @@ inline bool IsEventEngineDnsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_LISTENER inline bool IsEventEngineListenerEnabled() { return true; } inline bool IsFreeLargeAllocatorEnabled() { return false; } +#define GRPC_EXPERIMENT_IS_INCLUDED_HTTP2_STATS_FIX +inline bool IsHttp2StatsFixEnabled() { return true; } inline bool IsKeepaliveFixEnabled() { return false; } inline bool IsKeepaliveServerFixEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_LAZIER_STREAM_UPDATES @@ -298,6 +304,7 @@ enum ExperimentIds { kExperimentIdEventEngineDns, kExperimentIdEventEngineListener, kExperimentIdFreeLargeAllocator, + kExperimentIdHttp2StatsFix, kExperimentIdKeepaliveFix, kExperimentIdKeepaliveServerFix, kExperimentIdLazierStreamUpdates, @@ -382,6 +389,10 @@ inline bool IsEventEngineListenerEnabled() { inline bool IsFreeLargeAllocatorEnabled() { return IsExperimentEnabled(kExperimentIdFreeLargeAllocator); } +#define GRPC_EXPERIMENT_IS_INCLUDED_HTTP2_STATS_FIX +inline bool IsHttp2StatsFixEnabled() { + return IsExperimentEnabled(kExperimentIdHttp2StatsFix); +} #define GRPC_EXPERIMENT_IS_INCLUDED_KEEPALIVE_FIX inline bool IsKeepaliveFixEnabled() { return IsExperimentEnabled(kExperimentIdKeepaliveFix); diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml index bd69ff1a2d3..90d4a34cde8 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -105,6 +105,12 @@ expiry: 2023/11/01 owner: alishananda@google.com test_tags: [resource_quota_test] +- name: http2_stats_fix + description: + Fix on HTTP2 outgoing data stats reporting + expiry: 2024/03/31 + owner: yashkt@google.com + test_tags: [] - name: keepalive_fix description: Allows overriding keepalive_permit_without_calls. diff --git a/src/core/lib/experiments/rollouts.yaml b/src/core/lib/experiments/rollouts.yaml index ff25659a17a..5aa0c8f6b34 100644 --- a/src/core/lib/experiments/rollouts.yaml +++ b/src/core/lib/experiments/rollouts.yaml @@ -76,6 +76,8 @@ windows: true - name: free_large_allocator default: false +- name: http2_stats_fix + default: true - name: jitter_max_idle default: true - name: keepalive_fix diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD index cacd755bef7..0a8dd6146d9 100644 --- a/test/core/end2end/BUILD +++ b/test/core/end2end/BUILD @@ -318,6 +318,8 @@ grpc_core_end2end_test( shard_count = 50, ) +grpc_core_end2end_test(name = "http2_stats") + grpc_core_end2end_test(name = "invoke_large_request") grpc_core_end2end_test(name = "keepalive_timeout") diff --git a/test/core/end2end/end2end_test_corpus/http2_stats/empty b/test/core/end2end/end2end_test_corpus/http2_stats/empty new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/core/end2end/end2end_test_suites.cc b/test/core/end2end/end2end_test_suites.cc index c19ce955beb..a4ddc9eb286 100644 --- a/test/core/end2end/end2end_test_suites.cc +++ b/test/core/end2end/end2end_test_suites.cc @@ -1061,6 +1061,14 @@ CORE_END2END_TEST_SUITE( FEATURE_MASK_ENABLES_TRACES) .Run()); +CORE_END2END_TEST_SUITE( + Http2FullstackSingleHopTest, + ConfigQuery() + .EnforceFeatures(FEATURE_MASK_IS_HTTP2) + .EnforceFeatures(FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL) + .ExcludeFeatures(FEATURE_MASK_SUPPORTS_REQUEST_PROXYING) + .Run()); + CORE_END2END_TEST_SUITE( RetryTest, ConfigQuery() .EnforceFeatures(FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL) diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h index 436b0527bf3..af5da973eca 100644 --- a/test/core/end2end/end2end_tests.h +++ b/test/core/end2end/end2end_tests.h @@ -793,6 +793,8 @@ class CoreDeadlineTest : public CoreEnd2endTest {}; class CoreDeadlineSingleHopTest : public CoreEnd2endTest {}; // Test suite for http2 tests that only work over a single hop (unproxyable) class Http2SingleHopTest : public CoreEnd2endTest {}; +// Test suite for fullstack single hop http2 tests (require client channel) +class Http2FullstackSingleHopTest : public CoreEnd2endTest {}; // Test suite for tests that require retry features class RetryTest : public CoreEnd2endTest {}; // Test suite for write buffering diff --git a/test/core/end2end/tests/http2_stats.cc b/test/core/end2end/tests/http2_stats.cc new file mode 100644 index 00000000000..9d43bccf7f5 --- /dev/null +++ b/test/core/end2end/tests/http2_stats.cc @@ -0,0 +1,257 @@ +// Copyright 2023 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "gtest/gtest.h" + +#include +#include +#include + +#include "src/core/lib/channel/call_tracer.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_fwd.h" +#include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/channel/context.h" +#include "src/core/lib/channel/promise_based_filter.h" +#include "src/core/lib/config/core_configuration.h" +#include "src/core/lib/gprpp/sync.h" +#include "src/core/lib/gprpp/time.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/promise/arena_promise.h" +#include "src/core/lib/promise/context.h" +#include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/slice/slice.h" +#include "src/core/lib/slice/slice_buffer.h" +#include "src/core/lib/surface/channel_stack_type.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/lib/transport/transport.h" +#include "test/core/end2end/end2end_tests.h" + +namespace grpc_core { +namespace { + +Mutex* g_mu; + +class FakeCallTracer : public ClientCallTracer { + public: + class FakeCallAttemptTracer : public CallAttemptTracer { + public: + std::string TraceId() override { return ""; } + std::string SpanId() override { return ""; } + bool IsSampled() override { return false; } + void RecordSendInitialMetadata( + grpc_metadata_batch* /*send_initial_metadata*/) override {} + void RecordSendTrailingMetadata( + grpc_metadata_batch* /*send_trailing_metadata*/) override {} + void RecordSendMessage(const SliceBuffer& /*send_message*/) override {} + void RecordSendCompressedMessage( + const SliceBuffer& /*send_compressed_message*/) override {} + void RecordReceivedInitialMetadata( + grpc_metadata_batch* /*recv_initial_metadata*/) override {} + void RecordReceivedMessage(const SliceBuffer& /*recv_message*/) override {} + void RecordReceivedDecompressedMessage( + const SliceBuffer& /*recv_decompressed_message*/) override {} + + void RecordReceivedTrailingMetadata( + absl::Status /*status*/, + grpc_metadata_batch* /*recv_trailing_metadata*/, + const grpc_transport_stream_stats* transport_stream_stats) override { + MutexLock lock(g_mu); + transport_stream_stats_ = *transport_stream_stats; + } + + void RecordCancel(grpc_error_handle /*cancel_error*/) override {} + void RecordEnd(const gpr_timespec& /*latency*/) override { delete this; } + void RecordAnnotation(absl::string_view /*annotation*/) override {} + void RecordAnnotation(const Annotation& /*annotation*/) override {} + + static grpc_transport_stream_stats transport_stream_stats() { + MutexLock lock(g_mu); + return transport_stream_stats_; + } + + private: + static grpc_transport_stream_stats transport_stream_stats_ + ABSL_GUARDED_BY(g_mu); + }; + + explicit FakeCallTracer() {} + ~FakeCallTracer() override {} + std::string TraceId() override { return ""; } + std::string SpanId() override { return ""; } + bool IsSampled() override { return false; } + + FakeCallAttemptTracer* StartNewAttempt( + bool /*is_transparent_retry*/) override { + return new FakeCallAttemptTracer; + } + + void RecordAnnotation(absl::string_view /*annotation*/) override {} + void RecordAnnotation(const Annotation& /*annotation*/) override {} +}; + +grpc_transport_stream_stats + FakeCallTracer::FakeCallAttemptTracer::transport_stream_stats_; + +class FakeClientFilter : public ChannelFilter { + public: + static const grpc_channel_filter kFilter; + + static absl::StatusOr Create( + const ChannelArgs& /*args*/, ChannelFilter::Args /*filter_args*/) { + return FakeClientFilter(); + } + + ArenaPromise MakeCallPromise( + CallArgs call_args, NextPromiseFactory next_promise_factory) override { + auto* call_context = GetContext(); + auto* tracer = GetContext()->ManagedNew(); + GPR_DEBUG_ASSERT( + call_context[GRPC_CONTEXT_CALL_TRACER_ANNOTATION_INTERFACE].value == + nullptr); + call_context[GRPC_CONTEXT_CALL_TRACER_ANNOTATION_INTERFACE].value = tracer; + call_context[GRPC_CONTEXT_CALL_TRACER_ANNOTATION_INTERFACE].destroy = + nullptr; + return next_promise_factory(std::move(call_args)); + } +}; + +const grpc_channel_filter FakeClientFilter::kFilter = + MakePromiseBasedFilter( + "fake_client"); + +class FakeServerCallTracer : public ServerCallTracer { + public: + ~FakeServerCallTracer() override {} + void RecordSendInitialMetadata( + grpc_metadata_batch* /*send_initial_metadata*/) override {} + void RecordSendTrailingMetadata( + grpc_metadata_batch* /*send_trailing_metadata*/) override {} + void RecordSendMessage(const SliceBuffer& /*send_message*/) override {} + void RecordSendCompressedMessage( + const SliceBuffer& /*send_compressed_message*/) override {} + void RecordReceivedInitialMetadata( + grpc_metadata_batch* /*recv_initial_metadata*/) override {} + void RecordReceivedMessage(const SliceBuffer& /*recv_message*/) override {} + void RecordReceivedDecompressedMessage( + const SliceBuffer& /*recv_decompressed_message*/) override {} + void RecordCancel(grpc_error_handle /*cancel_error*/) override {} + void RecordReceivedTrailingMetadata( + grpc_metadata_batch* /*recv_trailing_metadata*/) override {} + + void RecordEnd(const grpc_call_final_info* final_info) override { + MutexLock lock(g_mu); + transport_stream_stats_ = final_info->stats.transport_stream_stats; + } + + void RecordAnnotation(absl::string_view /*annotation*/) override {} + void RecordAnnotation(const Annotation& /*annotation*/) override {} + std::string TraceId() override { return ""; } + std::string SpanId() override { return ""; } + bool IsSampled() override { return false; } + + static grpc_transport_stream_stats transport_stream_stats() { + MutexLock lock(g_mu); + return transport_stream_stats_; + } + + private: + static grpc_transport_stream_stats transport_stream_stats_ + ABSL_GUARDED_BY(g_mu); +}; + +grpc_transport_stream_stats FakeServerCallTracer::transport_stream_stats_; + +class FakeServerCallTracerFactory : public ServerCallTracerFactory { + public: + ServerCallTracer* CreateNewServerCallTracer(Arena* arena) override { + return arena->ManagedNew(); + } +}; + +// This test verifies the HTTP2 stats on a stream +CORE_END2END_TEST(Http2FullstackSingleHopTest, StreamStats) { + g_mu = new Mutex(); + CoreConfiguration::RegisterBuilder([](CoreConfiguration::Builder* builder) { + builder->channel_init()->RegisterFilter(GRPC_CLIENT_CHANNEL, + &FakeClientFilter::kFilter); + }); + ServerCallTracerFactory::RegisterGlobal(new FakeServerCallTracerFactory); + + auto send_from_client = RandomSlice(10); + auto send_from_server = RandomSlice(20); + CoreEnd2endTest::IncomingStatusOnClient server_status; + CoreEnd2endTest::IncomingMetadata server_initial_metadata; + CoreEnd2endTest::IncomingMessage server_message; + CoreEnd2endTest::IncomingMessage client_message; + CoreEnd2endTest::IncomingCloseOnServer client_close; + { + auto c = NewClientCall("/foo").Timeout(Duration::Minutes(5)).Create(); + c.NewBatch(1) + .SendInitialMetadata({}) + .SendMessage(send_from_client.Ref()) + .SendCloseFromClient() + .RecvInitialMetadata(server_initial_metadata) + .RecvMessage(server_message) + .RecvStatusOnClient(server_status); + auto s = RequestCall(101); + Expect(101, true); + Step(Duration::Minutes(1)); + s.NewBatch(102).SendInitialMetadata({}).RecvMessage(client_message); + Expect(102, true); + Step(Duration::Minutes(1)); + s.NewBatch(103) + .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) + .SendMessage(send_from_server.Ref()) + .RecvCloseOnServer(client_close); + Expect(103, true); + Expect(1, true); + Step(Duration::Minutes(1)); + EXPECT_EQ(s.method(), "/foo"); + } + EXPECT_EQ(server_status.status(), GRPC_STATUS_UNIMPLEMENTED); + EXPECT_EQ(server_status.message(), "xyz"); + EXPECT_FALSE(client_close.was_cancelled()); + EXPECT_EQ(client_message.payload(), send_from_client); + EXPECT_EQ(server_message.payload(), send_from_server); + + auto client_transport_stats = + FakeCallTracer::FakeCallAttemptTracer::transport_stream_stats(); + EXPECT_EQ(client_transport_stats.outgoing.data_bytes, + send_from_client.size()); + EXPECT_EQ(client_transport_stats.incoming.data_bytes, + send_from_server.size()); + auto server_transport_stats = FakeServerCallTracer::transport_stream_stats(); + EXPECT_EQ(server_transport_stats.outgoing.data_bytes, + send_from_server.size()); + EXPECT_EQ(server_transport_stats.incoming.data_bytes, + send_from_client.size()); + // TODO(yashykt): Add tests for framing bytes as well + + delete ServerCallTracerFactory::Get(ChannelArgs()); + ServerCallTracerFactory::RegisterGlobal(nullptr); + delete g_mu; + g_mu = nullptr; +} + +} // namespace +} // namespace grpc_core diff --git a/test/cpp/ext/otel/BUILD b/test/cpp/ext/otel/BUILD index 284aece49d6..8fa212f585c 100644 --- a/test/cpp/ext/otel/BUILD +++ b/test/cpp/ext/otel/BUILD @@ -57,8 +57,7 @@ grpc_cc_test( "otel/sdk/src/metrics", ], language = "C++", - tags = [ - ], + tags = [], deps = [ ":otel_test_library", "//:grpc++", diff --git a/test/cpp/ext/otel/otel_plugin_test.cc b/test/cpp/ext/otel/otel_plugin_test.cc index e27fcbd3443..19654c28d6b 100644 --- a/test/cpp/ext/otel/otel_plugin_test.cc +++ b/test/cpp/ext/otel/otel_plugin_test.cc @@ -121,6 +121,7 @@ TEST_F(OTelPluginEnd2EndTest, ClientAttemptSentTotalCompressedMessageSize) { &data[kMetricName][0].point_data); ASSERT_NE(point_data, nullptr); ASSERT_EQ(point_data->count_, 1); + ASSERT_EQ(absl::get(point_data->max_), 5); const auto& attributes = data[kMetricName][0].attributes.GetAttributes(); EXPECT_EQ(attributes.size(), 3); const auto* method_value = @@ -154,6 +155,7 @@ TEST_F(OTelPluginEnd2EndTest, ClientAttemptRcvdTotalCompressedMessageSize) { &data[kMetricName][0].point_data); ASSERT_NE(point_data, nullptr); ASSERT_EQ(point_data->count_, 1); + ASSERT_EQ(absl::get(point_data->max_), 5); const auto& attributes = data[kMetricName][0].attributes.GetAttributes(); EXPECT_EQ(attributes.size(), 3); const auto* method_value = @@ -238,6 +240,7 @@ TEST_F(OTelPluginEnd2EndTest, ServerCallSentTotalCompressedMessageSize) { &data[kMetricName][0].point_data); ASSERT_NE(point_data, nullptr); EXPECT_EQ(point_data->count_, 1); + ASSERT_EQ(absl::get(point_data->max_), 5); const auto& attributes = data[kMetricName][0].attributes.GetAttributes(); EXPECT_EQ(attributes.size(), 2); const auto* method_value = @@ -267,6 +270,7 @@ TEST_F(OTelPluginEnd2EndTest, ServerCallRcvdTotalCompressedMessageSize) { &data[kMetricName][0].point_data); ASSERT_NE(point_data, nullptr); ASSERT_EQ(point_data->count_, 1); + ASSERT_EQ(absl::get(point_data->max_), 5); const auto& attributes = data[kMetricName][0].attributes.GetAttributes(); EXPECT_EQ(attributes.size(), 2); const auto* method_value = diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index c35ba3e2033..4268a4b3a15 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -4657,6 +4657,30 @@ ], "uses_polling": true }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "http2_stats_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": true + }, { "args": [], "benchmark": false,