diff options
Diffstat (limited to 'src/jaegertracing/opentelemetry-cpp/api/test/trace')
21 files changed, 1765 insertions, 0 deletions
diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/BUILD b/src/jaegertracing/opentelemetry-cpp/api/test/trace/BUILD new file mode 100644 index 000000000..a9b5b0170 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/BUILD @@ -0,0 +1,199 @@ +load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") + +cc_test( + name = "default_span_test", + srcs = [ + "default_span_test.cc", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "noop_test", + srcs = [ + "noop_test.cc", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "key_value_iterable_view_test", + srcs = [ + "key_value_iterable_view_test.cc", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +otel_cc_benchmark( + name = "span_id_benchmark", + srcs = ["span_id_benchmark.cc"], + tags = [ + "api", + "test", + "trace", + ], + deps = ["//api"], +) + +otel_cc_benchmark( + name = "span_benchmark", + srcs = ["span_benchmark.cc"], + tags = [ + "api", + "test", + "trace", + ], + deps = ["//api"], +) + +cc_test( + name = "provider_test", + srcs = [ + "provider_test.cc", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "span_id_test", + srcs = [ + "span_id_test.cc", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "trace_flags_test", + srcs = [ + "trace_flags_test.cc", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "trace_id_test", + srcs = [ + "trace_id_test.cc", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "span_context_test", + srcs = [ + "span_context_test.cc", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "trace_state_test", + srcs = [ + "trace_state_test.cc", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "scope_test", + srcs = [ + "scope_test.cc", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "tracer_test", + srcs = [ + "tracer_test.cc", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/api/test/trace/CMakeLists.txt new file mode 100644 index 000000000..09d2c12d8 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/CMakeLists.txt @@ -0,0 +1,29 @@ +add_subdirectory(propagation) + +foreach( + testname + key_value_iterable_view_test + provider_test + span_id_test + trace_id_test + trace_flags_test + span_context_test + scope_test + noop_test + trace_state_test + tracer_test) + add_executable(api_${testname} "${testname}.cc") + target_link_libraries(api_${testname} ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) + gtest_add_tests( + TARGET api_${testname} + TEST_PREFIX trace. + TEST_LIST api_${testname}) +endforeach() + +add_executable(span_id_benchmark span_id_benchmark.cc) +target_link_libraries(span_id_benchmark benchmark::benchmark + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) +add_executable(span_benchmark span_benchmark.cc) +target_link_libraries(span_benchmark benchmark::benchmark + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/default_span_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/default_span_test.cc new file mode 100644 index 000000000..377a0a858 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/default_span_test.cc @@ -0,0 +1,24 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/trace/default_span.h" +#include "opentelemetry/trace/span_context.h" + +#include <cstring> +#include <string> + +#include <gtest/gtest.h> + +namespace +{ + +using opentelemetry::trace::DefaultSpan; +using opentelemetry::trace::SpanContext; + +TEST(DefaultSpanTest, GetContext) +{ + SpanContext span_context = SpanContext(false, false); + DefaultSpan sp = DefaultSpan(span_context); + EXPECT_EQ(span_context, sp.GetContext()); +} +} // namespace diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/key_value_iterable_view_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/key_value_iterable_view_test.cc new file mode 100644 index 000000000..989856b42 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/key_value_iterable_view_test.cc @@ -0,0 +1,68 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/common/key_value_iterable_view.h" + +#include <gtest/gtest.h> +#include <map> +#include "opentelemetry/nostd/type_traits.h" + +using namespace opentelemetry; + +static int TakeKeyValues(const common::KeyValueIterable &iterable) +{ + std::map<std::string, common::AttributeValue> result; + int count = 0; + iterable.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { + ++count; + return true; + }); + return count; +} + +template <class T, nostd::enable_if_t<common::detail::is_key_value_iterable<T>::value> * = nullptr> +static int TakeKeyValues(const T &iterable) +{ + return TakeKeyValues(common::KeyValueIterableView<T>{iterable}); +} + +TEST(KeyValueIterableViewTest, is_key_value_iterable) +{ + using M1 = std::map<std::string, std::string>; + EXPECT_TRUE(bool{common::detail::is_key_value_iterable<M1>::value}); + + using M2 = std::map<std::string, int>; + EXPECT_TRUE(bool{common::detail::is_key_value_iterable<M2>::value}); + + using M3 = std::map<std::string, common::AttributeValue>; + EXPECT_TRUE(bool{common::detail::is_key_value_iterable<M3>::value}); + + struct A + {}; + using M4 = std::map<std::string, A>; + EXPECT_FALSE(bool{common::detail::is_key_value_iterable<M4>::value}); +} + +TEST(KeyValueIterableViewTest, ForEachKeyValue) +{ + std::map<std::string, std::string> m1 = {{"abc", "123"}, {"xyz", "456"}}; + EXPECT_EQ(TakeKeyValues(m1), 2); + + std::vector<std::pair<std::string, int>> v1 = {{"abc", 123}, {"xyz", 456}}; + EXPECT_EQ(TakeKeyValues(v1), 2); +} + +TEST(KeyValueIterableViewTest, ForEachKeyValueWithExit) +{ + using M = std::map<std::string, std::string>; + M m1 = {{"abc", "123"}, {"xyz", "456"}}; + common::KeyValueIterableView<M> iterable{m1}; + int count = 0; + auto exit = iterable.ForEachKeyValue( + [&count](nostd::string_view /*key*/, common::AttributeValue /*value*/) noexcept { + ++count; + return false; + }); + EXPECT_EQ(count, 1); + EXPECT_FALSE(exit); +} diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/noop_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/noop_test.cc new file mode 100644 index 000000000..130496faf --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/noop_test.cc @@ -0,0 +1,81 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/trace/noop.h" +#include "opentelemetry/common/timestamp.h" + +#include <map> +#include <memory> +#include <string> + +#include <gtest/gtest.h> + +namespace trace_api = opentelemetry::trace; +namespace nonstd = opentelemetry::nostd; +namespace common = opentelemetry::common; + +TEST(NoopTest, UseNoopTracers) +{ + std::shared_ptr<trace_api::Tracer> tracer{new trace_api::NoopTracer{}}; + auto s1 = tracer->StartSpan("abc"); + + std::map<std::string, std::string> attributes1; + s1->AddEvent("abc", attributes1); + + std::vector<std::pair<std::string, int>> attributes2; + s1->AddEvent("abc", attributes2); + + s1->AddEvent("abc", {{"a", 1}, {"b", "2"}, {"c", 3.0}}); + + std::vector<std::pair<std::string, std::vector<int>>> attributes3; + s1->AddEvent("abc", attributes3); + + s1->SetAttribute("abc", 4); + + s1->AddEvent("abc"); // add Empty + + EXPECT_EQ(s1->IsRecording(), false); + + s1->SetStatus(trace_api::StatusCode::kUnset, "span unset"); + + s1->UpdateName("test_name"); + + common::SystemTimestamp t1; + s1->AddEvent("test_time_stamp", t1); + + s1->GetContext(); +} + +TEST(NoopTest, StartSpan) +{ + std::shared_ptr<trace_api::Tracer> tracer{new trace_api::NoopTracer{}}; + + std::map<std::string, std::string> attrs = {{"a", "3"}}; + std::vector<std::pair<trace_api::SpanContext, std::map<std::string, std::string>>> links = { + {trace_api::SpanContext(false, false), attrs}}; + auto s1 = tracer->StartSpan("abc", attrs, links); + + auto s2 = + tracer->StartSpan("efg", {{"a", 3}}, {{trace_api::SpanContext(false, false), {{"b", 4}}}}); +} + +TEST(NoopTest, CreateSpanValidSpanContext) +{ + // Create valid spancontext for NoopSpan + + constexpr uint8_t buf_span[] = {1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t buf_trace[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + auto trace_id = trace_api::TraceId{buf_trace}; + auto span_id = trace_api::SpanId{buf_span}; + auto span_context = nonstd::unique_ptr<trace_api::SpanContext>( + new trace_api::SpanContext{trace_id, span_id, trace_api::TraceFlags{true}, false}); + std::shared_ptr<trace_api::Tracer> tracer{new trace_api::NoopTracer{}}; + auto s1 = + nonstd::shared_ptr<trace_api::Span>(new trace_api::NoopSpan(tracer, std::move(span_context))); + auto stored_span_context = s1->GetContext(); + EXPECT_EQ(stored_span_context.span_id(), span_id); + EXPECT_EQ(stored_span_context.trace_id(), trace_id); + + s1->AddEvent("even1"); // noop + s1->End(); // noop +} diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/BUILD b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/BUILD new file mode 100644 index 000000000..b21ba6bca --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/BUILD @@ -0,0 +1,52 @@ +load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") + +cc_test( + name = "http_text_format_test", + srcs = [ + "http_text_format_test.cc", + "util.h", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "b3_propagation_test", + srcs = [ + "b3_propagation_test.cc", + "util.h", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "jaeger_propagation_test", + srcs = [ + "jaeger_propagation_test.cc", + "util.h", + ], + tags = [ + "api", + "test", + "trace", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/CMakeLists.txt new file mode 100644 index 000000000..da60712c6 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/CMakeLists.txt @@ -0,0 +1,10 @@ +foreach(testname http_text_format_test b3_propagation_test + jaeger_propagation_test) + add_executable(${testname} "${testname}.cc") + target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) + gtest_add_tests( + TARGET ${testname} + TEST_PREFIX trace. + TEST_LIST ${testname}) +endforeach() diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/b3_propagation_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/b3_propagation_test.cc new file mode 100644 index 000000000..2538b5be2 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/b3_propagation_test.cc @@ -0,0 +1,189 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/context/runtime_context.h" +#include "opentelemetry/trace/propagation/b3_propagator.h" +#include "opentelemetry/trace/scope.h" +#include "util.h" + +#include <map> + +#include <gtest/gtest.h> + +using namespace opentelemetry; + +class TextMapCarrierTest : public context::propagation::TextMapCarrier +{ +public: + virtual nostd::string_view Get(nostd::string_view key) const noexcept override + { + auto it = headers_.find(std::string(key)); + if (it != headers_.end()) + { + return nostd::string_view(it->second); + } + return ""; + } + virtual void Set(nostd::string_view key, nostd::string_view value) noexcept override + { + headers_[std::string(key)] = std::string(value); + } + + std::map<std::string, std::string> headers_; +}; + +using MapB3Context = trace::propagation::B3Propagator; + +static MapB3Context format = MapB3Context(); + +using MapB3ContextMultiHeader = trace::propagation::B3PropagatorMultiHeader; + +static MapB3ContextMultiHeader formatMultiHeader = MapB3ContextMultiHeader(); + +TEST(B3PropagationTest, TraceFlagsBufferGeneration) +{ + EXPECT_EQ(MapB3Context::TraceFlagsFromHex("0"), trace::TraceFlags()); + EXPECT_EQ(MapB3Context::TraceFlagsFromHex("1"), trace::TraceFlags(trace::TraceFlags::kIsSampled)); +} + +TEST(B3PropagationTest, PropagateInvalidContext) +{ + // Do not propagate invalid trace context. + TextMapCarrierTest carrier; + context::Context ctx{ + "current-span", + nostd::shared_ptr<trace::Span>(new trace::DefaultSpan(trace::SpanContext::GetInvalid()))}; + format.Inject(carrier, ctx); + EXPECT_TRUE(carrier.headers_.count("b3") == 0); +} + +TEST(B3PropagationTest, ExtractInvalidContext) +{ + TextMapCarrierTest carrier; + carrier.headers_ = {{"b3", "00000000000000000000000000000000-0000000000000000-0"}}; + context::Context ctx1 = context::Context{}; + context::Context ctx2 = format.Extract(carrier, ctx1); + auto ctx2_span = ctx2.GetValue(trace::kSpanKey); + auto span = nostd::get<nostd::shared_ptr<trace::Span>>(ctx2_span); + EXPECT_EQ(span->GetContext().IsRemote(), false); +} + +TEST(B3PropagationTest, DoNotExtractWithInvalidHex) +{ + TextMapCarrierTest carrier; + carrier.headers_ = {{"b3", "0000000zzz0000000000000000000000-0000000zzz000000-1"}}; + context::Context ctx1 = context::Context{}; + context::Context ctx2 = format.Extract(carrier, ctx1); + auto ctx2_span = ctx2.GetValue(trace::kSpanKey); + auto span = nostd::get<nostd::shared_ptr<trace::Span>>(ctx2_span); + EXPECT_EQ(span->GetContext().IsRemote(), false); +} + +TEST(B3PropagationTest, SetRemoteSpan) +{ + TextMapCarrierTest carrier; + carrier.headers_ = { + {"b3", "80f198ee56343ba864fe8b2a57d3eff7-e457b5a2e4d86bd1-1-05e3ac9a4f6e3b90"}}; + context::Context ctx1 = context::Context{}; + context::Context ctx2 = format.Extract(carrier, ctx1); + + auto ctx2_span = ctx2.GetValue(trace::kSpanKey); + EXPECT_TRUE(nostd::holds_alternative<nostd::shared_ptr<trace::Span>>(ctx2_span)); + + auto span = nostd::get<nostd::shared_ptr<trace::Span>>(ctx2_span); + + EXPECT_EQ(Hex(span->GetContext().trace_id()), "80f198ee56343ba864fe8b2a57d3eff7"); + EXPECT_EQ(Hex(span->GetContext().span_id()), "e457b5a2e4d86bd1"); + EXPECT_EQ(span->GetContext().IsSampled(), true); + EXPECT_EQ(span->GetContext().IsRemote(), true); +} + +TEST(B3PropagationTest, SetRemoteSpan_TraceIdShort) +{ + TextMapCarrierTest carrier; + carrier.headers_ = {{"b3", "80f198ee56343ba8-e457b5a2e4d86bd1-1-05e3ac9a4f6e3b90"}}; + context::Context ctx1 = context::Context{}; + context::Context ctx2 = format.Extract(carrier, ctx1); + + auto ctx2_span = ctx2.GetValue(trace::kSpanKey); + EXPECT_TRUE(nostd::holds_alternative<nostd::shared_ptr<trace::Span>>(ctx2_span)); + + auto span = nostd::get<nostd::shared_ptr<trace::Span>>(ctx2_span); + + EXPECT_EQ(Hex(span->GetContext().trace_id()), "000000000000000080f198ee56343ba8"); + EXPECT_EQ(Hex(span->GetContext().span_id()), "e457b5a2e4d86bd1"); + EXPECT_EQ(span->GetContext().IsSampled(), true); + EXPECT_EQ(span->GetContext().IsRemote(), true); +} + +TEST(B3PropagationTest, SetRemoteSpan_SingleHeaderNoFlags) +{ + TextMapCarrierTest carrier; + carrier.headers_ = {{"b3", "80f198ee56343ba864fe8b2a57d3eff7-e457b5a2e4d86bd1"}}; + context::Context ctx1 = context::Context{}; + context::Context ctx2 = format.Extract(carrier, ctx1); + + auto ctx2_span = ctx2.GetValue(trace::kSpanKey); + EXPECT_TRUE(nostd::holds_alternative<nostd::shared_ptr<trace::Span>>(ctx2_span)); + + auto span = nostd::get<nostd::shared_ptr<trace::Span>>(ctx2_span); + + EXPECT_EQ(Hex(span->GetContext().trace_id()), "80f198ee56343ba864fe8b2a57d3eff7"); + EXPECT_EQ(Hex(span->GetContext().span_id()), "e457b5a2e4d86bd1"); + EXPECT_EQ(span->GetContext().IsSampled(), false); + EXPECT_EQ(span->GetContext().IsRemote(), true); +} + +TEST(B3PropagationTest, SetRemoteSpanMultiHeader) +{ + TextMapCarrierTest carrier; + carrier.headers_ = {{"X-B3-TraceId", "80f198ee56343ba864fe8b2a57d3eff7"}, + {"X-B3-SpanId", "e457b5a2e4d86bd1"}, + {"X-B3-Sampled", "1"}}; + context::Context ctx1 = context::Context{}; + context::Context ctx2 = format.Extract(carrier, ctx1); + + auto ctx2_span = ctx2.GetValue(trace::kSpanKey); + EXPECT_TRUE(nostd::holds_alternative<nostd::shared_ptr<trace::Span>>(ctx2_span)); + + auto span = nostd::get<nostd::shared_ptr<trace::Span>>(ctx2_span); + + EXPECT_EQ(Hex(span->GetContext().trace_id()), "80f198ee56343ba864fe8b2a57d3eff7"); + EXPECT_EQ(Hex(span->GetContext().span_id()), "e457b5a2e4d86bd1"); + EXPECT_EQ(span->GetContext().IsSampled(), true); + EXPECT_EQ(span->GetContext().IsRemote(), true); +} + +TEST(B3PropagationTest, GetCurrentSpan) +{ + TextMapCarrierTest carrier; + constexpr uint8_t buf_span[] = {1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t buf_trace[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + trace::SpanContext span_context{trace::TraceId{buf_trace}, trace::SpanId{buf_span}, + trace::TraceFlags{true}, false}; + nostd::shared_ptr<trace::Span> sp{new trace::DefaultSpan{span_context}}; + + // Set `sp` as the currently active span, which must be used by `Inject`. + trace::Scope scoped_span{sp}; + + format.Inject(carrier, context::RuntimeContext::GetCurrent()); + EXPECT_EQ(carrier.headers_["b3"], "0102030405060708090a0b0c0d0e0f10-0102030405060708-1"); +} + +TEST(B3PropagationTest, GetCurrentSpanMultiHeader) +{ + TextMapCarrierTest carrier; + constexpr uint8_t buf_span[] = {1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t buf_trace[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + trace::SpanContext span_context{trace::TraceId{buf_trace}, trace::SpanId{buf_span}, + trace::TraceFlags{true}, false}; + nostd::shared_ptr<trace::Span> sp{new trace::DefaultSpan{span_context}}; + + // Set `sp` as the currently active span, which must be used by `Inject`. + trace::Scope scoped_span{sp}; + + formatMultiHeader.Inject(carrier, context::RuntimeContext::GetCurrent()); + EXPECT_EQ(carrier.headers_["X-B3-TraceId"], "0102030405060708090a0b0c0d0e0f10"); + EXPECT_EQ(carrier.headers_["X-B3-SpanId"], "0102030405060708"); + EXPECT_EQ(carrier.headers_["X-B3-Sampled"], "1"); +} diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/http_text_format_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/http_text_format_test.cc new file mode 100644 index 000000000..8fa0e44ed --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/http_text_format_test.cc @@ -0,0 +1,211 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/context/propagation/global_propagator.h" +#include "opentelemetry/context/runtime_context.h" +#include "opentelemetry/trace/context.h" +#include "opentelemetry/trace/propagation/http_trace_context.h" +#include "opentelemetry/trace/scope.h" +#include "util.h" + +#include <map> +#include <unordered_map> + +#include <gtest/gtest.h> + +using namespace opentelemetry; + +class TextMapCarrierTest : public context::propagation::TextMapCarrier +{ +public: + virtual nostd::string_view Get(nostd::string_view key) const noexcept override + { + auto it = headers_.find(std::string(key)); + if (it != headers_.end()) + { + return nostd::string_view(it->second); + } + return ""; + } + virtual void Set(nostd::string_view key, nostd::string_view value) noexcept override + { + headers_[std::string(key)] = std::string(value); + } + + std::map<std::string, std::string> headers_; +}; + +using MapHttpTraceContext = trace::propagation::HttpTraceContext; + +static MapHttpTraceContext format = MapHttpTraceContext(); + +TEST(TextMapPropagatorTest, TraceFlagsBufferGeneration) +{ + EXPECT_EQ(MapHttpTraceContext::TraceFlagsFromHex("00"), trace::TraceFlags()); +} + +TEST(TextMapPropagatorTest, NoSendEmptyTraceState) +{ + // If the trace state is empty, do not set the header. + TextMapCarrierTest carrier; + carrier.headers_ = {{"traceparent", "00-4bf92f3577b34da6a3ce929d0e0e4736-0102030405060708-01"}}; + context::Context ctx1 = context::Context{ + "current-span", + nostd::shared_ptr<trace::Span>(new trace::DefaultSpan(trace::SpanContext::GetInvalid()))}; + context::Context ctx2 = format.Extract(carrier, ctx1); + TextMapCarrierTest carrier2; + format.Inject(carrier2, ctx2); + EXPECT_TRUE(carrier2.headers_.count("traceparent") > 0); + EXPECT_FALSE(carrier2.headers_.count("tracestate") > 0); +} + +TEST(TextMapPropagatorTest, PropogateTraceState) +{ + TextMapCarrierTest carrier; + carrier.headers_ = {{"traceparent", "00-4bf92f3577b34da6a3ce929d0e0e4736-0102030405060708-01"}, + {"tracestate", "congo=t61rcWkgMzE"}}; + context::Context ctx1 = context::Context{ + "current-span", + nostd::shared_ptr<trace::Span>(new trace::DefaultSpan(trace::SpanContext::GetInvalid()))}; + context::Context ctx2 = format.Extract(carrier, ctx1); + + TextMapCarrierTest carrier2; + format.Inject(carrier2, ctx2); + + EXPECT_TRUE(carrier2.headers_.count("traceparent") > 0); + EXPECT_TRUE(carrier2.headers_.count("tracestate") > 0); + EXPECT_EQ(carrier2.headers_["tracestate"], "congo=t61rcWkgMzE"); +} + +TEST(TextMapPropagatorTest, PropagateInvalidContext) +{ + // Do not propagate invalid trace context. + TextMapCarrierTest carrier; + context::Context ctx{ + "current-span", + nostd::shared_ptr<trace::Span>(new trace::DefaultSpan(trace::SpanContext::GetInvalid()))}; + format.Inject(carrier, ctx); + EXPECT_TRUE(carrier.headers_.count("traceparent") == 0); + EXPECT_TRUE(carrier.headers_.count("tracestate") == 0); +} + +TEST(TextMapPropagatorTest, SetRemoteSpan) +{ + TextMapCarrierTest carrier; + carrier.headers_ = {{"traceparent", "00-4bf92f3577b34da6a3ce929d0e0e4736-0102030405060708-01"}}; + context::Context ctx1 = context::Context{}; + context::Context ctx2 = format.Extract(carrier, ctx1); + + auto ctx2_span = ctx2.GetValue(trace::kSpanKey); + EXPECT_TRUE(nostd::holds_alternative<nostd::shared_ptr<trace::Span>>(ctx2_span)); + + auto span = nostd::get<nostd::shared_ptr<trace::Span>>(ctx2_span); + + EXPECT_EQ(Hex(span->GetContext().trace_id()), "4bf92f3577b34da6a3ce929d0e0e4736"); + EXPECT_EQ(Hex(span->GetContext().span_id()), "0102030405060708"); + EXPECT_EQ(span->GetContext().IsSampled(), true); + EXPECT_EQ(span->GetContext().IsRemote(), true); +} + +TEST(TextMapPropagatorTest, GetCurrentSpan) +{ + TextMapCarrierTest carrier; + constexpr uint8_t buf_span[] = {1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t buf_trace[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + + auto trace_state = trace::TraceState::FromHeader("congo=t61rcWkgMzE"); + trace::SpanContext span_context{trace::TraceId{buf_trace}, trace::SpanId{buf_span}, + trace::TraceFlags{true}, false, trace_state}; + nostd::shared_ptr<trace::Span> sp{new trace::DefaultSpan{span_context}}; + + // Set `sp` as the currently active span, which must be used by `Inject`. + trace::Scope scoped_span{sp}; + + format.Inject(carrier, context::RuntimeContext::GetCurrent()); + EXPECT_EQ(carrier.headers_["traceparent"], + "00-0102030405060708090a0b0c0d0e0f10-0102030405060708-01"); + EXPECT_EQ(carrier.headers_["tracestate"], "congo=t61rcWkgMzE"); +} + +TEST(TextMapPropagatorTest, InvalidIdentitiesAreNotExtracted) +{ + TextMapCarrierTest carrier; + std::vector<std::string> traces = { + "ff-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", + "00-0af7651916cd43dd8448eb211c80319c1-b9c7c989f97918e1-01", + "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e11-01", + "0-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", + "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-0", + "00-0af7651916cd43dd8448eb211c8031-b9c7c989f97918e1-01", + "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97-01", + "00-1-1-00", + "00--b9c7c989f97918e1-01", + "00-0af7651916cd43dd8448eb211c80319c1--01", + "", + "---", + }; + + for (auto &trace : traces) + { + carrier.headers_ = {{"traceparent", trace}}; + context::Context ctx1 = context::Context{}; + context::Context ctx2 = format.Extract(carrier, ctx1); + + auto span = trace::GetSpan(ctx2)->GetContext(); + EXPECT_FALSE(span.IsValid()); + } +} + +TEST(GlobalTextMapPropagator, NoOpPropagator) +{ + + auto propagator = context::propagation::GlobalTextMapPropagator::GetGlobalPropagator(); + TextMapCarrierTest carrier; + + carrier.headers_ = {{"traceparent", "00-4bf92f3577b34da6a3ce929d0e0e4736-0102030405060708-01"}, + {"tracestate", "congo=t61rcWkgMzE"}}; + context::Context ctx1 = context::Context{ + "current-span", + nostd::shared_ptr<trace::Span>(new trace::DefaultSpan(trace::SpanContext::GetInvalid()))}; + context::Context ctx2 = propagator->Extract(carrier, ctx1); + + TextMapCarrierTest carrier2; + propagator->Inject(carrier2, ctx2); + + EXPECT_TRUE(carrier2.headers_.count("tracestate") == 0); + EXPECT_TRUE(carrier2.headers_.count("traceparent") == 0); +} + +TEST(GlobalPropagator, SetAndGet) +{ + + auto trace_state_value = "congo=t61rcWkgMzE"; + context::propagation::GlobalTextMapPropagator::SetGlobalPropagator( + nostd::shared_ptr<context::propagation::TextMapPropagator>(new MapHttpTraceContext())); + + auto propagator = context::propagation::GlobalTextMapPropagator::GetGlobalPropagator(); + + TextMapCarrierTest carrier; + carrier.headers_ = {{"traceparent", "00-4bf92f3577b34da6a3ce929d0e0e4736-0102030405060708-01"}, + {"tracestate", trace_state_value}}; + context::Context ctx1 = context::Context{ + "current-span", + nostd::shared_ptr<trace::Span>(new trace::DefaultSpan(trace::SpanContext::GetInvalid()))}; + context::Context ctx2 = propagator->Extract(carrier, ctx1); + + TextMapCarrierTest carrier2; + propagator->Inject(carrier2, ctx2); + + EXPECT_TRUE(carrier.headers_.count("traceparent") > 0); + EXPECT_TRUE(carrier.headers_.count("tracestate") > 0); + EXPECT_EQ(carrier.headers_["tracestate"], trace_state_value); + + std::vector<std::string> fields; + propagator->Fields([&fields](nostd::string_view field) { + fields.push_back(field.data()); + return true; + }); + EXPECT_EQ(fields.size(), 2); + EXPECT_EQ(fields[0], trace::propagation::kTraceParent); + EXPECT_EQ(fields[1], trace::propagation::kTraceState); +} diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/jaeger_propagation_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/jaeger_propagation_test.cc new file mode 100644 index 000000000..c33761738 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/jaeger_propagation_test.cc @@ -0,0 +1,168 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/trace/propagation/jaeger.h" +#include "opentelemetry/trace/scope.h" +#include "util.h" + +#include <map> + +#include <gtest/gtest.h> + +using namespace opentelemetry; + +class TextMapCarrierTest : public context::propagation::TextMapCarrier +{ +public: + virtual nostd::string_view Get(nostd::string_view key) const noexcept override + { + auto it = headers_.find(std::string(key)); + if (it != headers_.end()) + { + return nostd::string_view(it->second); + } + return ""; + } + virtual void Set(nostd::string_view key, nostd::string_view value) noexcept override + { + headers_[std::string(key)] = std::string(value); + } + + std::map<std::string, std::string> headers_; +}; + +using Propagator = trace::propagation::JaegerPropagator; + +static Propagator format = Propagator(); + +TEST(JaegerPropagatorTest, ExtractValidSpans) +{ + struct TestTrace + { + std::string trace_state; + std::string expected_trace_id; + std::string expected_span_id; + bool sampled; + }; + + std::vector<TestTrace> traces = { + { + "4bf92f3577b34da6a3ce929d0e0e4736:0102030405060708:0:00", + "4bf92f3577b34da6a3ce929d0e0e4736", + "0102030405060708", + false, + }, + { + "4bf92f3577b34da6a3ce929d0e0e4736:0102030405060708:0:ff", + "4bf92f3577b34da6a3ce929d0e0e4736", + "0102030405060708", + true, + }, + { + "4bf92f3577b34da6a3ce929d0e0e4736:0102030405060708:0:f", + "4bf92f3577b34da6a3ce929d0e0e4736", + "0102030405060708", + true, + }, + { + "a3ce929d0e0e4736:0102030405060708:0:00", + "0000000000000000a3ce929d0e0e4736", + "0102030405060708", + false, + }, + { + "A3CE929D0E0E4736:ABCDEFABCDEF1234:0:01", + "0000000000000000a3ce929d0e0e4736", + "abcdefabcdef1234", + true, + }, + { + "ff:ABCDEFABCDEF1234:0:0", + "000000000000000000000000000000ff", + "abcdefabcdef1234", + false, + }, + { + "4bf92f3577b34da6a3ce929d0e0e4736:0102030405060708:0102030405060708:00", + "4bf92f3577b34da6a3ce929d0e0e4736", + "0102030405060708", + false, + }, + + }; + + for (TestTrace &test_trace : traces) + { + TextMapCarrierTest carrier; + carrier.headers_ = {{"uber-trace-id", test_trace.trace_state}}; + context::Context ctx1 = context::Context{}; + context::Context ctx2 = format.Extract(carrier, ctx1); + + auto span = trace::GetSpan(ctx2)->GetContext(); + EXPECT_TRUE(span.IsValid()); + + EXPECT_EQ(Hex(span.trace_id()), test_trace.expected_trace_id); + EXPECT_EQ(Hex(span.span_id()), test_trace.expected_span_id); + EXPECT_EQ(span.IsSampled(), test_trace.sampled); + EXPECT_EQ(span.IsRemote(), true); + } +} + +TEST(JaegerPropagatorTest, ExctractInvalidSpans) +{ + TextMapCarrierTest carrier; + std::vector<std::string> traces = { + "4bf92f3577b34da6a3ce929d0e0e47344:0102030405060708:0:00", // too long trace id + "4bf92f3577b34da6a3ce929d0e0e4734:01020304050607089:0:00", // too long span id + "4bf92f3577b34da6x3ce929d0y0e4734:01020304050607089:0:00", // invalid trace id character + "4bf92f3577b34da6a3ce929d0e0e4734:01020304g50607089:0:00", // invalid span id character + "4bf92f3577b34da6a3ce929d0e0e4734::0:00", + "", + "::::", + "0:0:0:0", + ":abcdef12:0:0", + }; + + for (auto &trace : traces) + { + carrier.headers_ = {{"uber-trace-id", trace}}; + context::Context ctx1 = context::Context{}; + context::Context ctx2 = format.Extract(carrier, ctx1); + + auto span = trace::GetSpan(ctx2)->GetContext(); + EXPECT_FALSE(span.IsValid()); + } +} + +TEST(JaegerPropagatorTest, InjectsContext) +{ + TextMapCarrierTest carrier; + constexpr uint8_t buf_span[] = {1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t buf_trace[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + trace::SpanContext span_context{trace::TraceId{buf_trace}, trace::SpanId{buf_span}, + trace::TraceFlags{true}, false}; + nostd::shared_ptr<trace::Span> sp{new trace::DefaultSpan{span_context}}; + trace::Scope scoped_span{sp}; + + format.Inject(carrier, context::RuntimeContext::GetCurrent()); + EXPECT_EQ(carrier.headers_["uber-trace-id"], + "0102030405060708090a0b0c0d0e0f10:0102030405060708:0:01"); + + std::vector<std::string> fields; + format.Fields([&fields](nostd::string_view field) { + fields.push_back(field.data()); + return true; + }); + EXPECT_EQ(fields.size(), 1); + EXPECT_EQ(fields[0], opentelemetry::trace::propagation::kJaegerTraceHeader); +} + +TEST(JaegerPropagatorTest, DoNotInjectInvalidContext) +{ + TextMapCarrierTest carrier; + context::Context ctx{ + "current-span", + nostd::shared_ptr<trace::Span>(new trace::DefaultSpan(trace::SpanContext::GetInvalid()))}; + format.Inject(carrier, ctx); + EXPECT_TRUE(carrier.headers_.count("uber-trace-id") == 0); +} diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/util.h b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/util.h new file mode 100644 index 000000000..ae234d92e --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/propagation/util.h @@ -0,0 +1,14 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include <string> + +template <typename T> +static std::string Hex(const T &id_item) +{ + char buf[T::kSize * 2]; + id_item.ToLowerBase16(buf); + return std::string(buf, sizeof(buf)); +} diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/provider_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/provider_test.cc new file mode 100644 index 000000000..9e5a7aad1 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/provider_test.cc @@ -0,0 +1,36 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/nostd/shared_ptr.h" + +#include <gtest/gtest.h> + +using opentelemetry::trace::Provider; +using opentelemetry::trace::Tracer; +using opentelemetry::trace::TracerProvider; + +namespace nostd = opentelemetry::nostd; + +class TestProvider : public TracerProvider +{ + nostd::shared_ptr<Tracer> GetTracer(nostd::string_view library_name, + nostd::string_view library_version, + nostd::string_view schema_url) noexcept override + { + return nostd::shared_ptr<Tracer>(nullptr); + } +}; + +TEST(Provider, GetTracerProviderDefault) +{ + auto tf = Provider::GetTracerProvider(); + EXPECT_NE(nullptr, tf); +} + +TEST(Provider, SetTracerProvider) +{ + auto tf = nostd::shared_ptr<TracerProvider>(new TestProvider()); + Provider::SetTracerProvider(tf); + ASSERT_EQ(tf, Provider::GetTracerProvider()); +} diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/scope_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/scope_test.cc new file mode 100644 index 000000000..b74905b16 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/scope_test.cc @@ -0,0 +1,51 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/trace/scope.h" +#include "opentelemetry/context/context.h" +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/trace/noop.h" + +#include <gtest/gtest.h> + +using opentelemetry::trace::kSpanKey; +using opentelemetry::trace::NoopSpan; +using opentelemetry::trace::Scope; +using opentelemetry::trace::Span; +namespace nostd = opentelemetry::nostd; +namespace context = opentelemetry::context; + +TEST(ScopeTest, Construct) +{ + nostd::shared_ptr<Span> span(new NoopSpan(nullptr)); + Scope scope(span); + + context::ContextValue active_span_value = context::RuntimeContext::GetValue(kSpanKey); + ASSERT_TRUE(nostd::holds_alternative<nostd::shared_ptr<Span>>(active_span_value)); + + auto active_span = nostd::get<nostd::shared_ptr<Span>>(active_span_value); + ASSERT_EQ(active_span, span); +} + +TEST(ScopeTest, Destruct) +{ + nostd::shared_ptr<Span> span(new NoopSpan(nullptr)); + Scope scope(span); + + { + nostd::shared_ptr<Span> span_nested(new NoopSpan(nullptr)); + Scope scope_nested(span_nested); + + context::ContextValue active_span_value = context::RuntimeContext::GetValue(kSpanKey); + ASSERT_TRUE(nostd::holds_alternative<nostd::shared_ptr<Span>>(active_span_value)); + + auto active_span = nostd::get<nostd::shared_ptr<Span>>(active_span_value); + ASSERT_EQ(active_span, span_nested); + } + + context::ContextValue active_span_value = context::RuntimeContext::GetValue(kSpanKey); + ASSERT_TRUE(nostd::holds_alternative<nostd::shared_ptr<Span>>(active_span_value)); + + auto active_span = nostd::get<nostd::shared_ptr<Span>>(active_span_value); + ASSERT_EQ(active_span, span); +} diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_benchmark.cc new file mode 100644 index 000000000..ef14cd4ca --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_benchmark.cc @@ -0,0 +1,129 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/trace/context.h" +#include "opentelemetry/trace/noop.h" +#include "opentelemetry/trace/span_id.h" +#include "opentelemetry/trace/trace_id.h" + +#include <cstdint> + +#include <benchmark/benchmark.h> + +using opentelemetry::trace::SpanContext; +namespace trace_api = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace context = opentelemetry::context; + +namespace +{ + +std::shared_ptr<trace_api::Tracer> initTracer() +{ + return std::shared_ptr<trace_api::Tracer>(new trace_api::NoopTracer()); +} + +// Test to measure performance for span creation +void BM_SpanCreation(benchmark::State &state) +{ + auto tracer = initTracer(); + while (state.KeepRunning()) + { + auto span = tracer->StartSpan("span"); + span->End(); + } +} +BENCHMARK(BM_SpanCreation); + +// Test to measure performance for single span creation with scope +void BM_SpanCreationWithScope(benchmark::State &state) +{ + auto tracer = initTracer(); + while (state.KeepRunning()) + { + auto span = tracer->StartSpan("span"); + auto scope = tracer->WithActiveSpan(span); + span->End(); + } +} +BENCHMARK(BM_SpanCreationWithScope); + +// Test to measure performance for nested span creation with scope +void BM_NestedSpanCreationWithScope(benchmark::State &state) +{ + auto tracer = initTracer(); + while (state.KeepRunning()) + { + auto span = tracer->StartSpan("outer"); + auto scope = tracer->WithActiveSpan(span); + { + auto span = tracer->StartSpan("inner"); + auto scope = tracer->WithActiveSpan(span); + { + auto span = tracer->StartSpan("innermost"); + auto scope = tracer->WithActiveSpan(span); + span->End(); + } + span->End(); + } + span->End(); + } +} + +BENCHMARK(BM_NestedSpanCreationWithScope); + +// Test to measure performance for nested span creation with manual span context management +void BM_SpanCreationWithManualSpanContextPropagation(benchmark::State &state) +{ + auto tracer = initTracer(); + constexpr uint8_t buf1[] = {1, 2, 3, 4, 5, 6, 7, 8}; + trace_api::SpanId span_id(buf1); + constexpr uint8_t buf2[] = {1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}; + trace_api::TraceId trace_id(buf2); + + while (state.KeepRunning()) + { + auto outer_span = nostd::shared_ptr<trace_api::Span>( + new trace_api::DefaultSpan(SpanContext(trace_id, span_id, trace_api::TraceFlags(), false))); + trace_api::StartSpanOptions options; + options.parent = outer_span->GetContext(); + auto inner_span = tracer->StartSpan("inner", options); + auto inner_span_context = inner_span->GetContext(); + options.parent = inner_span_context; + auto innermost_span = tracer->StartSpan("innermost", options); + innermost_span->End(); + inner_span->End(); + } +} +BENCHMARK(BM_SpanCreationWithManualSpanContextPropagation); + +// Test to measure performance for nested span creation with context propagation +void BM_SpanCreationWitContextPropagation(benchmark::State &state) +{ + auto tracer = initTracer(); + constexpr uint8_t buf1[] = {1, 2, 3, 4, 5, 6, 7, 8}; + trace_api::SpanId span_id(buf1); + constexpr uint8_t buf2[] = {1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}; + trace_api::TraceId trace_id(buf2); + + while (state.KeepRunning()) + { + auto current_ctx = context::RuntimeContext::GetCurrent(); + auto outer_span_context = SpanContext(trace_id, span_id, trace_api::TraceFlags(), false); + auto outer_span = + nostd::shared_ptr<trace_api::Span>(new trace_api::DefaultSpan(outer_span_context)); + trace_api::SetSpan(current_ctx, outer_span); + auto inner_child = tracer->StartSpan("inner"); + auto scope = tracer->WithActiveSpan(inner_child); + { + auto innermost_child = tracer->StartSpan("innermost"); + auto scope = tracer->WithActiveSpan(innermost_child); + innermost_child->End(); + } + inner_child->End(); + } +} +BENCHMARK(BM_SpanCreationWitContextPropagation); +} // namespace +BENCHMARK_MAIN(); diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_context_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_context_test.cc new file mode 100644 index 000000000..a3fd9a84a --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_context_test.cc @@ -0,0 +1,55 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/trace/span_context.h" +#include "opentelemetry/trace/span_id.h" +#include "opentelemetry/trace/trace_id.h" + +#include <gtest/gtest.h> + +using opentelemetry::trace::SpanContext; +namespace trace_api = opentelemetry::trace; + +TEST(SpanContextTest, IsSampled) +{ + SpanContext s1(true, true); + + ASSERT_EQ(s1.IsSampled(), true); + + SpanContext s2(false, true); + + ASSERT_EQ(s2.IsSampled(), false); +} + +TEST(SpanContextTest, IsRemote) +{ + SpanContext s1(true, true); + + ASSERT_EQ(s1.IsRemote(), true); + + SpanContext s2(true, false); + + ASSERT_EQ(s2.IsRemote(), false); +} + +TEST(SpanContextTest, TraceFlags) +{ + SpanContext s1(true, true); + + ASSERT_EQ(s1.trace_flags().flags(), 1); + + SpanContext s2(false, true); + + ASSERT_EQ(s2.trace_flags().flags(), 0); +} + +// Test that SpanContext is invalid +TEST(SpanContextTest, Invalid) +{ + SpanContext s1 = SpanContext::GetInvalid(); + EXPECT_FALSE(s1.IsValid()); + + // Test that trace id and span id are invalid + EXPECT_EQ(s1.trace_id(), trace_api::TraceId()); + EXPECT_EQ(s1.span_id(), trace_api::SpanId()); +} diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_id_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_id_benchmark.cc new file mode 100644 index 000000000..42d4aeb46 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_id_benchmark.cc @@ -0,0 +1,55 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/trace/span_id.h" + +#include <benchmark/benchmark.h> +#include <cstdint> + +namespace +{ +using opentelemetry::trace::SpanId; +constexpr uint8_t bytes[] = {1, 2, 3, 4, 5, 6, 7, 8}; + +void BM_SpanIdDefaultConstructor(benchmark::State &state) +{ + while (state.KeepRunning()) + { + benchmark::DoNotOptimize(SpanId()); + } +} +BENCHMARK(BM_SpanIdDefaultConstructor); + +void BM_SpanIdConstructor(benchmark::State &state) +{ + while (state.KeepRunning()) + { + benchmark::DoNotOptimize(SpanId(bytes)); + } +} +BENCHMARK(BM_SpanIdConstructor); + +void BM_SpanIdToLowerBase16(benchmark::State &state) +{ + SpanId id(bytes); + char buf[SpanId::kSize * 2]; + while (state.KeepRunning()) + { + id.ToLowerBase16(buf); + benchmark::DoNotOptimize(buf); + } +} +BENCHMARK(BM_SpanIdToLowerBase16); + +void BM_SpanIdIsValid(benchmark::State &state) +{ + SpanId id(bytes); + while (state.KeepRunning()) + { + benchmark::DoNotOptimize(id.IsValid()); + } +} +BENCHMARK(BM_SpanIdIsValid); + +} // namespace +BENCHMARK_MAIN(); diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_id_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_id_test.cc new file mode 100644 index 000000000..52bb9b7de --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/span_id_test.cc @@ -0,0 +1,58 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/trace/span_id.h" + +#include <cstring> +#include <string> + +#include <gtest/gtest.h> + +namespace +{ + +using opentelemetry::trace::SpanId; + +std::string Hex(const opentelemetry::trace::SpanId &span) +{ + char buf[16]; + span.ToLowerBase16(buf); + return std::string(buf, sizeof(buf)); +} + +TEST(SpanIdTest, DefaultConstruction) +{ + SpanId id; + EXPECT_FALSE(id.IsValid()); + EXPECT_EQ("0000000000000000", Hex(id)); +} + +TEST(SpanIdTest, ValidId) +{ + constexpr uint8_t buf[] = {1, 2, 3, 4, 5, 6, 7, 8}; + SpanId id(buf); + EXPECT_TRUE(id.IsValid()); + EXPECT_EQ("0102030405060708", Hex(id)); + EXPECT_NE(SpanId(), id); + EXPECT_EQ(SpanId(buf), id); +} + +TEST(SpanIdTest, LowercaseBase16) +{ + constexpr uint8_t buf[] = {1, 2, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; + SpanId id(buf); + EXPECT_TRUE(id.IsValid()); + EXPECT_EQ("0102aabbccddeeff", Hex(id)); + EXPECT_NE(SpanId(), id); + EXPECT_EQ(SpanId(buf), id); +} + +TEST(SpanIdTest, CopyBytesTo) +{ + constexpr uint8_t src[] = {1, 2, 3, 4, 5, 6, 7, 8}; + SpanId id(src); + uint8_t buf[8]; + id.CopyBytesTo(buf); + EXPECT_TRUE(memcmp(src, buf, 8) == 0); +} +} // namespace diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/trace_flags_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/trace_flags_test.cc new file mode 100644 index 000000000..783b56d83 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/trace_flags_test.cc @@ -0,0 +1,43 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/trace/trace_flags.h" + +#include <cstring> +#include <string> + +#include <gtest/gtest.h> + +namespace +{ + +using opentelemetry::trace::TraceFlags; + +std::string Hex(const TraceFlags &flags) +{ + char buf[2]; + flags.ToLowerBase16(buf); + return std::string(buf, sizeof(buf)); +} + +TEST(TraceFlagsTest, DefaultConstruction) +{ + TraceFlags flags; + EXPECT_FALSE(flags.IsSampled()); + EXPECT_EQ(0, flags.flags()); + EXPECT_EQ("00", Hex(flags)); +} + +TEST(TraceFlagsTest, Sampled) +{ + TraceFlags flags{TraceFlags::kIsSampled}; + EXPECT_TRUE(flags.IsSampled()); + EXPECT_EQ(1, flags.flags()); + EXPECT_EQ("01", Hex(flags)); + + uint8_t buf[1]; + flags.CopyBytesTo(buf); + EXPECT_EQ(1, buf[0]); +} + +} // namespace diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/trace_id_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/trace_id_test.cc new file mode 100644 index 000000000..f903bfe9e --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/trace_id_test.cc @@ -0,0 +1,58 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/trace/trace_id.h" + +#include <cstring> +#include <string> + +#include <gtest/gtest.h> + +namespace +{ + +using opentelemetry::trace::TraceId; + +std::string Hex(const opentelemetry::trace::TraceId &trace) +{ + char buf[32]; + trace.ToLowerBase16(buf); + return std::string(buf, sizeof(buf)); +} + +TEST(TraceIdTest, DefaultConstruction) +{ + TraceId id; + EXPECT_FALSE(id.IsValid()); + EXPECT_EQ("00000000000000000000000000000000", Hex(id)); +} + +TEST(TraceIdTest, ValidId) +{ + constexpr uint8_t buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}; + TraceId id(buf); + EXPECT_TRUE(id.IsValid()); + EXPECT_EQ("01020304050607080807060504030201", Hex(id)); + EXPECT_NE(TraceId(), id); + EXPECT_EQ(TraceId(buf), id); +} + +TEST(TraceIdTest, LowercaseBase16) +{ + constexpr uint8_t buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; + TraceId id(buf); + EXPECT_TRUE(id.IsValid()); + EXPECT_EQ("01020304050607080807aabbccddeeff", Hex(id)); + EXPECT_NE(TraceId(), id); + EXPECT_EQ(TraceId(buf), id); +} + +TEST(TraceIdTest, CopyBytesTo) +{ + constexpr uint8_t src[] = {1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}; + TraceId id(src); + uint8_t buf[TraceId::kSize]; + id.CopyBytesTo(buf); + EXPECT_TRUE(memcmp(src, buf, sizeof(buf)) == 0); +} +} // namespace diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/trace_state_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/trace_state_test.cc new file mode 100644 index 000000000..ed6c7e827 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/trace_state_test.cc @@ -0,0 +1,196 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/trace/trace_state.h" + +#include <gtest/gtest.h> +#include "opentelemetry/nostd/string_view.h" + +namespace +{ + +using opentelemetry::trace::TraceState; +namespace nostd = opentelemetry::nostd; + +// Random string of length 257. Used for testing strings with max length 256. +const char *kLongString = + "4aekid3he76zgytjavudqqeltyvu5zqio2lx7d92dlxlf0z4883irvxuwelsq27sx1mlrjg3r7ad3jeq09rjppyd9veorg" + "2nmihy4vilabfts8bsxruih0urusmjnglzl3iwpjinmo835dbojcrd73p56nw80v4xxrkye59ytmu5v84ysfa24d58ovv9" + "w1n54n0mhhf4z0mpv6oudywrp9vfoks6lrvxv3uihvbi2ihazf237kvt1nbsjn3kdvfdb"; + +// -------------------------- TraceState class tests --------------------------- + +std::string create_ts_return_header(std::string header) +{ + auto ts = TraceState::FromHeader(header); + return ts->ToHeader(); +} + +std::string header_with_max_members() +{ + std::string header = ""; + auto max_members = TraceState::kMaxKeyValuePairs; + for (int i = 0; i < max_members; i++) + { + std::string key = "key" + std::to_string(i); + std::string value = "value" + std::to_string(i); + header += key + "=" + value; + if (i != max_members - 1) + { + header += ","; + } + } + return header; +} + +TEST(TraceStateTest, ValidateHeaderParsing) +{ + auto max_trace_state_header = header_with_max_members(); + + struct + { + const char *input; + const char *expected; + } testcases[] = {{"k1=v1", "k1=v1"}, + {"K1=V1", ""}, + {"k1=v1,k2=v2,k3=v3", "k1=v1,k2=v2,k3=v3"}, + {"k1=v1,k2=v2,,", "k1=v1,k2=v2"}, + {"k1=v1,k2=v2,invalidmember", ""}, + {"1a-2f@foo=bar1,a*/foo-_/bar=bar4", "1a-2f@foo=bar1,a*/foo-_/bar=bar4"}, + {"1a-2f@foo=bar1,*/foo-_/bar=bar4", ""}, + {",k1=v1", "k1=v1"}, + {",", ""}, + {",=,", ""}, + {"", ""}, + {max_trace_state_header.data(), max_trace_state_header.data()}}; + for (auto &testcase : testcases) + { + EXPECT_EQ(create_ts_return_header(testcase.input), testcase.expected); + } +} + +TEST(TraceStateTest, TraceStateGet) +{ + + std::string trace_state_header = header_with_max_members(); + auto ts = TraceState::FromHeader(trace_state_header); + + std::string value; + EXPECT_TRUE(ts->Get("key0", value)); + EXPECT_EQ(value, "value0"); + EXPECT_TRUE(ts->Get("key16", value)); + EXPECT_EQ(value, "value16"); + EXPECT_TRUE(ts->Get("key31", value)); + EXPECT_EQ(value, "value31"); + EXPECT_FALSE(ts->Get("key32", value)); +} + +TEST(TraceStateTest, TraceStateSet) +{ + std::string trace_state_header = "k1=v1,k2=v2"; + auto ts1 = TraceState::FromHeader(trace_state_header); + auto ts1_new = ts1->Set("k3", "v3"); + EXPECT_EQ(ts1_new->ToHeader(), "k3=v3,k1=v1,k2=v2"); + + trace_state_header = header_with_max_members(); + auto ts2 = TraceState::FromHeader(trace_state_header); + auto ts2_new = + ts2->Set("n_k1", "n_v1"); // adding to max list, should return copy of existing list + EXPECT_EQ(ts2_new->ToHeader(), trace_state_header); + + trace_state_header = "k1=v1,k2=v2"; + auto ts3 = TraceState::FromHeader(trace_state_header); + auto ts3_new = ts3->Set("*n_k1", "n_v1"); // adding invalid key, should return empty + EXPECT_EQ(ts3_new->ToHeader(), ""); +} + +TEST(TraceStateTest, TraceStateDelete) +{ + std::string trace_state_header = "k1=v1,k2=v2,k3=v3"; + auto ts1 = TraceState::FromHeader(trace_state_header); + auto ts1_new = ts1->Delete(std::string("k1")); + EXPECT_EQ(ts1_new->ToHeader(), "k2=v2,k3=v3"); + + trace_state_header = "k1=v1"; // single list member + auto ts2 = TraceState::FromHeader(trace_state_header); + auto ts2_new = ts2->Delete(std::string("k1")); + EXPECT_EQ(ts2_new->ToHeader(), ""); + + trace_state_header = "k1=v1"; // single list member, delete invalid entry + auto ts3 = TraceState::FromHeader(trace_state_header); + auto ts3_new = ts3->Delete(std::string("InvalidKey")); + EXPECT_EQ(ts3_new->ToHeader(), ""); +} + +TEST(TraceStateTest, Empty) +{ + std::string trace_state_header = ""; + auto ts = TraceState::FromHeader(trace_state_header); + EXPECT_TRUE(ts->Empty()); + + trace_state_header = "k1=v1,k2=v2"; + auto ts1 = TraceState::FromHeader(trace_state_header); + EXPECT_FALSE(ts1->Empty()); +} + +TEST(TraceStateTest, GetAllEntries) +{ + std::string trace_state_header = "k1=v1,k2=v2,k3=v3"; + auto ts1 = TraceState::FromHeader(trace_state_header); + const int kNumPairs = 3; + nostd::string_view keys[kNumPairs] = {"k1", "k2", "k3"}; + nostd::string_view values[kNumPairs] = {"v1", "v2", "v3"}; + size_t index = 0; + ts1->GetAllEntries([&keys, &values, &index](nostd::string_view key, nostd::string_view value) { + EXPECT_EQ(key, keys[index]); + EXPECT_EQ(value, values[index]); + index++; + return true; + }); +} + +TEST(TraceStateTest, IsValidKey) +{ + EXPECT_TRUE(TraceState::IsValidKey("valid-key23/*")); + EXPECT_FALSE(TraceState::IsValidKey("Invalid_key")); + EXPECT_FALSE(TraceState::IsValidKey("invalid$Key&")); + EXPECT_FALSE(TraceState::IsValidKey("")); + EXPECT_FALSE(TraceState::IsValidKey(kLongString)); +} + +TEST(TraceStateTest, IsValidValue) +{ + EXPECT_TRUE(TraceState::IsValidValue("valid-val$%&~")); + EXPECT_FALSE(TraceState::IsValidValue("\tinvalid")); + EXPECT_FALSE(TraceState::IsValidValue("invalid=")); + EXPECT_FALSE(TraceState::IsValidValue("invalid,val")); + EXPECT_FALSE(TraceState::IsValidValue("")); + EXPECT_FALSE(TraceState::IsValidValue(kLongString)); +} + +// Tests that keys and values don't depend on null terminators +TEST(TraceStateTest, MemorySafe) +{ + std::string trace_state_header = ""; + auto ts = TraceState::FromHeader(trace_state_header); + const int kNumPairs = 3; + nostd::string_view key_string = "test_key_1test_key_2test_key_3"; + nostd::string_view val_string = "test_val_1test_val_2test_val_3"; + nostd::string_view keys[kNumPairs] = {key_string.substr(0, 10), key_string.substr(10, 10), + key_string.substr(20, 10)}; + nostd::string_view values[kNumPairs] = {val_string.substr(0, 10), val_string.substr(10, 10), + val_string.substr(20, 10)}; + + auto ts1 = ts->Set(keys[2], values[2]); + auto ts2 = ts1->Set(keys[1], values[1]); + auto ts3 = ts2->Set(keys[0], values[0]); + size_t index = 0; + + ts3->GetAllEntries([&keys, &values, &index](nostd::string_view key, nostd::string_view value) { + EXPECT_EQ(key, keys[index]); + EXPECT_EQ(value, values[index]); + index++; + return true; + }); +} +} // namespace diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/trace/tracer_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/trace/tracer_test.cc new file mode 100644 index 000000000..8e16f15e2 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/test/trace/tracer_test.cc @@ -0,0 +1,39 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/trace/noop.h" +#include "opentelemetry/trace/scope.h" + +#include <gtest/gtest.h> + +namespace trace_api = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace context = opentelemetry::context; + +TEST(TracerTest, GetCurrentSpan) +{ + std::unique_ptr<trace_api::Tracer> tracer(new trace_api::NoopTracer()); + nostd::shared_ptr<trace_api::Span> span_first(new trace_api::NoopSpan(nullptr)); + nostd::shared_ptr<trace_api::Span> span_second(new trace_api::NoopSpan(nullptr)); + + auto current = tracer->GetCurrentSpan(); + ASSERT_FALSE(current->GetContext().IsValid()); + + { + auto scope_first = tracer->WithActiveSpan(span_first); + current = tracer->GetCurrentSpan(); + ASSERT_EQ(current, span_first); + + { + auto scope_second = tracer->WithActiveSpan(span_second); + current = tracer->GetCurrentSpan(); + ASSERT_EQ(current, span_second); + } + current = tracer->GetCurrentSpan(); + ASSERT_EQ(current, span_first); + } + + current = tracer->GetCurrentSpan(); + ASSERT_FALSE(current->GetContext().IsValid()); +} |