// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 #include #include "gtest/gtest.h" #ifdef ENABLE_OTLP_RETRY_PREVIEW # include # include "gmock/gmock.h" #endif // ENABLE_OTLP_RETRY_PREVIEW #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "opentelemetry/ext//http/client/curl/http_client_curl.h" #include "opentelemetry/ext/http/client/curl/http_operation_curl.h" #include "opentelemetry/ext/http/client/http_client.h" #include "opentelemetry/ext/http/client/http_client_factory.h" #include "opentelemetry/ext/http/server/http_server.h" #include "opentelemetry/nostd/function_ref.h" #include "opentelemetry/nostd/string_view.h" #define HTTP_PORT 19000 namespace curl = opentelemetry::ext::http::client::curl; namespace http_client = opentelemetry::ext::http::client; namespace nostd = opentelemetry::nostd; class CustomEventHandler : public http_client::EventHandler { public: void OnResponse(http_client::Response & /* response */) noexcept override { got_response_.store(true, std::memory_order_release); } void OnEvent(http_client::SessionState state, nostd::string_view /* reason */) noexcept override { switch (state) { case http_client::SessionState::ConnectFailed: case http_client::SessionState::SendFailed: { is_called_.store(true, std::memory_order_release); break; } default: break; } } CustomEventHandler() : is_called_(false), got_response_(false) {} ~CustomEventHandler() override = default; std::atomic is_called_; std::atomic got_response_; }; class GetEventHandler : public CustomEventHandler { void OnResponse(http_client::Response &response) noexcept override { ASSERT_EQ(200, response.GetStatusCode()); ASSERT_EQ(response.GetBody().size(), 0); is_called_.store(true, std::memory_order_release); got_response_.store(true, std::memory_order_release); } }; class PostEventHandler : public CustomEventHandler { void OnResponse(http_client::Response &response) noexcept override { ASSERT_EQ(200, response.GetStatusCode()); std::string body(response.GetBody().begin(), response.GetBody().end()); ASSERT_EQ(body, "{'k1':'v1', 'k2':'v2', 'k3':'v3'}"); is_called_.store(true, std::memory_order_release); got_response_.store(true, std::memory_order_release); } }; class FinishInCallbackHandler : public CustomEventHandler { public: FinishInCallbackHandler(std::shared_ptr session) : session_(std::move(session)) {} void OnResponse(http_client::Response &response) noexcept override { ASSERT_EQ(200, response.GetStatusCode()); ASSERT_EQ(response.GetBody().size(), 0); is_called_.store(true, std::memory_order_release); got_response_.store(true, std::memory_order_release); if (session_) { session_->FinishSession(); session_.reset(); } } private: std::shared_ptr session_; }; class RetryEventHandler : public CustomEventHandler { void OnResponse(http_client::Response &response) noexcept override { ASSERT_EQ(429, response.GetStatusCode()); ASSERT_EQ(response.GetBody().size(), 0); is_called_.store(true, std::memory_order_release); got_response_.store(true, std::memory_order_release); } }; class BasicCurlHttpTests : public ::testing::Test, public HTTP_SERVER_NS::HttpRequestCallback { protected: HTTP_SERVER_NS::HttpServer server_; std::string server_address_; std::atomic is_setup_{false}; std::atomic is_running_{false}; std::vector received_requests_; std::mutex cv_mtx_requests; std::mutex mtx_requests; std::condition_variable cv_got_events; std::mutex cv_m; public: BasicCurlHttpTests() : is_setup_(false), is_running_(false) {} void SetUp() override { if (is_setup_.exchange(true)) { return; } int port = server_.addListeningPort(HTTP_PORT); std::ostringstream os; os << "localhost:" << port; server_address_ = "http://" + os.str() + "/simple/"; server_.setServerName(os.str()); server_.setKeepalive(false); server_.addHandler("/simple/", *this); server_.addHandler("/get/", *this); server_.addHandler("/post/", *this); server_.addHandler("/retry/", *this); server_.start(); is_running_ = true; } void TearDown() override { if (!is_setup_.exchange(false)) return; server_.stop(); is_running_ = false; } int onHttpRequest(HTTP_SERVER_NS::HttpRequest const &request, HTTP_SERVER_NS::HttpResponse &response) override { int response_status = 404; if (request.uri == "/get/") { std::unique_lock lk1(mtx_requests); received_requests_.push_back(request); response.headers["Content-Type"] = "text/plain"; response_status = 200; } else if (request.uri == "/post/") { std::unique_lock lk1(mtx_requests); received_requests_.push_back(request); response.headers["Content-Type"] = "application/json"; response.body = "{'k1':'v1', 'k2':'v2', 'k3':'v3'}"; response_status = 200; } else if (request.uri == "/retry/") { std::unique_lock lk1(mtx_requests); received_requests_.push_back(request); response.headers["Content-Type"] = "text/plain"; response_status = 429; } cv_got_events.notify_one(); return response_status; } bool waitForRequests(unsigned timeOutSec, unsigned expected_count = 1) { std::unique_lock lk(cv_mtx_requests); if (cv_got_events.wait_for(lk, std::chrono::milliseconds(1000 * timeOutSec), [&] { std::unique_lock lk1(mtx_requests); return received_requests_.size() >= expected_count; })) { return true; } return false; } }; TEST_F(BasicCurlHttpTests, DoNothing) {} TEST_F(BasicCurlHttpTests, HttpRequest) { curl::Request req; const char *b = "test-data"; http_client::Body body = {b, b + strlen(b)}; http_client::Body body1 = body; req.SetBody(body); ASSERT_EQ(req.body_, body1); req.AddHeader("name1", "value1"); req.AddHeader("name2", "value2"); ASSERT_TRUE(req.headers_.find("name1")->second == "value1"); ASSERT_TRUE(req.headers_.find("name2")->second == "value2"); req.ReplaceHeader("name1", "value3"); ASSERT_EQ(req.headers_.find("name1")->second, "value3"); req.SetTimeoutMs(std::chrono::duration(2000)); ASSERT_EQ(req.timeout_ms_, std::chrono::duration(2000)); } TEST_F(BasicCurlHttpTests, HttpResponse) { curl::Response res; http_client::Headers m1 = { {"name1", "value1_1"}, {"name1", "value1_2"}, {"name2", "value3"}, {"name3", "value3"}}; res.headers_ = m1; const char *b = "test-data"; http_client::Body body = {b, b + strlen(b)}; int count = 0; res.ForEachHeader("name1", [&count](nostd::string_view name, nostd::string_view value) { if (name != "name1") return false; if (value != "value1_1" && value != "value1_2") return false; count++; return true; }); ASSERT_EQ(count, 2); count = 0; res.ForEachHeader([&count](nostd::string_view name, nostd::string_view value) { if (name != "name1" && name != "name2" && name != "name3") return false; if (value != "value1_1" && value != "value1_2" && value != "value2" && value != "value3") return false; count++; return true; }); ASSERT_EQ(count, 4); } TEST_F(BasicCurlHttpTests, SendGetRequest) { received_requests_.clear(); auto session_manager = http_client::HttpClientFactory::Create(); EXPECT_TRUE(session_manager != nullptr); auto session = session_manager->CreateSession("http://127.0.0.1:19000"); auto request = session->CreateRequest(); request->SetUri("get/"); auto handler = std::make_shared(); session->SendRequest(handler); ASSERT_TRUE(waitForRequests(30, 1)); session->FinishSession(); ASSERT_TRUE(handler->is_called_.load(std::memory_order_acquire)); ASSERT_TRUE(handler->got_response_.load(std::memory_order_acquire)); } TEST_F(BasicCurlHttpTests, SendPostRequest) { received_requests_.clear(); auto session_manager = http_client::HttpClientFactory::Create(); EXPECT_TRUE(session_manager != nullptr); auto session = session_manager->CreateSession("http://127.0.0.1:19000"); auto request = session->CreateRequest(); request->SetUri("post/"); request->SetMethod(http_client::Method::Post); const char *b = "test-data"; http_client::Body body = {b, b + strlen(b)}; request->SetBody(body); request->AddHeader("Content-Type", "text/plain"); auto handler = std::make_shared(); session->SendRequest(handler); ASSERT_TRUE(waitForRequests(30, 1)); session->FinishSession(); ASSERT_TRUE(handler->is_called_.load(std::memory_order_acquire)); ASSERT_TRUE(handler->got_response_.load(std::memory_order_acquire)); session_manager->CancelAllSessions(); session_manager->FinishAllSessions(); } TEST_F(BasicCurlHttpTests, RequestTimeout) { received_requests_.clear(); auto session_manager = http_client::HttpClientFactory::Create(); EXPECT_TRUE(session_manager != nullptr); auto session = session_manager->CreateSession("222.222.222.200:19000"); // Non Existing address auto request = session->CreateRequest(); request->SetUri("get/"); auto handler = std::make_shared(); session->SendRequest(handler); session->FinishSession(); ASSERT_TRUE(handler->is_called_.load(std::memory_order_acquire)); ASSERT_FALSE(handler->got_response_.load(std::memory_order_acquire)); } TEST_F(BasicCurlHttpTests, CurlHttpOperations) { http_client::HttpSslOptions no_ssl; GetEventHandler *handler = new GetEventHandler(); const char *b = "test-data"; http_client::Body body = {b, b + strlen(b)}; http_client::Headers headers = { {"name1", "value1_1"}, {"name1", "value1_2"}, {"name2", "value3"}, {"name3", "value3"}}; http_client::Compression compression = http_client::Compression::kNone; curl::HttpOperation http_operations1(http_client::Method::Head, "/get", no_ssl, handler, headers, body, compression, true); http_operations1.Send(); curl::HttpOperation http_operations2(http_client::Method::Get, "/get", no_ssl, handler, headers, body, compression, true); http_operations2.Send(); curl::HttpOperation http_operations3(http_client::Method::Get, "/get", no_ssl, handler, headers, body, compression, false); http_operations3.Send(); delete handler; } #ifdef ENABLE_OTLP_RETRY_PREVIEW TEST_F(BasicCurlHttpTests, RetryPolicyEnabled) { RetryEventHandler handler; http_client::HttpSslOptions no_ssl; http_client::Body body; http_client::Headers headers; http_client::Compression compression = http_client::Compression::kNone; http_client::RetryPolicy retry_policy = {5, std::chrono::duration{1.0f}, std::chrono::duration{5.0f}, 1.5f}; curl::HttpOperation operation(http_client::Method::Post, "http://127.0.0.1:19000/retry/", no_ssl, &handler, headers, body, compression, false, curl::kDefaultHttpConnTimeout, false, false, retry_policy); ASSERT_EQ(CURLE_OK, operation.Send()); ASSERT_TRUE(operation.IsRetryable()); } TEST_F(BasicCurlHttpTests, RetryPolicyDisabled) { RetryEventHandler handler; http_client::HttpSslOptions no_ssl; http_client::Body body; http_client::Headers headers; http_client::Compression compression = http_client::Compression::kNone; http_client::RetryPolicy no_retry_policy = {0, std::chrono::duration::zero(), std::chrono::duration::zero(), 0.0f}; curl::HttpOperation operation(http_client::Method::Post, "http://127.0.0.1:19000/retry/", no_ssl, &handler, headers, body, compression, false, curl::kDefaultHttpConnTimeout, false, false, no_retry_policy); ASSERT_EQ(CURLE_OK, operation.Send()); ASSERT_FALSE(operation.IsRetryable()); } TEST_F(BasicCurlHttpTests, ExponentialBackoffRetry) { using ::testing::AllOf; using ::testing::Gt; using ::testing::Lt; RetryEventHandler handler; http_client::HttpSslOptions no_ssl; http_client::Body body; http_client::Headers headers; http_client::Compression compression = http_client::Compression::kNone; http_client::RetryPolicy retry_policy = {4, std::chrono::duration{1.0f}, std::chrono::duration{5.0f}, 2.0f}; curl::HttpOperation operation(http_client::Method::Post, "http://127.0.0.1:19000/retry/", no_ssl, &handler, headers, body, compression, false, curl::kDefaultHttpConnTimeout, false, false, retry_policy); auto first_attempt_time = std::chrono::system_clock::now(); ASSERT_EQ(CURLE_OK, operation.Send()); ASSERT_TRUE(operation.IsRetryable()); ASSERT_THAT( operation.NextRetryTime().time_since_epoch().count(), AllOf(Gt((first_attempt_time + std::chrono::milliseconds{750}).time_since_epoch().count()), Lt((first_attempt_time + std::chrono::milliseconds{1250}).time_since_epoch().count()))); auto second_attempt_time = std::chrono::system_clock::now(); ASSERT_EQ(CURLE_OK, operation.Send()); ASSERT_TRUE(operation.IsRetryable()); ASSERT_THAT( operation.NextRetryTime().time_since_epoch().count(), AllOf( Gt((second_attempt_time + std::chrono::milliseconds{1550}).time_since_epoch().count()), Lt((second_attempt_time + std::chrono::milliseconds{2450}).time_since_epoch().count()))); auto third_attempt_time = std::chrono::system_clock::now(); ASSERT_EQ(CURLE_OK, operation.Send()); ASSERT_TRUE(operation.IsRetryable()); ASSERT_THAT( operation.NextRetryTime().time_since_epoch().count(), AllOf(Gt((third_attempt_time + std::chrono::milliseconds{3150}).time_since_epoch().count()), Lt((third_attempt_time + std::chrono::milliseconds{4850}).time_since_epoch().count()))); ASSERT_EQ(CURLE_OK, operation.Send()); ASSERT_FALSE(operation.IsRetryable()); } #endif // ENABLE_OTLP_RETRY_PREVIEW TEST_F(BasicCurlHttpTests, SendGetRequestSync) { received_requests_.clear(); curl::HttpClientSync http_client; http_client::Headers m1 = {}; auto result = http_client.GetNoSsl("http://127.0.0.1:19000/get/", m1); EXPECT_EQ(result, true); EXPECT_EQ(result.GetSessionState(), http_client::SessionState::Response); } TEST_F(BasicCurlHttpTests, SendGetRequestSyncTimeout) { received_requests_.clear(); curl::HttpClientSync http_client; http_client::Headers m1 = {}; auto result = http_client.GetNoSsl("https://192.0.2.0:19000/get/", m1); EXPECT_EQ(result, false); // When network is under proxy, it may connect success but closed by peer when send data EXPECT_TRUE(result.GetSessionState() == http_client::SessionState::ConnectFailed || result.GetSessionState() == http_client::SessionState::SendFailed); } TEST_F(BasicCurlHttpTests, SendPostRequestSync) { received_requests_.clear(); curl::HttpClientSync http_client; http_client::Headers m1 = {}; http_client::Body body = {}; auto result = http_client.PostNoSsl("http://127.0.0.1:19000/post/", body, m1); EXPECT_EQ(result, true); EXPECT_EQ(result.GetSessionState(), http_client::SessionState::Response); } TEST_F(BasicCurlHttpTests, GetBaseUri) { curl::HttpClient session_manager; auto session = session_manager.CreateSession("127.0.0.1:80"); ASSERT_EQ(std::static_pointer_cast(session)->GetBaseUri(), "http://127.0.0.1:80/"); session = session_manager.CreateSession("https://127.0.0.1:443"); ASSERT_EQ(std::static_pointer_cast(session)->GetBaseUri(), "https://127.0.0.1:443/"); session = session_manager.CreateSession("http://127.0.0.1:31339"); ASSERT_EQ(std::static_pointer_cast(session)->GetBaseUri(), "http://127.0.0.1:31339/"); } TEST_F(BasicCurlHttpTests, SendGetRequestAsync) { curl::HttpClient http_client; for (int round = 0; round < 2; ++round) { received_requests_.clear(); static constexpr const unsigned batch_count = 5; std::shared_ptr sessions[batch_count]; std::shared_ptr handlers[batch_count]; for (unsigned i = 0; i < batch_count; ++i) { sessions[i] = http_client.CreateSession("http://127.0.0.1:19000/get/"); auto request = sessions[i]->CreateRequest(); request->SetMethod(http_client::Method::Get); request->SetUri("get/"); handlers[i] = std::make_shared(); // Lock mtx_requests to prevent response, we will check IsSessionActive() in the end std::unique_lock lock_requests(mtx_requests); sessions[i]->SendRequest(handlers[i]); ASSERT_TRUE(sessions[i]->IsSessionActive()); } ASSERT_TRUE(waitForRequests(30, batch_count)); for (unsigned i = 0; i < batch_count; ++i) { sessions[i]->FinishSession(); ASSERT_FALSE(sessions[i]->IsSessionActive()); ASSERT_TRUE(handlers[i]->is_called_.load(std::memory_order_acquire)); ASSERT_TRUE(handlers[i]->got_response_.load(std::memory_order_acquire)); } http_client.WaitBackgroundThreadExit(); } } TEST_F(BasicCurlHttpTests, SendGetRequestAsyncTimeout) { received_requests_.clear(); curl::HttpClient http_client; static constexpr const unsigned batch_count = 5; std::shared_ptr sessions[batch_count]; std::shared_ptr handlers[batch_count]; for (unsigned i = 0; i < batch_count; ++i) { sessions[i] = http_client.CreateSession("https://192.0.2.0:19000/get/"); auto request = sessions[i]->CreateRequest(); request->SetMethod(http_client::Method::Get); request->SetUri("get/"); request->SetTimeoutMs(std::chrono::milliseconds(256)); handlers[i] = std::make_shared(); // Lock mtx_requests to prevent response, we will check IsSessionActive() in the end std::unique_lock lock_requests(mtx_requests); sessions[i]->SendRequest(handlers[i]); ASSERT_TRUE(sessions[i]->IsSessionActive() || handlers[i]->is_called_.load(std::memory_order_acquire)); } for (unsigned i = 0; i < batch_count; ++i) { sessions[i]->FinishSession(); ASSERT_FALSE(sessions[i]->IsSessionActive()); ASSERT_TRUE(handlers[i]->is_called_.load(std::memory_order_acquire)); ASSERT_FALSE(handlers[i]->got_response_.load(std::memory_order_acquire)); } } TEST_F(BasicCurlHttpTests, SendPostRequestAsync) { curl::HttpClient http_client; for (int round = 0; round < 2; ++round) { received_requests_.clear(); auto handler = std::make_shared(); static constexpr const unsigned batch_count = 5; std::shared_ptr sessions[batch_count]; for (auto &session : sessions) { session = http_client.CreateSession("http://127.0.0.1:19000/post/"); auto request = session->CreateRequest(); request->SetMethod(http_client::Method::Post); request->SetUri("post/"); // Lock mtx_requests to prevent response, we will check IsSessionActive() in the end std::unique_lock lock_requests(mtx_requests); session->SendRequest(handler); ASSERT_TRUE(session->IsSessionActive()); } ASSERT_TRUE(waitForRequests(30, batch_count)); for (auto &session : sessions) { session->FinishSession(); ASSERT_FALSE(session->IsSessionActive()); } ASSERT_TRUE(handler->is_called_.load(std::memory_order_acquire)); ASSERT_TRUE(handler->got_response_.load(std::memory_order_acquire)); http_client.WaitBackgroundThreadExit(); } } TEST_F(BasicCurlHttpTests, FinishInAsyncCallback) { curl::HttpClient http_client; for (int round = 0; round < 2; ++round) { received_requests_.clear(); static constexpr const unsigned batch_count = 5; std::shared_ptr sessions[batch_count]; std::shared_ptr handlers[batch_count]; for (unsigned i = 0; i < batch_count; ++i) { sessions[i] = http_client.CreateSession("http://127.0.0.1:19000/get/"); auto request = sessions[i]->CreateRequest(); request->SetMethod(http_client::Method::Get); request->SetUri("get/"); handlers[i] = std::make_shared(sessions[i]); // Lock mtx_requests to prevent response, we will check IsSessionActive() in the end std::unique_lock lock_requests(mtx_requests); sessions[i]->SendRequest(handlers[i]); ASSERT_TRUE(sessions[i]->IsSessionActive()); } http_client.WaitBackgroundThreadExit(); ASSERT_TRUE(waitForRequests(300, batch_count)); for (unsigned i = 0; i < batch_count; ++i) { ASSERT_FALSE(sessions[i]->IsSessionActive()); ASSERT_TRUE(handlers[i]->is_called_.load(std::memory_order_acquire)); ASSERT_TRUE(handlers[i]->got_response_.load(std::memory_order_acquire)); } } } TEST_F(BasicCurlHttpTests, ElegantQuitQuick) { auto http_client = http_client::HttpClientFactory::Create(); std::static_pointer_cast(http_client)->MaybeSpawnBackgroundThread(); // start background first, then test it could wakeup auto session = http_client->CreateSession("http://127.0.0.1:19000/get/"); auto request = session->CreateRequest(); request->SetUri("get/"); auto handler = std::make_shared(); session->SendRequest(handler); std::this_thread::sleep_for(std::chrono::milliseconds{10}); // let it enter poll state auto beg = std::chrono::system_clock::now(); http_client->FinishAllSessions(); http_client.reset(); // when background_thread_wait_for_ is used, it should have no side effect on elegant quit // wait should be less than scheduled_delay_milliseconds_ // Due to load on CI hosts (some take 10ms), we assert it is less than 20ms auto cost = std::chrono::system_clock::now() - beg; ASSERT_TRUE(cost < std::chrono::milliseconds{20}) << "cost ms: " << std::chrono::duration_cast(cost).count() << " libcurl version: 0x" << std::hex << LIBCURL_VERSION_NUM; ASSERT_TRUE(handler->is_called_); ASSERT_TRUE(handler->got_response_); } TEST_F(BasicCurlHttpTests, BackgroundThreadWaitMore) { { curl::HttpClient http_client; http_client.MaybeSpawnBackgroundThread(); std::this_thread::sleep_for(std::chrono::milliseconds{10}); #if LIBCURL_VERSION_NUM >= 0x074200 ASSERT_FALSE(http_client.MaybeSpawnBackgroundThread()); #else // low version curl do not support delay quit, so old background would quit ASSERT_TRUE(http_client.MaybeSpawnBackgroundThread()); #endif } { curl::HttpClient http_client; http_client.SetBackgroundWaitFor(std::chrono::milliseconds::zero()); http_client.MaybeSpawnBackgroundThread(); std::this_thread::sleep_for(std::chrono::milliseconds{10}); // we can disable delay quit by set wait for 0 ASSERT_TRUE(http_client.MaybeSpawnBackgroundThread()); } } #ifdef ENABLE_OTLP_COMPRESSION_PREVIEW struct GzipEventHandler : public CustomEventHandler { ~GzipEventHandler() override = default; void OnResponse(http_client::Response & /* response */) noexcept override {} void OnEvent(http_client::SessionState state, nostd::string_view reason) noexcept override { is_called_ = true; state_ = state; reason_ = std::string{reason}; } bool is_called_ = false; http_client::SessionState state_ = static_cast(-1); std::string reason_; }; TEST_F(BasicCurlHttpTests, GzipCompressibleData) { received_requests_.clear(); auto session_manager = http_client::HttpClientFactory::Create(); EXPECT_TRUE(session_manager != nullptr); auto session = session_manager->CreateSession("http://127.0.0.1:19000"); auto request = session->CreateRequest(); request->SetUri("post/"); request->SetMethod(http_client::Method::Post); const auto original_size = 500UL; http_client::Body body(original_size); std::iota(body.begin(), body.end(), 0); request->SetBody(body); request->AddHeader("Content-Type", "text/plain"); request->SetCompression(opentelemetry::ext::http::client::Compression::kGzip); auto handler = std::make_shared(); session->SendRequest(handler); ASSERT_TRUE(waitForRequests(30, 1)); session->FinishSession(); ASSERT_TRUE(handler->is_called_); ASSERT_EQ(handler->state_, http_client::SessionState::Response); ASSERT_TRUE(handler->reason_.empty()); auto http_request = dynamic_cast(request.get()); ASSERT_TRUE(http_request != nullptr); ASSERT_LT(http_request->body_.size(), original_size); session_manager->CancelAllSessions(); session_manager->FinishAllSessions(); } TEST_F(BasicCurlHttpTests, GzipIncompressibleData) { received_requests_.clear(); auto session_manager = http_client::HttpClientFactory::Create(); EXPECT_TRUE(session_manager != nullptr); auto session = session_manager->CreateSession("http://127.0.0.1:19000"); auto request = session->CreateRequest(); request->SetUri("post/"); request->SetMethod(http_client::Method::Post); // Random data generated using code snippet below. // const auto original_size = 500UL; // http_client::Body body(original_size); // std::random_device rd; // std::mt19937 gen(rd()); // std::uniform_int_distribution<> uid(1, 255); // std::generate(body.begin(), body.end(), [&]() { return uid(gen); }); // The input values are fixed to make the test repeatable in the event that some distributions // might yield results that are, in fact, compressible. http_client::Body body = { 140, 198, 12, 56, 165, 185, 173, 20, 13, 83, 127, 223, 77, 38, 224, 43, 236, 10, 178, 75, 169, 157, 136, 199, 74, 30, 148, 195, 51, 30, 225, 21, 121, 219, 7, 155, 198, 121, 205, 102, 80, 38, 132, 202, 45, 229, 206, 90, 150, 202, 53, 221, 54, 37, 172, 90, 238, 248, 191, 240, 109, 227, 248, 41, 251, 121, 35, 226, 107, 122, 15, 242, 203, 45, 64, 195, 186, 23, 1, 158, 61, 196, 182, 26, 201, 47, 211, 241, 251, 209, 255, 170, 181, 192, 89, 133, 176, 60, 178, 97, 168, 223, 152, 9, 118, 98, 169, 240, 170, 15, 13, 161, 24, 57, 123, 117, 230, 30, 244, 117, 238, 255, 198, 232, 95, 148, 37, 61, 67, 103, 31, 240, 52, 21, 145, 175, 201, 86, 19, 61, 228, 76, 131, 185, 111, 149, 203, 143, 16, 142, 95, 173, 42, 106, 39, 203, 116, 235, 20, 162, 112, 173, 112, 70, 126, 191, 210, 219, 90, 145, 126, 118, 43, 241, 101, 66, 175, 179, 5, 233, 208, 164, 180, 83, 214, 194, 173, 29, 179, 149, 75, 202, 17, 152, 139, 130, 94, 247, 142, 249, 159, 224, 205, 131, 93, 82, 186, 226, 210, 84, 17, 212, 155, 61, 226, 103, 152, 37, 3, 193, 216, 219, 203, 101, 99, 33, 59, 38, 106, 62, 232, 127, 44, 125, 90, 169, 148, 238, 34, 106, 12, 221, 90, 173, 67, 122, 232, 161, 89, 198, 43, 241, 195, 248, 219, 35, 47, 200, 11, 227, 168, 246, 243, 103, 38, 17, 203, 237, 203, 158, 204, 89, 231, 19, 24, 25, 199, 160, 233, 43, 117, 144, 196, 117, 152, 42, 121, 189, 217, 202, 221, 250, 157, 237, 47, 29, 64, 32, 10, 32, 243, 28, 114, 158, 228, 102, 36, 191, 139, 217, 161, 162, 186, 19, 141, 212, 49, 1, 239, 153, 107, 249, 31, 235, 138, 73, 80, 58, 152, 15, 149, 50, 42, 84, 75, 95, 82, 56, 86, 143, 45, 214, 11, 184, 164, 181, 249, 74, 184, 26, 207, 165, 162, 240, 154, 90, 56, 175, 72, 4, 166, 188, 78, 232, 87, 243, 50, 59, 62, 175, 213, 210, 182, 31, 123, 91, 118, 98, 249, 23, 170, 240, 228, 236, 121, 87, 132, 129, 250, 41, 227, 204, 250, 147, 145, 109, 149, 210, 21, 174, 165, 127, 234, 64, 211, 52, 93, 126, 117, 231, 216, 210, 15, 16, 2, 167, 215, 178, 104, 245, 119, 211, 235, 120, 135, 202, 117, 150, 101, 94, 201, 136, 179, 205, 167, 212, 236, 7, 178, 132, 228, 65, 230, 90, 171, 109, 31, 83, 31, 210, 123, 136, 76, 186, 81, 205, 63, 35, 21, 121, 152, 22, 242, 199, 106, 217, 199, 211, 206, 165, 88, 77, 112, 108, 193, 122, 8, 193, 74, 91, 50, 6, 156, 185, 165, 15, 92, 116, 3, 18, 244, 165, 191, 2, 183, 9, 164, 116, 75, 127}; const auto original_size = body.size(); request->SetBody(body); request->AddHeader("Content-Type", "text/plain"); request->SetCompression(opentelemetry::ext::http::client::Compression::kGzip); auto handler = std::make_shared(); session->SendRequest(handler); ASSERT_TRUE(waitForRequests(30, 1)); session->FinishSession(); ASSERT_TRUE(handler->is_called_); ASSERT_EQ(handler->state_, http_client::SessionState::Response); ASSERT_TRUE(handler->reason_.empty()); auto http_request = dynamic_cast(request.get()); ASSERT_TRUE(http_request != nullptr); ASSERT_EQ(http_request->body_.size(), original_size); session_manager->CancelAllSessions(); session_manager->FinishAllSessions(); } #endif // ENABLE_OTLP_COMPRESSION_PREVIEW