// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 #ifndef HAVE_CPP_STDLIB // Unfortunately as of 04/27/2021 the fix is NOT in the vcpkg snapshot of Google Test. // Remove above `#ifdef` once the GMock fix for C++20 is in the mainline. // // Please refer to this GitHub issue for additional details: // https://github.com/google/googletest/issues/2914 // https://github.com/google/googletest/commit/61f010d703b32de9bfb20ab90ece38ab2f25977f // // If we compile using Visual Studio 2019 with `c++latest` (C++20) without the GMock fix, // then the compilation here fails in `gmock-actions.h` from: // .\tools\vcpkg\installed\x64-windows\include\gmock\gmock-actions.h(819): // error C2653: 'result_of': is not a class or namespace name // // That is because `std::result_of` has been removed in C++20. # include "opentelemetry/exporters/otlp/otlp_grpc_exporter.h" # include "opentelemetry/exporters/otlp/protobuf_include_prefix.h" // Problematic code that pulls in Gmock and breaks with vs2019/c++latest : # include "opentelemetry/proto/collector/trace/v1/trace_service_mock.grpc.pb.h" # include "opentelemetry/exporters/otlp/protobuf_include_suffix.h" # include "opentelemetry/sdk/trace/simple_processor.h" # include "opentelemetry/sdk/trace/tracer_provider.h" # include "opentelemetry/trace/provider.h" # include # if defined(_MSC_VER) # include "opentelemetry/sdk/common/env_variables.h" using opentelemetry::sdk::common::setenv; using opentelemetry::sdk::common::unsetenv; # endif using namespace testing; OPENTELEMETRY_BEGIN_NAMESPACE namespace exporter { namespace otlp { class OtlpGrpcExporterTestPeer : public ::testing::Test { public: std::unique_ptr GetExporter( std::unique_ptr &stub_interface) { return std::unique_ptr( new OtlpGrpcExporter(std::move(stub_interface))); } // Get the options associated with the given exporter. const OtlpGrpcExporterOptions &GetOptions(std::unique_ptr &exporter) { return exporter->options_; } }; TEST_F(OtlpGrpcExporterTestPeer, ShutdownTest) { auto mock_stub = new proto::collector::trace::v1::MockTraceServiceStub(); std::unique_ptr stub_interface( mock_stub); auto exporter = GetExporter(stub_interface); auto recordable_1 = exporter->MakeRecordable(); recordable_1->SetName("Test span 1"); auto recordable_2 = exporter->MakeRecordable(); recordable_2->SetName("Test span 2"); // exporter shuold not be shutdown by default nostd::span> batch_1(&recordable_1, 1); EXPECT_CALL(*mock_stub, Export(_, _, _)).Times(Exactly(1)).WillOnce(Return(grpc::Status::OK)); auto result = exporter->Export(batch_1); EXPECT_EQ(sdk::common::ExportResult::kSuccess, result); exporter->Shutdown(); nostd::span> batch_2(&recordable_2, 1); result = exporter->Export(batch_2); EXPECT_EQ(sdk::common::ExportResult::kFailure, result); } // Call Export() directly TEST_F(OtlpGrpcExporterTestPeer, ExportUnitTest) { auto mock_stub = new proto::collector::trace::v1::MockTraceServiceStub(); std::unique_ptr stub_interface( mock_stub); auto exporter = GetExporter(stub_interface); auto recordable_1 = exporter->MakeRecordable(); recordable_1->SetName("Test span 1"); auto recordable_2 = exporter->MakeRecordable(); recordable_2->SetName("Test span 2"); // Test successful RPC nostd::span> batch_1(&recordable_1, 1); EXPECT_CALL(*mock_stub, Export(_, _, _)).Times(Exactly(1)).WillOnce(Return(grpc::Status::OK)); auto result = exporter->Export(batch_1); EXPECT_EQ(sdk::common::ExportResult::kSuccess, result); // Test failed RPC nostd::span> batch_2(&recordable_2, 1); EXPECT_CALL(*mock_stub, Export(_, _, _)) .Times(Exactly(1)) .WillOnce(Return(grpc::Status::CANCELLED)); result = exporter->Export(batch_2); EXPECT_EQ(sdk::common::ExportResult::kFailure, result); } // Create spans, let processor call Export() TEST_F(OtlpGrpcExporterTestPeer, ExportIntegrationTest) { auto mock_stub = new proto::collector::trace::v1::MockTraceServiceStub(); std::unique_ptr stub_interface( mock_stub); auto exporter = GetExporter(stub_interface); auto processor = std::unique_ptr( new sdk::trace::SimpleSpanProcessor(std::move(exporter))); auto provider = nostd::shared_ptr( new sdk::trace::TracerProvider(std::move(processor))); auto tracer = provider->GetTracer("test"); EXPECT_CALL(*mock_stub, Export(_, _, _)) .Times(AtLeast(1)) .WillRepeatedly(Return(grpc::Status::OK)); auto parent_span = tracer->StartSpan("Test parent span"); auto child_span = tracer->StartSpan("Test child span"); child_span->End(); parent_span->End(); } // Test exporter configuration options TEST_F(OtlpGrpcExporterTestPeer, ConfigTest) { OtlpGrpcExporterOptions opts; opts.endpoint = "localhost:45454"; std::unique_ptr exporter(new OtlpGrpcExporter(opts)); EXPECT_EQ(GetOptions(exporter).endpoint, "localhost:45454"); } // Test exporter configuration options with use_ssl_credentials TEST_F(OtlpGrpcExporterTestPeer, ConfigSslCredentialsTest) { std::string cacert_str = "--begin and end fake cert--"; OtlpGrpcExporterOptions opts; opts.use_ssl_credentials = true; opts.ssl_credentials_cacert_as_string = cacert_str; std::unique_ptr exporter(new OtlpGrpcExporter(opts)); EXPECT_EQ(GetOptions(exporter).ssl_credentials_cacert_as_string, cacert_str); EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, true); } # ifndef NO_GETENV // Test exporter configuration options with use_ssl_credentials TEST_F(OtlpGrpcExporterTestPeer, ConfigFromEnv) { const std::string cacert_str = "--begin and end fake cert--"; setenv("OTEL_EXPORTER_OTLP_CERTIFICATE_STRING", cacert_str.c_str(), 1); setenv("OTEL_EXPORTER_OTLP_SSL_ENABLE", "True", 1); const std::string endpoint = "http://localhost:9999"; setenv("OTEL_EXPORTER_OTLP_ENDPOINT", endpoint.c_str(), 1); setenv("OTEL_EXPORTER_OTLP_TIMEOUT", "20050ms", 1); setenv("OTEL_EXPORTER_OTLP_HEADERS", "k1=v1,k2=v2", 1); setenv("OTEL_EXPORTER_OTLP_TRACES_HEADERS", "k1=v3,k1=v4", 1); std::unique_ptr exporter(new OtlpGrpcExporter()); EXPECT_EQ(GetOptions(exporter).ssl_credentials_cacert_as_string, cacert_str); EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, true); EXPECT_EQ(GetOptions(exporter).endpoint, endpoint); EXPECT_EQ(GetOptions(exporter).timeout.count(), std::chrono::duration_cast( std::chrono::milliseconds{20050}) .count()); EXPECT_EQ(GetOptions(exporter).metadata.size(), 3); { // Test k2 auto range = GetOptions(exporter).metadata.equal_range("k2"); EXPECT_TRUE(range.first != range.second); EXPECT_EQ(range.first->second, std::string("v2")); ++range.first; EXPECT_TRUE(range.first == range.second); } { // Test k1 auto range = GetOptions(exporter).metadata.equal_range("k1"); EXPECT_TRUE(range.first != range.second); EXPECT_EQ(range.first->second, std::string("v3")); ++range.first; EXPECT_EQ(range.first->second, std::string("v4")); ++range.first; EXPECT_TRUE(range.first == range.second); } unsetenv("OTEL_EXPORTER_OTLP_ENDPOINT"); unsetenv("OTEL_EXPORTER_OTLP_CERTIFICATE_STRING"); unsetenv("OTEL_EXPORTER_OTLP_SSL_ENABLE"); unsetenv("OTEL_EXPORTER_OTLP_TIMEOUT"); unsetenv("OTEL_EXPORTER_OTLP_HEADERS"); unsetenv("OTEL_EXPORTER_OTLP_TRACES_HEADERS"); } # endif } // namespace otlp } // namespace exporter OPENTELEMETRY_END_NAMESPACE #endif