diff --git a/exporters/jaeger/BUILD b/exporters/jaeger/BUILD index ea18ef4153..7ccca66f50 100644 --- a/exporters/jaeger/BUILD +++ b/exporters/jaeger/BUILD @@ -116,3 +116,19 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "jaeger_exporter_test", + srcs = ["test/jaeger_exporter_test.cc"], + copts = ["-fexceptions"], + defines = ["BAZEL_BUILD"], + tags = [ + "jaeger", + "test", + ], + deps = [ + ":opentelemetry_exporter_jaeger_trace", + "//sdk/src/resource", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/exporters/jaeger/CMakeLists.txt b/exporters/jaeger/CMakeLists.txt index 0ae9162c61..5ae830aa60 100644 --- a/exporters/jaeger/CMakeLists.txt +++ b/exporters/jaeger/CMakeLists.txt @@ -67,4 +67,28 @@ if(BUILD_TESTING) TARGET jaeger_recordable_test TEST_PREFIX exporter. TEST_LIST jaeger_recordable_test) + + add_executable(jaeger_exporter_test test/jaeger_exporter_test.cc) + add_definitions(-DGTEST_LINKED_AS_SHARED_LIBRARY=1) + if(MSVC) + if(GMOCK_LIB) + unset(GMOCK_LIB CACHE) + endif() + endif() + if(MSVC AND CMAKE_BUILD_TYPE STREQUAL "Debug") + find_library(GMOCK_LIB gmockd PATH_SUFFIXES lib) + else() + find_library(GMOCK_LIB gmock PATH_SUFFIXES lib) + endif() + target_link_libraries( + jaeger_exporter_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + ${GMOCK_LIB} opentelemetry_exporter_jaeger_trace) + + target_include_directories(jaeger_exporter_test + PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src) + + gtest_add_tests( + TARGET jaeger_exporter_test + TEST_PREFIX exporter. + TEST_LIST jaeger_exporter_test) endif() # BUILD_TESTING diff --git a/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter.h b/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter.h index ecb08114f4..e58b2230ef 100644 --- a/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter.h +++ b/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter.h @@ -75,6 +75,14 @@ class JaegerExporter final : public opentelemetry::sdk::trace::SpanExporter bool is_shutdown_ = false; JaegerExporterOptions options_; std::unique_ptr sender_; + // For testing + friend class JaegerExporterTestPeer; + /** + * Create an JaegerExporter using the specified thrift sender. + * Only tests can call this constructor directly. + * @param sender the thrift sender to be used for exporting + */ + JaegerExporter(std::unique_ptr sender); }; } // namespace jaeger diff --git a/exporters/jaeger/src/jaeger_exporter.cc b/exporters/jaeger/src/jaeger_exporter.cc index c4e6ac0f0b..e194def470 100644 --- a/exporters/jaeger/src/jaeger_exporter.cc +++ b/exporters/jaeger/src/jaeger_exporter.cc @@ -27,6 +27,10 @@ JaegerExporter::JaegerExporter(const JaegerExporterOptions &options) : options_( JaegerExporter::JaegerExporter() : JaegerExporter(JaegerExporterOptions()) {} +JaegerExporter::JaegerExporter(std::unique_ptr sender) + : options_(JaegerExporterOptions()), sender_(std::move(sender)) +{} + std::unique_ptr JaegerExporter::MakeRecordable() noexcept { return std::unique_ptr(new JaegerRecordable); diff --git a/exporters/jaeger/src/thrift_sender.h b/exporters/jaeger/src/thrift_sender.h index 40fcf5f09a..0ec8d47f11 100644 --- a/exporters/jaeger/src/thrift_sender.h +++ b/exporters/jaeger/src/thrift_sender.h @@ -67,6 +67,10 @@ class ThriftSender : public Sender uint32_t byte_buffer_size_ = 0; uint32_t process_bytes_size_ = 0; uint32_t max_span_bytes_ = 0; + friend class MockThriftSender; + +protected: + ThriftSender() = default; }; } // namespace jaeger diff --git a/exporters/jaeger/test/jaeger_exporter_test.cc b/exporters/jaeger/test/jaeger_exporter_test.cc new file mode 100644 index 0000000000..ab680e35fc --- /dev/null +++ b/exporters/jaeger/test/jaeger_exporter_test.cc @@ -0,0 +1,112 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include + +#ifdef BAZEL_BUILD +# include "exporters/jaeger/src/thrift_sender.h" +#else +# include "thrift_sender.h" +#endif + +#include +#include "gmock/gmock.h" + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace sdktrace = opentelemetry::sdk::trace; +namespace common = opentelemetry::common; +namespace sdk_common = opentelemetry::sdk::common; + +using namespace testing; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace jaeger +{ + +class JaegerExporterTestPeer : public ::testing::Test +{ +public: + std::unique_ptr GetExporter(std::unique_ptr sender) + { + return std::unique_ptr(new JaegerExporter(std::move(sender))); + } + + // Get the options associated with the given exporter. + const JaegerExporterOptions &GetOptions(std::unique_ptr &exporter) + { + return exporter->options_; + } +}; + +class MockThriftSender : public ThriftSender +{ +public: + MOCK_METHOD(int, Append, (std::unique_ptr &&), (noexcept, override)); +}; + +TEST_F(JaegerExporterTestPeer, ShutdownTest) +{ + auto mock_thrift_sender = new MockThriftSender; + auto exporter = GetExporter(std::unique_ptr{mock_thrift_sender}); + + 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_thrift_sender, Append(_)).Times(Exactly(1)).WillOnce(Return(1)); + 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(JaegerExporterTestPeer, ExportTest) +{ + auto mock_thrift_sender = new MockThriftSender; + auto exporter = GetExporter(std::unique_ptr{mock_thrift_sender}); + + auto recordable_1 = exporter->MakeRecordable(); + recordable_1->SetName("Test span 1"); + auto recordable_2 = exporter->MakeRecordable(); + recordable_2->SetName("Test span 2"); + + // Test successful send + nostd::span> batch_1(&recordable_1, 1); + EXPECT_CALL(*mock_thrift_sender, Append(_)).Times(Exactly(1)).WillOnce(Return(1)); + auto result = exporter->Export(batch_1); + EXPECT_EQ(sdk_common::ExportResult::kSuccess, result); + + // Test failed send + nostd::span> batch_2(&recordable_2, 1); + EXPECT_CALL(*mock_thrift_sender, Append(_)).Times(Exactly(1)).WillOnce(Return(0)); + result = exporter->Export(batch_2); + EXPECT_EQ(sdk::common::ExportResult::kFailure, result); +} + +// Test exporter configuration options +TEST_F(JaegerExporterTestPeer, ConfigTest) +{ + JaegerExporterOptions opts; + opts.endpoint = "localhost"; + opts.server_port = 6851; + std::unique_ptr exporter(new JaegerExporter(opts)); + EXPECT_EQ(GetOptions(exporter).endpoint, "localhost"); + EXPECT_EQ(GetOptions(exporter).server_port, 6851); +} + +} // namespace jaeger +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE