text: // 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 <gtest/gtest.h>
  
  #  if defined(_MSC_VER)
  #    define putenv _putenv
  #  endif
  
  using namespace testing;
  
  OPENTELEMETRY_BEGIN_NAMESPACE
  namespace exporter
  {
  namespace otlp
  {
  
  class OtlpGrpcExporterTestPeer : public ::testing::Test
  {
  public:
    std::unique_ptr<sdk::trace::SpanExporter> GetExporter(
        std::unique_ptr<proto::collector::trace::v1::TraceService::StubInterface> &stub_interface)
    {
      return std::unique_ptr<sdk::trace::SpanExporter>(
          new OtlpGrpcExporter(std::move(stub_interface)));
    }
  
    // Get the options associated with the given exporter.
    const OtlpGrpcExporterOptions &GetOptions(std::unique_ptr<OtlpGrpcExporter> &exporter)
    {
      return exporter->options_;
    }
  };
  
  // Call Export() directly
  TEST_F(OtlpGrpcExporterTestPeer, ExportUnitTest)
  {
    auto mock_stub = new proto::collector::trace::v1::MockTraceServiceStub();
    std::unique_ptr<proto::collector::trace::v1::TraceService::StubInterface> 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<std::unique_ptr<sdk::trace::Recordable>> 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<std::unique_ptr<sdk::trace::Recordable>> 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<proto::collector::trace::v1::TraceService::StubInterface> stub_interface(
        mock_stub);
  
    auto exporter = GetExporter(stub_interface);
  
    auto processor = std::unique_ptr<sdk::trace::SpanProcessor>(
        new sdk::trace::SimpleSpanProcessor(std::move(exporter)));
    auto provider = nostd::shared_ptr<trace::TracerProvider>(
        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<OtlpGrpcExporter> 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<OtlpGrpcExporter> 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--";
    const std::string cacert_env = "OTEL_EXPORTER_OTLP_GRPC_SSL_CERTIFICATE=" + cacert_str;
    putenv(const_cast<char *>(cacert_env.data()));
    char ssl_enable_env[] = "OTEL_EXPORTER_OTLP_GRPC_SSL_ENABLE=True";
    putenv(ssl_enable_env);
    const std::string endpoint     = "http://localhost:9999";
    const std::string endpoint_env = "OTEL_EXPORTER_OTLP_GRPC_ENDPOINT=" + endpoint;
    putenv(const_cast<char *>(endpoint_env.data()));
  
    std::unique_ptr<OtlpGrpcExporter> 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);
  #    if defined(_MSC_VER)
    putenv("OTEL_EXPORTER_OTLP_GRPC_ENDPOINT=");
    putenv("OTEL_EXPORTER_OTLP_GRPC_SSL_CERTIFICATE=");
    putenv("OTEL_EXPORTER_OTLP_GRPC_SSL_ENABLE=");
  
  #    else
    unsetenv("OTEL_EXPORTER_OTLP_GRPC_ENDPOINT");
    unsetenv("OTEL_EXPORTER_OTLP_GRPC_SSL_CERTIFICATE");
    unsetenv("OTEL_EXPORTER_OTLP_GRPC_SSL_ENABLE");
  
  #    endif
  }
  #  endif
  
  }  // namespace otlp
  }  // namespace exporter
  OPENTELEMETRY_END_NAMESPACE
  #endif
  