@@ -34,18 +34,41 @@ namespace {
3434using ReadResponse =
3535 ::google::cloud::storage_experimental::AsyncReaderConnection::ReadResponse;
3636using ::google::cloud::storage_experimental::ObjectDescriptorConnection;
37+ using ::google::cloud::storage_experimental::ReadPayload;
3738using ::google::cloud::storage_mocks::MockAsyncObjectDescriptorConnection;
3839using ::google::cloud::storage_mocks::MockAsyncReaderConnection;
3940using ::google::cloud::testing_util::EventNamed;
4041using ::google::cloud::testing_util::InstallSpanCatcher;
4142using ::google::cloud::testing_util::OTelAttribute;
43+ using ::google::cloud::testing_util::OTelContextCaptured;
44+ using ::google::cloud::testing_util::PromiseWithOTelContext;
4245using ::google::cloud::testing_util::SpanEventAttributesAre;
4346using ::google::cloud::testing_util::SpanHasInstrumentationScope;
4447using ::google::cloud::testing_util::SpanKindIsClient;
4548using ::google::cloud::testing_util::SpanNamed;
4649using ::google::cloud::testing_util::SpanWithStatus;
50+ using ::google::cloud::testing_util::ThereIsAnActiveSpan;
4751using ::testing::_;
4852
53+ // A helper to set expectations on a mock async reader. It captures the OTel
54+ // context and returns a future that can be controlled by the test.
55+ auto expect_context = [](auto & p) {
56+ return [&p] {
57+ EXPECT_TRUE (ThereIsAnActiveSpan ());
58+ EXPECT_TRUE (OTelContextCaptured ());
59+ return p.get_future ();
60+ };
61+ };
62+
63+ // A helper to be used in a `.then()` clause. It verifies the OTel context
64+ // has been detached before the user receives the result.
65+ auto expect_no_context = [](auto f) {
66+ auto t = f.get ();
67+ EXPECT_FALSE (ThereIsAnActiveSpan ());
68+ EXPECT_FALSE (OTelContextCaptured ());
69+ return t;
70+ };
71+
4972TEST (ObjectDescriptorConnectionTracing, Read) {
5073 namespace sc = ::opentelemetry::trace::SemanticConventions;
5174 auto span_catcher = InstallSpanCatcher ();
@@ -76,6 +99,55 @@ TEST(ObjectDescriptorConnectionTracing, Read) {
7699 OTelAttribute<std::string>(sc::kThreadId , _)))))));
77100}
78101
102+ TEST (ObjectDescriptorConnectionTracing, ReadThenRead) {
103+ namespace sc = ::opentelemetry::trace::SemanticConventions;
104+ auto span_catcher = InstallSpanCatcher ();
105+
106+ auto mock_connection =
107+ std::make_shared<MockAsyncObjectDescriptorConnection>();
108+ auto * mock_reader_ptr = new MockAsyncReaderConnection;
109+ PromiseWithOTelContext<ReadResponse> p;
110+ EXPECT_CALL (*mock_reader_ptr, Read).WillOnce (expect_context (p));
111+
112+ EXPECT_CALL (*mock_connection, Read)
113+ .WillOnce ([&](ObjectDescriptorConnection::ReadParams) {
114+ return std::unique_ptr<storage_experimental::AsyncReaderConnection>(
115+ mock_reader_ptr);
116+ });
117+
118+ auto connection = MakeTracingObjectDescriptorConnection (
119+ internal::MakeSpan (" test-span" ), std::move (mock_connection));
120+
121+ auto reader = connection->Read ({});
122+ auto f = reader->Read ().then (expect_no_context);
123+ p.set_value (ReadPayload (" test-payload" ).set_offset (123 ));
124+ (void )f.get ();
125+
126+ connection.reset (); // End the span
127+
128+ auto spans = span_catcher->GetSpans ();
129+ EXPECT_THAT (
130+ spans, ElementsAre (AllOf (
131+ SpanNamed (" test-span" ),
132+ SpanWithStatus (opentelemetry::trace::StatusCode::kOk ),
133+ SpanHasInstrumentationScope (), SpanKindIsClient (),
134+ SpanEventsAre (
135+ AllOf (EventNamed (" gl-cpp.open.read" ),
136+ SpanEventAttributesAre (
137+ OTelAttribute<std::int64_t >(" read-length" , 0 ),
138+ OTelAttribute<std::int64_t >(" read-start" , 0 ),
139+ OTelAttribute<std::string>(sc::kThreadId , _))),
140+ AllOf (EventNamed (" gl-cpp.read" ),
141+ SpanEventAttributesAre (
142+ OTelAttribute<std::int64_t >(
143+ " message.starting_offset" , 123 ),
144+ OTelAttribute<std::string>(sc::kThreadId , _),
145+ OTelAttribute<std::int64_t >(" rpc.message.id" , 1 ),
146+ // THIS WAS THE MISSING ATTRIBUTE:
147+ OTelAttribute<std::string>(" rpc.message.type" ,
148+ " RECEIVED" )))))));
149+ }
150+
79151} // namespace
80152GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
81153} // namespace storage_internal
0 commit comments