diff --git a/opentracing-shim/include/propagation.h b/opentracing-shim/include/propagation.h new file mode 100644 index 0000000000..19d0da73fb --- /dev/null +++ b/opentracing-shim/include/propagation.h @@ -0,0 +1,96 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "opentelemetry/baggage/baggage.h" +#include "opentelemetry/common/attribute_value.h" +#include "opentelemetry/context/propagation/text_map_propagator.h" +#include "opentelemetry/nostd/type_traits.h" +#include "opentracing/propagation.h" +#include "opentracing/value.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace opentracingshim +{ + +template::value, bool> = true> +class CarrierWriterShim : public opentelemetry::context::propagation::TextMapCarrier +{ +public: + CarrierWriterShim(const T& writer) : writer_(writer) {} + + // returns the value associated with the passed key. + virtual nostd::string_view Get(nostd::string_view key) const noexcept override + { + return ""; + } + + // stores the key-value pair. + virtual void Set(nostd::string_view key, nostd::string_view value) noexcept override + { + writer_.Set(key.data(), value.data()); + } + +private: + const T& writer_; +}; + +template::value, bool> = true> +class CarrierReaderShim : public opentelemetry::context::propagation::TextMapCarrier +{ +public: + CarrierReaderShim(const T& reader) : reader_(reader) {} + + // returns the value associated with the passed key. + virtual nostd::string_view Get(nostd::string_view key) const noexcept override + { + nostd::string_view value; + + // First try carrier.LookupKey since that can potentially be the fastest approach. + if (auto result = reader_.LookupKey(key.data())) + { + value = result.value().data(); + } + else // Fall back to iterating through all of the keys. + { + reader_.ForeachKey([key, &value] + (opentracing::string_view k, opentracing::string_view v) -> opentracing::expected { + if (k == key.data()) + { + value = v.data(); + // Found key, so bail out of the loop with a success error code. + return opentracing::make_unexpected(std::error_code{}); + } + return opentracing::make_expected(); + }); + } + + return value; + } + + // stores the key-value pair. + virtual void Set(nostd::string_view key, nostd::string_view value) noexcept override + { + // Not required for Opentracing reader + } + + // list of all the keys in the carrier. + virtual bool Keys(nostd::function_ref callback) const noexcept override + { + return reader_.ForeachKey([&callback] + (opentracing::string_view key, opentracing::string_view) -> opentracing::expected { + return callback(key.data()) + ? opentracing::make_expected() + : opentracing::make_unexpected(std::error_code{}); + }).has_value(); + } + +private: + const T& reader_; +}; + +} // namespace opentracingshim +OPENTELEMETRY_END_NAMESPACE diff --git a/opentracing-shim/include/shim_utils.h b/opentracing-shim/include/shim_utils.h index 87e1951140..89dad026a6 100644 --- a/opentracing-shim/include/shim_utils.h +++ b/opentracing-shim/include/shim_utils.h @@ -5,12 +5,20 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include "span_context_shim.h" + +#include "opentelemetry/baggage/baggage.h" +#include "opentelemetry/baggage/baggage_context.h" +#include "opentelemetry/common/attribute_value.h" +#include "opentelemetry/context/propagation/text_map_propagator.h" +#include "opentelemetry/nostd/type_traits.h" +#include "opentelemetry/trace/semantic_conventions.h" +#include "opentelemetry/trace/tracer.h" +#include "opentracing/propagation.h" +#include "opentracing/tracer.h" +#include "opentracing/value.h" + +#include OPENTELEMETRY_BEGIN_NAMESPACE namespace opentracingshim::utils @@ -56,92 +64,126 @@ static inline std::string stringFromValue(const opentracing::Value& value) return opentracing::Value::visit(value, StringMapper); } -template::value, bool> = true> -class CarrierWriterShim : public opentelemetry::context::propagation::TextMapCarrier +static inline bool isBaggageEmpty(const nostd::shared_ptr& baggage) { -public: - CarrierWriterShim(const T& writer) : writer_(writer) {} - - // returns the value associated with the passed key. - virtual nostd::string_view Get(nostd::string_view key) const noexcept override + if (baggage) { - return ""; + return baggage->GetAllEntries([](nostd::string_view, nostd::string_view){ + return false; + }); } - // stores the key-value pair. - virtual void Set(nostd::string_view key, nostd::string_view value) noexcept override + return true; +} + +static opentelemetry::trace::StartSpanOptions makeOptionsShim(const opentracing::StartSpanOptions& options) noexcept +{ + using opentracing::SpanReferenceType; + // If an explicit start timestamp is specified, a conversion MUST + // be done to match the OpenTracing and OpenTelemetry units. + opentelemetry::trace::StartSpanOptions options_shim; + options_shim.start_system_time = opentelemetry::common::SystemTimestamp{options.start_system_timestamp}; + options_shim.start_steady_time = opentelemetry::common::SteadyTimestamp{options.start_steady_timestamp}; + + const auto& refs = options.references; + // If a list of Span references is specified... + if (!refs.empty()) { - writer_.Set(key.data(), value.data()); + auto first_child_of = std::find_if(refs.cbegin(), refs.cend(), + [](const std::pair& entry){ + return entry.first == SpanReferenceType::ChildOfRef; + }); + // The first SpanContext with Child Of type in the entire list is used as parent, + // else the first SpanContext is used as parent + auto context = (first_child_of != refs.cend()) ? first_child_of->second : refs.cbegin()->second; + + if (auto context_shim = dynamic_cast(context)) + { + options_shim.parent = context_shim->context(); + } } -private: - const T& writer_; -}; + return options_shim; +} -template::value, bool> = true> -class CarrierReaderShim : public opentelemetry::context::propagation::TextMapCarrier -{ -public: - CarrierReaderShim(const T& reader) : reader_(reader) {} +using RefsList = std::vector>; +using LinksList = std::vector>; - // returns the value associated with the passed key. - virtual nostd::string_view Get(nostd::string_view key) const noexcept override +static LinksList makeReferenceLinks(const opentracing::StartSpanOptions& options) noexcept +{ + using opentracing::SpanReferenceType; + using namespace opentelemetry::trace::SemanticConventions; + + LinksList links; + links.reserve(options.references.size()); + // All values in the list MUST be added as Links with the reference type value + // as a Link attribute, i.e. opentracing.ref_type set to follows_from or child_of + for (const auto& entry : options.references) { - nostd::string_view value; + auto context_shim = dynamic_cast(entry.second); + nostd::string_view span_kind; - // First try carrier.LookupKey since that can potentially be the fastest approach. - if (auto result = reader_.LookupKey(key.data())) + if (entry.first == SpanReferenceType::ChildOfRef) { - value = result.value().data(); + span_kind = OpentracingRefTypeValues::kChildOf; } - else // Fall back to iterating through all of the keys. + else if (entry.first == SpanReferenceType::FollowsFromRef) { - reader_.ForeachKey([key, &value] - (opentracing::string_view k, opentracing::string_view v) -> opentracing::expected { - if (k == key.data()) - { - value = v.data(); - // Found key, so bail out of the loop with a success error code. - return opentracing::make_unexpected(std::error_code{}); - } - return opentracing::make_expected(); - }); + span_kind = OpentracingRefTypeValues::kFollowsFrom; } - return value; + if (context_shim && !span_kind.empty()) + { + links.emplace_back(std::piecewise_construct, + std::forward_as_tuple(context_shim->context()), + std::forward_as_tuple(std::forward({{ kOpentracingRefType, span_kind }}))); + } } - // stores the key-value pair. - virtual void Set(nostd::string_view key, nostd::string_view value) noexcept override - { - // Not required for Opentracing reader - } + return links; +} - // list of all the keys in the carrier. - virtual bool Keys(nostd::function_ref callback) const noexcept override +static nostd::shared_ptr makeBaggage(const opentracing::StartSpanOptions& options) noexcept +{ + using namespace opentelemetry::baggage; + + std::unordered_map baggage_items; + // If a list of Span references is specified... + for (const auto& entry : options.references) { - return reader_.ForeachKey([&callback] - (opentracing::string_view key, opentracing::string_view) -> opentracing::expected { - return callback(key.data()) - ? opentracing::make_expected() - : opentracing::make_unexpected(std::error_code{}); - }).has_value(); + if (auto context_shim = dynamic_cast(entry.second)) + { + // The union of their Baggage values MUST be used as the initial Baggage of the newly created Span. + context_shim->ForeachBaggageItem([&baggage_items](const std::string& key, const std::string& value){ + // It is unspecified which Baggage value is used in the case of repeated keys. + if (baggage_items.find(key) == baggage_items.end()) + { + baggage_items.emplace(key, value); // Here, only insert if key not already present + } + return true; + }); + } } + // If no such list of references is specified, the current Baggage + // MUST be used as the initial value of the newly created Span. + return baggage_items.empty() + ? GetBaggage(opentelemetry::context::RuntimeContext::GetCurrent()) + : nostd::shared_ptr(new Baggage(baggage_items)); +} -private: - const T& reader_; -}; - -static inline bool isBaggageEmpty(const nostd::shared_ptr& baggage) +static std::vector> makeTags(const opentracing::StartSpanOptions& options) noexcept { - if (baggage) + std::vector> tags; + tags.reserve(options.tags.size()); + + // If an initial set of tags is specified, the values MUST + // be set at the creation time of the OpenTelemetry Span. + for (const auto& entry : options.tags) { - return baggage->GetAllEntries([](nostd::string_view, nostd::string_view){ - return false; - }); + tags.emplace_back(entry.first, utils::attributeFromValue(entry.second)); } - return true; + return tags; } } // namespace opentracingshim::utils diff --git a/opentracing-shim/src/span_shim.cc b/opentracing-shim/src/span_shim.cc index 1f1be112c4..b40b897d0a 100644 --- a/opentracing-shim/src/span_shim.cc +++ b/opentracing-shim/src/span_shim.cc @@ -10,7 +10,7 @@ #include "opentelemetry/trace/semantic_conventions.h" #include "opentelemetry/trace/span_metadata.h" -#include +#include "opentracing/ext/tags.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace opentracingshim diff --git a/opentracing-shim/src/tracer_shim.cc b/opentracing-shim/src/tracer_shim.cc index e6674e328e..9e402d45c5 100644 --- a/opentracing-shim/src/tracer_shim.cc +++ b/opentracing-shim/src/tracer_shim.cc @@ -6,142 +6,25 @@ #include "tracer_shim.h" #include "span_shim.h" #include "shim_utils.h" +#include "propagation.h" -#include -#include -#include -#include -#include +#include "opentelemetry/context/propagation/global_propagator.h" +#include "opentelemetry/trace/context.h" +#include "opentracing/ext/tags.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace opentracingshim { -namespace detail -{ - -using RefsList = std::initializer_list>; -using LinksList = std::vector>; - -static opentelemetry::trace::StartSpanOptions makeOptionsShim(const opentracing::StartSpanOptions& options) noexcept -{ - using opentracing::SpanReferenceType; - // If an explicit start timestamp is specified, a conversion MUST - // be done to match the OpenTracing and OpenTelemetry units. - opentelemetry::trace::StartSpanOptions options_shim; - options_shim.start_system_time = opentelemetry::common::SystemTimestamp{options.start_system_timestamp}; - options_shim.start_steady_time = opentelemetry::common::SteadyTimestamp{options.start_steady_timestamp}; - - const auto& refs = options.references; - // If a list of Span references is specified... - if (!refs.empty()) - { - auto first_child_of = std::find_if(refs.cbegin(), refs.cend(), - [](const std::pair& entry){ - return entry.first == SpanReferenceType::ChildOfRef; - }); - // The first SpanContext with Child Of type in the entire list is used as parent, - // else the first SpanContext is used as parent - auto context = (first_child_of != refs.cend()) ? first_child_of->second : refs.cbegin()->second; - - if (auto context_shim = dynamic_cast(context)) - { - options_shim.parent = context_shim->context(); - } - } - - return options_shim; -} - -static LinksList makeReferenceLinks(const opentracing::StartSpanOptions& options) noexcept -{ - using opentracing::SpanReferenceType; - using namespace opentelemetry::trace::SemanticConventions; - - LinksList links; - links.reserve(options.references.size()); - // All values in the list MUST be added as Links with the reference type value - // as a Link attribute, i.e. opentracing.ref_type set to follows_from or child_of - for (const auto& entry : options.references) - { - auto context_shim = dynamic_cast(entry.second); - nostd::string_view span_kind; - - if (entry.first == SpanReferenceType::ChildOfRef) - { - span_kind = OpentracingRefTypeValues::kChildOf; - } - else if (entry.first == SpanReferenceType::FollowsFromRef) - { - span_kind = OpentracingRefTypeValues::kFollowsFrom; - } - - if (context_shim && !span_kind.empty()) - { - // links.push_back({ context_shim->context(), {{ opentracing::ext::span_kind.data(), span_kind }} }); - links.emplace_back(std::piecewise_construct, - std::forward_as_tuple(context_shim->context()), - std::forward_as_tuple(std::forward({{ opentracing::ext::span_kind.data(), span_kind }}))); - } - } - - return links; -} - -static BaggagePtr makeBaggage(const opentracing::StartSpanOptions& options) noexcept -{ - using namespace opentelemetry::baggage; - - std::unordered_map baggage_items; - // If a list of Span references is specified... - for (const auto& entry : options.references) - { - if (auto context_shim = dynamic_cast(entry.second)) - { - // The union of their Baggage values MUST be used as the initial Baggage of the newly created Span. - context_shim->ForeachBaggageItem([&baggage_items](const std::string& key, const std::string& value){ - // It is unspecified which Baggage value is used in the case of repeated keys. - if (baggage_items.find(key) == baggage_items.end()) - { - baggage_items.emplace(key, value); // Here, only insert if key not already present - } - return true; - }); - } - } - // If no such lisf of references is specified, the current Baggage - // MUST be used as the initial value of the newly created Span. - return baggage_items.empty() - ? GetBaggage(opentelemetry::context::RuntimeContext::GetCurrent()) - : nostd::shared_ptr(new Baggage(baggage_items)); -} - -static std::vector> makeTags(const opentracing::StartSpanOptions& options) noexcept -{ - std::vector> tags; - tags.reserve(options.tags.size()); - - // If an initial set of tags is specified, the values MUST - // be set at the creation time of the OpenTelemetry Span. - for (const auto& entry : options.tags) - { - tags.emplace_back(entry.first, utils::attributeFromValue(entry.second)); - } - - return tags; -} - -} // namespace opentracingshim::detail - std::unique_ptr TracerShim::StartSpanWithOptions(opentracing::string_view operation_name, const opentracing::StartSpanOptions& options) const noexcept { if (is_closed_) return nullptr; - const auto& opts = detail::makeOptionsShim(options); - const auto& links = detail::makeReferenceLinks(options); - const auto& baggage = detail::makeBaggage(options); - const auto& attributes = detail::makeTags(options); + const auto& opts = utils::makeOptionsShim(options); + const auto& links = utils::makeReferenceLinks(options); + const auto& baggage = utils::makeBaggage(options); + const auto& attributes = utils::makeTags(options); auto span = tracer_->StartSpan(operation_name.data(), attributes, links, opts); auto span_shim = new SpanShim(*this, span, baggage); @@ -233,11 +116,12 @@ opentracing::expected TracerShim::injectImpl(const opentracing::SpanContex // It MUST inject any non-empty Baggage even amidst no valid SpanContext. const auto& context = opentelemetry::baggage::SetBaggage(current_context, context_shim->baggage()); - utils::CarrierWriterShim carrier{writer}; + CarrierWriterShim carrier{writer}; propagator->Inject(carrier, context); + return opentracing::make_expected(); } - return opentracing::make_expected(); + return opentracing::make_unexpected(opentracing::invalid_span_context_error); } template @@ -246,7 +130,7 @@ opentracing::expected> TracerShim::ext { // Extract the underlying OpenTelemetry Span and Baggage using either the explicitly registered // or the global OpenTelemetry Propagators, as configured at construction time. - utils::CarrierReaderShim carrier{reader}; + CarrierReaderShim carrier{reader}; auto current_context = opentelemetry::context::RuntimeContext::GetCurrent(); auto context = propagator->Extract(carrier, current_context); auto span_context = opentelemetry::trace::GetSpan(context)->GetContext(); diff --git a/opentracing-shim/test/propagation_test.cc b/opentracing-shim/test/propagation_test.cc new file mode 100644 index 0000000000..717cb99c9a --- /dev/null +++ b/opentracing-shim/test/propagation_test.cc @@ -0,0 +1,115 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "propagation.h" +#include "shim_mocks.h" + +#include + +namespace baggage = opentelemetry::baggage; +namespace common = opentelemetry::common; +namespace nostd = opentelemetry::nostd; +namespace shim = opentelemetry::opentracingshim; + +class PropagationTest : public testing::Test +{ +protected: + virtual void SetUp() + { + } + + virtual void TearDown() + { + } +}; + +TEST_F(PropagationTest, TextMapReader_Get_LookupKey_Unsupported) +{ + std::unordered_map text_map; + TextMapCarrier testee{text_map}; + ASSERT_FALSE(testee.supports_lookup); + ASSERT_EQ(testee.foreach_key_call_count, 0); + + shim::CarrierReaderShim tester{testee}; + auto lookup_unsupported = testee.LookupKey("foo"); + ASSERT_TRUE(text_map.empty()); + ASSERT_TRUE(opentracing::are_errors_equal(lookup_unsupported.error(), opentracing::lookup_key_not_supported_error)); + ASSERT_EQ(tester.Get("foo"), nostd::string_view{}); + ASSERT_EQ(testee.foreach_key_call_count, 1); + + text_map["foo"] = "bar"; + auto lookup_found = testee.LookupKey("foo"); + ASSERT_FALSE(text_map.empty()); + ASSERT_TRUE(opentracing::are_errors_equal(lookup_unsupported.error(), opentracing::lookup_key_not_supported_error)); + ASSERT_EQ(tester.Get("foo"), nostd::string_view{"bar"}); + ASSERT_EQ(testee.foreach_key_call_count, 2); +} + +TEST_F(PropagationTest, TextMapReader_Get_LookupKey_Supported) +{ + std::unordered_map text_map; + TextMapCarrier testee{text_map}; + testee.supports_lookup = true; + ASSERT_TRUE(testee.supports_lookup); + ASSERT_EQ(testee.foreach_key_call_count, 0); + + shim::CarrierReaderShim tester{testee}; + auto lookup_not_found = testee.LookupKey("foo"); + ASSERT_TRUE(text_map.empty()); + ASSERT_TRUE(opentracing::are_errors_equal(lookup_not_found.error(), opentracing::key_not_found_error)); + ASSERT_EQ(tester.Get("foo"), nostd::string_view{}); + ASSERT_EQ(testee.foreach_key_call_count, 1); + + text_map["foo"] = "bar"; + auto lookup_found = testee.LookupKey("foo"); + ASSERT_FALSE(text_map.empty()); + ASSERT_EQ(lookup_found.value(), opentracing::string_view{"bar"}); + ASSERT_EQ(tester.Get("foo"), nostd::string_view{"bar"}); + ASSERT_EQ(testee.foreach_key_call_count, 1); +} + +TEST_F(PropagationTest, TextMapReader_Keys) +{ + std::unordered_map text_map; + TextMapCarrier testee{text_map}; + ASSERT_EQ(testee.foreach_key_call_count, 0); + + shim::CarrierReaderShim tester{testee}; + std::vector kvs; + auto callback = [&text_map,&kvs](nostd::string_view k){ + kvs.emplace_back(k); + return !text_map.empty(); + }; + + ASSERT_TRUE(tester.Keys(callback)); + ASSERT_TRUE(text_map.empty()); + ASSERT_TRUE(kvs.empty()); + ASSERT_EQ(testee.foreach_key_call_count, 1); + + text_map["foo"] = "bar"; + text_map["bar"] = "baz"; + text_map["baz"] = "foo"; + ASSERT_TRUE(tester.Keys(callback)); + ASSERT_FALSE(text_map.empty()); + ASSERT_EQ(text_map.size(), kvs.size()); + ASSERT_EQ(testee.foreach_key_call_count, 2); +} + +TEST_F(PropagationTest, TextMapWriter_Set) +{ + std::unordered_map text_map; + TextMapCarrier testee{text_map}; + shim::CarrierWriterShim tester{testee}; + ASSERT_TRUE(text_map.empty()); + + tester.Set("foo", "bar"); + tester.Set("bar", "baz"); + tester.Set("baz", "foo"); + ASSERT_FALSE(text_map.empty()); + ASSERT_EQ(text_map.size(), 3); + ASSERT_EQ(text_map["foo"], "bar"); + ASSERT_EQ(text_map["bar"], "baz"); + ASSERT_EQ(text_map["baz"], "foo"); +} \ No newline at end of file diff --git a/opentracing-shim/test/shim_mocks.h b/opentracing-shim/test/shim_mocks.h index 1a74ae1f49..7994dcdec9 100644 --- a/opentracing-shim/test/shim_mocks.h +++ b/opentracing-shim/test/shim_mocks.h @@ -5,12 +5,12 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include "opentelemetry/baggage/baggage_context.h" +#include "opentelemetry/trace/span.h" +#include "opentelemetry/trace/span_context.h" +#include "opentelemetry/trace/span_metadata.h" +#include "opentelemetry/trace/tracer.h" +#include "opentracing/propagation.h" #include #include diff --git a/opentracing-shim/test/shim_utils_test.cc b/opentracing-shim/test/shim_utils_test.cc index 665f070b9c..ca459079f5 100644 --- a/opentracing-shim/test/shim_utils_test.cc +++ b/opentracing-shim/test/shim_utils_test.cc @@ -6,12 +6,15 @@ #include "shim_utils.h" #include "shim_mocks.h" +#include "opentracing/tracer.h" + #include -namespace baggage = opentelemetry::baggage; -namespace common = opentelemetry::common; -namespace nostd = opentelemetry::nostd; -namespace shim = opentelemetry::opentracingshim; +namespace trace_api = opentelemetry::trace; +namespace baggage = opentelemetry::baggage; +namespace common = opentelemetry::common; +namespace nostd = opentelemetry::nostd; +namespace shim = opentelemetry::opentracingshim; class ShimUtilsTest : public testing::Test { @@ -106,91 +109,168 @@ TEST_F(ShimUtilsTest, AttributeFromValue) ASSERT_EQ(nostd::get(value), nostd::string_view{}); } -TEST_F(ShimUtilsTest, TextMapReader_Get_LookupKey_Unsupported) +TEST_F(ShimUtilsTest, MakeOptionsShim_EmptyRefs) +{ + auto span_context_shim = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), baggage::Baggage::GetDefault())); + auto span_context = static_cast(span_context_shim.get()); + + opentracing::StartSpanOptions options; + options.start_system_timestamp = opentracing::SystemTime::time_point::clock::now(); + options.start_steady_timestamp = opentracing::SteadyTime::time_point::clock::now(); + + auto options_shim = shim::utils::makeOptionsShim(options); + ASSERT_EQ(options_shim.start_system_time, common::SystemTimestamp{options.start_system_timestamp}); + ASSERT_EQ(options_shim.start_steady_time, common::SteadyTimestamp{options.start_steady_timestamp}); + ASSERT_EQ(nostd::get(options_shim.parent), trace_api::SpanContext::GetInvalid()); +} + +TEST_F(ShimUtilsTest, MakeOptionsShim_InvalidSpanContext) +{ + auto span_context_shim = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), baggage::Baggage::GetDefault())); + auto span_context = static_cast(span_context_shim.get()); + + opentracing::StartSpanOptions options; + options.start_system_timestamp = opentracing::SystemTime::time_point::clock::now(); + options.start_steady_timestamp = opentracing::SteadyTime::time_point::clock::now(); + options.references = {{ opentracing::SpanReferenceType::FollowsFromRef, nullptr }}; + + auto options_shim = shim::utils::makeOptionsShim(options); + ASSERT_EQ(options_shim.start_system_time, common::SystemTimestamp{options.start_system_timestamp}); + ASSERT_EQ(options_shim.start_steady_time, common::SteadyTimestamp{options.start_steady_timestamp}); + ASSERT_EQ(nostd::get(options_shim.parent), trace_api::SpanContext::GetInvalid()); +} + +TEST_F(ShimUtilsTest, MakeOptionsShim_FirstChildOf) { - std::unordered_map text_map; - TextMapCarrier testee{text_map}; - ASSERT_FALSE(testee.supports_lookup); - ASSERT_EQ(testee.foreach_key_call_count, 0); - - shim::utils::CarrierReaderShim tester{testee}; - auto lookup_unsupported = testee.LookupKey("foo"); - ASSERT_TRUE(text_map.empty()); - ASSERT_TRUE(opentracing::are_errors_equal(lookup_unsupported.error(), opentracing::lookup_key_not_supported_error)); - ASSERT_EQ(tester.Get("foo"), nostd::string_view{}); - ASSERT_EQ(testee.foreach_key_call_count, 1); - - text_map["foo"] = "bar"; - auto lookup_found = testee.LookupKey("foo"); - ASSERT_FALSE(text_map.empty()); - ASSERT_TRUE(opentracing::are_errors_equal(lookup_unsupported.error(), opentracing::lookup_key_not_supported_error)); - ASSERT_EQ(tester.Get("foo"), nostd::string_view{"bar"}); - ASSERT_EQ(testee.foreach_key_call_count, 2); + auto span_context_shim = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), baggage::Baggage::GetDefault())); + auto span_context = static_cast(span_context_shim.get()); + + opentracing::StartSpanOptions options; + options.start_system_timestamp = opentracing::SystemTime::time_point::clock::now(); + options.start_steady_timestamp = opentracing::SteadyTime::time_point::clock::now(); + options.references = { + { opentracing::SpanReferenceType::FollowsFromRef, nullptr }, + { opentracing::SpanReferenceType::ChildOfRef, span_context }, + { opentracing::SpanReferenceType::ChildOfRef, nullptr } + }; + + auto options_shim = shim::utils::makeOptionsShim(options); + ASSERT_EQ(options_shim.start_system_time, common::SystemTimestamp{options.start_system_timestamp}); + ASSERT_EQ(options_shim.start_steady_time, common::SteadyTimestamp{options.start_steady_timestamp}); + ASSERT_EQ(nostd::get(options_shim.parent), span_context_shim->context()); +} + +TEST_F(ShimUtilsTest, MakeOptionsShim_FirstInList) +{ + auto span_context_shim = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), baggage::Baggage::GetDefault())); + auto span_context = static_cast(span_context_shim.get()); + + opentracing::StartSpanOptions options; + options.start_system_timestamp = opentracing::SystemTime::time_point::clock::now(); + options.start_steady_timestamp = opentracing::SteadyTime::time_point::clock::now(); + options.references = { + { opentracing::SpanReferenceType::FollowsFromRef, span_context }, + { opentracing::SpanReferenceType::FollowsFromRef, nullptr } + }; + + auto options_shim = shim::utils::makeOptionsShim(options); + ASSERT_EQ(options_shim.start_system_time, common::SystemTimestamp{options.start_system_timestamp}); + ASSERT_EQ(options_shim.start_steady_time, common::SteadyTimestamp{options.start_steady_timestamp}); + ASSERT_EQ(nostd::get(options_shim.parent), span_context_shim->context()); +} + +TEST_F(ShimUtilsTest, MakeReferenceLinks) +{ + auto span_context_shim1 = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), baggage::Baggage::GetDefault())); + auto span_context1 = static_cast(span_context_shim1.get()); + auto span_context_shim2 = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), baggage::Baggage::GetDefault())); + auto span_context2 = static_cast(span_context_shim2.get()); + + opentracing::StartSpanOptions options; + auto links = shim::utils::makeReferenceLinks(options); + ASSERT_TRUE(links.empty()); + + options.references = { + { opentracing::SpanReferenceType::FollowsFromRef, nullptr }, + { opentracing::SpanReferenceType::FollowsFromRef, span_context1 }, + { opentracing::SpanReferenceType::ChildOfRef, span_context2 } + }; + + links = shim::utils::makeReferenceLinks(options); + ASSERT_EQ(links.size(), 2); + ASSERT_EQ(links[0].first, span_context_shim1->context()); + ASSERT_FALSE(links[0].second.empty()); + ASSERT_EQ(links[0].second[0].first, "opentracing.ref_type"); + ASSERT_EQ(nostd::get(links[0].second[0].second), "follows_from"); + ASSERT_EQ(links[1].first, span_context_shim2->context()); + ASSERT_EQ(links[1].second[0].first, "opentracing.ref_type"); + ASSERT_EQ(nostd::get(links[1].second[0].second), "child_of"); } -TEST_F(ShimUtilsTest, TextMapReader_Get_LookupKey_Supported) +TEST_F(ShimUtilsTest, MakeBaggage_EmptyRefs) { - std::unordered_map text_map; - TextMapCarrier testee{text_map}; - testee.supports_lookup = true; - ASSERT_TRUE(testee.supports_lookup); - ASSERT_EQ(testee.foreach_key_call_count, 0); - - shim::utils::CarrierReaderShim tester{testee}; - auto lookup_not_found = testee.LookupKey("foo"); - ASSERT_TRUE(text_map.empty()); - ASSERT_TRUE(opentracing::are_errors_equal(lookup_not_found.error(), opentracing::key_not_found_error)); - ASSERT_EQ(tester.Get("foo"), nostd::string_view{}); - ASSERT_EQ(testee.foreach_key_call_count, 1); - - text_map["foo"] = "bar"; - auto lookup_found = testee.LookupKey("foo"); - ASSERT_FALSE(text_map.empty()); - ASSERT_EQ(lookup_found.value(), opentracing::string_view{"bar"}); - ASSERT_EQ(tester.Get("foo"), nostd::string_view{"bar"}); - ASSERT_EQ(testee.foreach_key_call_count, 1); + auto baggage = baggage::Baggage::GetDefault()->Set("foo", "bar"); + std::string value; + ASSERT_TRUE(baggage->GetValue("foo", value)); + ASSERT_EQ(value, "bar"); + + auto context = context::RuntimeContext::GetCurrent(); + auto new_context = baggage::SetBaggage(context, baggage); + auto token = context::RuntimeContext::Attach(new_context); + ASSERT_EQ(context::RuntimeContext::GetCurrent(), new_context); + + opentracing::StartSpanOptions options; + auto new_baggage = shim::utils::makeBaggage(options); + ASSERT_TRUE(new_baggage->GetValue("foo", value)); + ASSERT_EQ(value, "bar"); } -TEST_F(ShimUtilsTest, TextMapReader_Keys) +TEST_F(ShimUtilsTest, MakeBaggage_NonEmptyRefs) { - std::unordered_map text_map; - TextMapCarrier testee{text_map}; - ASSERT_EQ(testee.foreach_key_call_count, 0); - - shim::utils::CarrierReaderShim tester{testee}; - std::vector kvs; - auto callback = [&text_map,&kvs](nostd::string_view k){ - kvs.emplace_back(k); - return !text_map.empty(); + auto span_context_shim1 = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), + baggage::Baggage::GetDefault()->Set("test", "foo")->Set("test1", "hello"))); + auto span_context1 = static_cast(span_context_shim1.get()); + auto span_context_shim2 = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), + baggage::Baggage::GetDefault()->Set("test", "bar")->Set("test2", "world"))); + auto span_context2 = static_cast(span_context_shim2.get()); + + opentracing::StartSpanOptions options; + options.references = { + { opentracing::SpanReferenceType::FollowsFromRef, span_context1 }, + { opentracing::SpanReferenceType::ChildOfRef, span_context2 } }; - ASSERT_TRUE(tester.Keys(callback)); - ASSERT_TRUE(text_map.empty()); - ASSERT_TRUE(kvs.empty()); - ASSERT_EQ(testee.foreach_key_call_count, 1); - - text_map["foo"] = "bar"; - text_map["bar"] = "baz"; - text_map["baz"] = "foo"; - ASSERT_TRUE(tester.Keys(callback)); - ASSERT_FALSE(text_map.empty()); - ASSERT_EQ(text_map.size(), kvs.size()); - ASSERT_EQ(testee.foreach_key_call_count, 2); + auto baggage = shim::utils::makeBaggage(options); + std::string value; + ASSERT_TRUE(baggage->GetValue("test", value)); + ASSERT_EQ(value, "foo"); + ASSERT_TRUE(baggage->GetValue("test1", value)); + ASSERT_EQ(value, "hello"); + ASSERT_TRUE(baggage->GetValue("test2", value)); + ASSERT_EQ(value, "world"); } -TEST_F(ShimUtilsTest, TextMapWriter_Set) +TEST_F(ShimUtilsTest, MakeTags) { - std::unordered_map text_map; - TextMapCarrier testee{text_map}; - shim::utils::CarrierWriterShim tester{testee}; - ASSERT_TRUE(text_map.empty()); - - tester.Set("foo", "bar"); - tester.Set("bar", "baz"); - tester.Set("baz", "foo"); - ASSERT_FALSE(text_map.empty()); - ASSERT_EQ(text_map.size(), 3); - ASSERT_EQ(text_map["foo"], "bar"); - ASSERT_EQ(text_map["bar"], "baz"); - ASSERT_EQ(text_map["baz"], "foo"); + opentracing::StartSpanOptions options; + auto attributes = shim::utils::makeTags(options); + ASSERT_TRUE(attributes.empty()); + + options.tags = {{ "foo", 42.0 }, { "bar", true }, { "baz", "test" }}; + attributes = shim::utils::makeTags(options); + ASSERT_EQ(attributes.size(), 3); + ASSERT_EQ(attributes[0].first, "foo"); + ASSERT_EQ(nostd::get(attributes[0].second), 42.0); + ASSERT_EQ(attributes[1].first, "bar"); + ASSERT_TRUE(nostd::get(attributes[1].second)); + ASSERT_EQ(attributes[2].first, "baz"); + ASSERT_STREQ(nostd::get(attributes[2].second), "test" ); } \ No newline at end of file diff --git a/opentracing-shim/test/span_context_shim_test.cc b/opentracing-shim/test/span_context_shim_test.cc index 0c36b8c3c1..b8aacd66fe 100644 --- a/opentracing-shim/test/span_context_shim_test.cc +++ b/opentracing-shim/test/span_context_shim_test.cc @@ -46,6 +46,10 @@ TEST_F(SpanContextShimTest, BaggageItem) TEST_F(SpanContextShimTest, NewWithKeyValue) { auto new_span_context_shim = span_context_shim->newWithKeyValue("test", "this"); + ASSERT_NE(span_context_shim.get(), &new_span_context_shim); + ASSERT_EQ(span_context_shim->context(), new_span_context_shim.context()); + ASSERT_EQ(span_context_shim->context().IsValid(), new_span_context_shim.context().IsValid()); + ASSERT_EQ(span_context_shim->context().IsRemote(), new_span_context_shim.context().IsRemote()); std::string value; ASSERT_TRUE(new_span_context_shim.BaggageItem("foo", value)); @@ -81,7 +85,9 @@ TEST_F(SpanContextShimTest, Clone) auto new_span_context_shim = dynamic_cast(new_span_context.get()); ASSERT_TRUE(new_span_context_shim != nullptr); ASSERT_NE(span_context_shim.get(), new_span_context_shim); + ASSERT_EQ(span_context_shim->context(), new_span_context_shim->context()); ASSERT_EQ(span_context_shim->context().IsValid(), new_span_context_shim->context().IsValid()); + ASSERT_EQ(span_context_shim->context().IsRemote(), new_span_context_shim->context().IsRemote()); std::string value; std::string new_value; diff --git a/opentracing-shim/test/tracer_shim_test.cc b/opentracing-shim/test/tracer_shim_test.cc index 3e0abd77f6..f675cb4dd3 100644 --- a/opentracing-shim/test/tracer_shim_test.cc +++ b/opentracing-shim/test/tracer_shim_test.cc @@ -9,7 +9,7 @@ #include "shim_utils.h" #include "shim_mocks.h" -#include +#include "opentracing/noop.h" #include @@ -80,7 +80,7 @@ TEST_F(TracerShimTest, InjectNullContext) auto noop_tracer = opentracing::MakeNoopTracer(); auto span = noop_tracer->StartSpan("a"); auto result = tracer_shim->Inject(span->context(), TextMapCarrier{text_map}); - ASSERT_TRUE(result.has_value()); + ASSERT_TRUE(opentracing::are_errors_equal(result.error(), opentracing::invalid_span_context_error)); ASSERT_TRUE(text_map.empty()); }