Skip to content

Commit

Permalink
Unit tests for span shim
Browse files Browse the repository at this point in the history
  • Loading branch information
chusitoo committed Jan 4, 2023
1 parent 4d99b85 commit 22949e2
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 12 deletions.
2 changes: 1 addition & 1 deletion opentracing-shim/include/span_context_shim.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class SpanContextShim final : public opentracing::SpanContext
explicit SpanContextShim(const opentelemetry::trace::SpanContext& context, const BaggagePtr& baggage)
: context_(context), baggage_(baggage) {}
inline const opentelemetry::trace::SpanContext& context() const { return context_; }
inline const BaggagePtr& baggage() const { return baggage_; }
inline const BaggagePtr baggage() const { return baggage_; }
SpanContextShim newWithKeyValue(nostd::string_view key, nostd::string_view value) const noexcept;
bool BaggageItem(nostd::string_view key, std::string& value) const noexcept;
// Overrides
Expand Down
2 changes: 1 addition & 1 deletion opentracing-shim/include/span_shim.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class SpanShim : public opentracing::Span
inline const opentracing::Tracer& tracer() const noexcept override { return tracer_; };

private:
void logImpl(opentracing::SystemTime timestamp, nostd::span<const EventEntry> fields) noexcept;
void logImpl(nostd::span<const EventEntry> fields, const opentracing::SystemTime* const timestamp) noexcept;

const TracerShim& tracer_;
SpanPtr span_;
Expand Down
18 changes: 11 additions & 7 deletions opentracing-shim/src/span_shim.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,18 @@ void SpanShim::SetBaggageItem(opentracing::string_view restricted_key, opentraci
{
// Creates a new SpanContext Shim with a new OpenTelemetry Baggage containing the specified
// Baggage key/value pair, and sets it as the current instance for this Span Shim.
if (restricted_key.empty() || value.empty()) return;

const std::lock_guard<decltype(context_lock_)> guard(context_lock_);
context_ = context_.newWithKeyValue(restricted_key.data(), value.data());;
context_ = context_.newWithKeyValue(restricted_key.data(), value.data());
}

std::string SpanShim::BaggageItem(opentracing::string_view restricted_key) const noexcept
{
// Returns the value for the specified key in the OpenTelemetry Baggage
// of the current SpanContext Shim, or null if none exists.
if (restricted_key.empty()) return "";

const std::lock_guard<decltype(context_lock_)> guard(context_lock_);
std::string value;
return context_.BaggageItem(restricted_key.data(), value) ? value : "";
Expand All @@ -84,24 +88,24 @@ void SpanShim::Log(std::initializer_list<EventEntry> fields) noexcept
{
// If an explicit timestamp is specified, a conversion MUST
// be done to match the OpenTracing and OpenTelemetry units.
logImpl(opentracing::SystemTime::min(), fields);
logImpl(fields, nullptr);
}

void SpanShim::Log(opentracing::SystemTime timestamp, std::initializer_list<EventEntry> fields) noexcept
{
// If an explicit timestamp is specified, a conversion MUST
// be done to match the OpenTracing and OpenTelemetry units.
logImpl(timestamp, fields);
logImpl(fields, &timestamp);
}

void SpanShim::Log(opentracing::SystemTime timestamp, const std::vector<EventEntry>& fields) noexcept
{
// If an explicit timestamp is specified, a conversion MUST
// be done to match the OpenTracing and OpenTelemetry units.
logImpl(timestamp, fields);
logImpl(fields, &timestamp);
}

void SpanShim::logImpl(opentracing::SystemTime timestamp, nostd::span<const EventEntry> fields) noexcept
void SpanShim::logImpl(nostd::span<const EventEntry> fields, const opentracing::SystemTime* const timestamp) noexcept
{
// The Add Event’s name parameter MUST be the value with the event key
// in the pair set, or else fallback to use the log literal string.
Expand Down Expand Up @@ -143,9 +147,9 @@ void SpanShim::logImpl(opentracing::SystemTime timestamp, nostd::span<const Even
attributes.emplace_back(key, value);
}
// Calls Add Events on the underlying OpenTelemetry Span with the specified key/value pair set.
if (timestamp != opentracing::SystemTime::min())
if (timestamp)
{
span_->AddEvent(name, timestamp, attributes);
span_->AddEvent(name, *timestamp, attributes);
}
else
{
Expand Down
65 changes: 62 additions & 3 deletions opentracing-shim/test/shim_mocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,72 @@
#pragma once

#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 <unordered_map>
#include <tuple>

namespace baggage = opentelemetry::baggage;
namespace context = opentelemetry::context;
namespace nostd = opentelemetry::nostd;
namespace trace_api = opentelemetry::trace;
namespace baggage = opentelemetry::baggage;
namespace common = opentelemetry::common;
namespace context = opentelemetry::context;
namespace nostd = opentelemetry::nostd;

struct MockSpan final : public trace_api::Span
{
void SetAttribute(nostd::string_view key,
const common::AttributeValue& value) noexcept override
{
attribute_ = {key.data(), value};
}

void AddEvent(nostd::string_view name,
common::SystemTimestamp timestamp,
const common::KeyValueIterable& attributes) noexcept override
{
std::unordered_map<std::string, common::AttributeValue> attribute_map;
attribute_map.reserve(attributes.size());
attributes.ForEachKeyValue([&attribute_map](nostd::string_view key, const common::AttributeValue& value){
attribute_map.emplace(key.data(), value);
return true;
});
event_ = {name.data(), timestamp, attribute_map};
}

void AddEvent(nostd::string_view name,
const common::KeyValueIterable& attributes) noexcept override
{
AddEvent(name, {}, attributes);
}

void AddEvent(nostd::string_view name,
common::SystemTimestamp timestamp) noexcept override {}

void AddEvent(nostd::string_view name) noexcept override {}

void SetStatus(trace_api::StatusCode code, nostd::string_view description) noexcept override
{
status_ = {code, description.data()};
}

void UpdateName(nostd::string_view name) noexcept override { name_ = name.data(); }

void End(const trace_api::EndSpanOptions& options) noexcept override { options_ = options; }

bool IsRecording() const noexcept override { return false; }

trace_api::SpanContext GetContext() const noexcept override { return trace_api::SpanContext(false, false); }

std::pair<std::string, common::AttributeValue> attribute_;
std::tuple<std::string, common::SystemTimestamp, std::unordered_map<std::string, common::AttributeValue>> event_;
std::pair<trace_api::StatusCode, std::string> status_;
std::string name_;
trace_api::EndSpanOptions options_;
};

struct MockPropagator : public context::propagation::TextMapPropagator
{
Expand Down
184 changes: 184 additions & 0 deletions opentracing-shim/test/span_shim_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

#include "span_shim.h"
#include "tracer_shim.h"
#include "shim_mocks.h"

#include <gtest/gtest.h>

namespace trace_api = opentelemetry::trace;
namespace baggage = opentelemetry::baggage;
namespace nostd = opentelemetry::nostd;
namespace shim = opentelemetry::opentracingshim;

class SpanShimTest : public testing::Test
{
public:
nostd::unique_ptr<shim::SpanShim> span_shim;
MockSpan* mock_span;

protected:
virtual void SetUp()
{
mock_span = new MockSpan();
auto span = nostd::shared_ptr<trace_api::Span>(mock_span);
auto tracer = shim::TracerShim::createTracerShim();
auto tracer_shim = dynamic_cast<shim::TracerShim*>(tracer.get());
auto baggage = baggage::Baggage::GetDefault()->Set("baggage", "item");
span_shim = nostd::unique_ptr<shim::SpanShim>(
new shim::SpanShim(*tracer_shim, span, baggage));
}

virtual void TearDown()
{
span_shim.reset();
}
};

TEST_F(SpanShimTest, HandleError)
{
span_shim->handleError(true);
ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kError);
span_shim->handleError("true");
ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kError);
span_shim->handleError(false);
ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kOk);
span_shim->handleError("false");
ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kOk);
span_shim->handleError(nullptr);
ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kUnset);
}

TEST_F(SpanShimTest, FinishWithOptions)
{
opentracing::FinishSpanOptions options;
options.finish_steady_timestamp = opentracing::SteadyTime::clock::now();
ASSERT_NE(mock_span->options_.end_steady_time, options.finish_steady_timestamp);
span_shim->FinishWithOptions(options);
ASSERT_EQ(mock_span->options_.end_steady_time, options.finish_steady_timestamp);
}

TEST_F(SpanShimTest, SetOperationName)
{
ASSERT_NE(mock_span->name_, "foo");
span_shim->SetOperationName("foo");
ASSERT_EQ(mock_span->name_, "foo");
}

TEST_F(SpanShimTest, SetTag_Normal)
{
ASSERT_NE(mock_span->attribute_.first, "foo");
span_shim->SetTag("foo", "bar");
ASSERT_EQ(mock_span->attribute_.first, "foo");
ASSERT_STREQ(nostd::get<const char *>(mock_span->attribute_.second), "bar");
}

TEST_F(SpanShimTest, SetTag_Error)
{
ASSERT_NE(mock_span->attribute_.first, "error");
span_shim->SetTag("error", true);
ASSERT_NE(mock_span->attribute_.first, "error");
span_shim->SetTag("error", "false");
ASSERT_NE(mock_span->attribute_.first, "error");
span_shim->SetTag("error", nullptr);
ASSERT_NE(mock_span->attribute_.first, "error");
}

TEST_F(SpanShimTest, BaggageItem)
{
ASSERT_EQ(span_shim->BaggageItem({}), "");
ASSERT_EQ(span_shim->BaggageItem(""), "");
ASSERT_EQ(span_shim->BaggageItem("invalid"), "");
ASSERT_EQ(span_shim->BaggageItem("baggage"), "item");
}

TEST_F(SpanShimTest, SetBaggageItem)
{
span_shim->SetBaggageItem("new", "entry");
ASSERT_EQ(span_shim->BaggageItem("new"), "entry");
ASSERT_EQ(span_shim->BaggageItem("baggage"), "item");
span_shim->SetBaggageItem("empty", "");
ASSERT_EQ(span_shim->BaggageItem("empty"), "");
span_shim->SetBaggageItem("no value", {});
ASSERT_EQ(span_shim->BaggageItem("no value"), "");
}

TEST_F(SpanShimTest, Log_NoEvent)
{
std::string name;
common::SystemTimestamp timestamp;
std::unordered_map<std::string, common::AttributeValue> attributes;

span_shim->Log({{"test", 42}});
std::tie(name, timestamp, attributes) = mock_span->event_;

ASSERT_EQ(name, "log");
ASSERT_EQ(timestamp, common::SystemTimestamp{});
ASSERT_EQ(attributes.size(), 1);
ASSERT_EQ(nostd::get<int64_t>(attributes["test"]), 42);
}

TEST_F(SpanShimTest, Log_NoEvent_Timestamp)
{
std::string name;
common::SystemTimestamp timestamp;
std::unordered_map<std::string, common::AttributeValue> attributes;

auto logtime = opentracing::SystemTime::time_point::clock::now();
span_shim->Log(logtime, {{"foo", "bar"}});
std::tie(name, timestamp, attributes) = mock_span->event_;

ASSERT_EQ(name, "log");
ASSERT_EQ(timestamp, common::SystemTimestamp{logtime});
ASSERT_EQ(attributes.size(), 1);
ASSERT_STREQ(nostd::get<const char *>(attributes["foo"]), "bar");
}

TEST_F(SpanShimTest, Log_Event)
{
std::string name;
common::SystemTimestamp timestamp;
std::unordered_map<std::string, common::AttributeValue> attributes;

auto logtime = opentracing::SystemTime::time_point::clock::now();
std::initializer_list<std::pair<opentracing::string_view, opentracing::Value>> fields{
{"event", "test!"}, {"foo", opentracing::string_view{"bar"}},
{"error.kind", 42}, {"message","hello"}, {"stack","overflow"}};
span_shim->Log(logtime, fields);
std::tie(name, timestamp, attributes) = mock_span->event_;

ASSERT_EQ(name, "test!");
ASSERT_EQ(timestamp, common::SystemTimestamp{logtime});
ASSERT_EQ(attributes.size(), 5);
ASSERT_STREQ(nostd::get<const char *>(attributes["event"]), "test!");
ASSERT_EQ(nostd::get<nostd::string_view>(attributes["foo"]), nostd::string_view{"bar"});
ASSERT_EQ(nostd::get<int64_t>(attributes["error.kind"]), 42);
ASSERT_STREQ(nostd::get<const char *>(attributes["message"]), "hello");
ASSERT_STREQ(nostd::get<const char *>(attributes["stack"]), "overflow");
}

TEST_F(SpanShimTest, Log_Error)
{
std::string name;
common::SystemTimestamp timestamp;
std::unordered_map<std::string, common::AttributeValue> attributes;

auto logtime = opentracing::SystemTime::time_point::clock::now();
std::vector<std::pair<opentracing::string_view, opentracing::Value>> fields{
{"event", "error"}, {"foo", opentracing::string_view{"bar"}},
{"error.kind", 42}, {"message","hello"}, {"stack","overflow"}};
span_shim->Log(logtime, fields);
std::tie(name, timestamp, attributes) = mock_span->event_;

ASSERT_EQ(name, "exception");
ASSERT_EQ(timestamp, common::SystemTimestamp{logtime});
ASSERT_EQ(attributes.size(), 5);
ASSERT_STREQ(nostd::get<const char *>(attributes["event"]), "error");
ASSERT_EQ(nostd::get<nostd::string_view>(attributes["foo"]), nostd::string_view{"bar"});
ASSERT_EQ(nostd::get<int64_t>(attributes["exception.type"]), 42);
ASSERT_STREQ(nostd::get<const char *>(attributes["exception.message"]), "hello");
ASSERT_STREQ(nostd::get<const char *>(attributes["exception.stacktrace"]), "overflow");
}

0 comments on commit 22949e2

Please sign in to comment.