Skip to content

Instantly share code, notes, and snippets.

@Shikugawa
Created March 16, 2022 10:37
Show Gist options
  • Save Shikugawa/fd154a816ad1ea2b3cfce78001effa0d to your computer and use it in GitHub Desktop.
Save Shikugawa/fd154a816ad1ea2b3cfce78001effa0d to your computer and use it in GitHub Desktop.
#include "source/extensions/tracers/skywalking/skywalking_tracer_impl.h"
#include "test/extensions/tracers/skywalking/skywalking_test_helper.h"
#include "test/mocks/common.h"
#include "test/mocks/server/tracer_factory_context.h"
#include "test/mocks/tracing/mocks.h"
#include "test/test_common/utility.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using testing::NiceMock;
using testing::Return;
using testing::ReturnRef;
namespace Envoy {
namespace Extensions {
namespace Tracers {
namespace SkyWalking {
namespace {
class SkyWalkingDriverTest : public testing::Test {
public:
SkyWalkingDriverTest() : grpc_stream_(NiceMock<Grpc::MockAsyncStream>()) {
expectGrpcClientCreated();
}
void setupDriver(const std::string& config) {
TestUtility::loadFromYaml(config, config_);
driver_ = std::make_unique<Driver>(config_, context_);
}
void expectGrpcClientCreated() {
auto mock_client_factory = std::make_unique<NiceMock<Grpc::MockAsyncClientFactory>>();
auto mock_client = std::make_unique<NiceMock<Grpc::MockAsyncClient>>();
EXPECT_CALL(*mock_client, startRaw(_, _, _, _)).WillOnce(Return(&grpc_stream_));
EXPECT_CALL(*mock_client_factory, createUncachedRawAsyncClient())
.WillOnce(Return(ByMove(std::move(mock_client))));
auto& factory_context = context_.server_factory_context_;
EXPECT_CALL(factory_context.cluster_manager_.async_client_manager_,
factoryForGrpcService(_, _, _))
.WillOnce(Return(ByMove(std::move(mock_client_factory))));
EXPECT_CALL(factory_context.thread_local_.dispatcher_, createTimer_(_))
.WillOnce(Invoke([](Event::TimerCb) { return new NiceMock<Event::MockTimer>(); }));
}
void validateSpan(Tracing::SpanPtr span, const std::string& expected_service_name,
const std::string& expected_instance_name, bool expected_skip_analysis,
bool should_send) {
EXPECT_NE(nullptr, span.get());
auto* internal_span = dynamic_cast<Span*>(span.get());
auto& trace_context = internal_span->tracingContext();
EXPECT_EQ(expected_service_name, trace_context->service());
EXPECT_EQ(expected_instance_name, trace_context->serviceInstance());
EXPECT_EQ(expected_skip_analysis, trace_context->skipAnalysis());
if (should_send) {
EXPECT_CALL(grpc_stream_, sendMessageRaw_(_, _));
internal_span->finishSpan();
}
}
void validateStats(int sent, int dropped, int flushed, int cache_flushed) {
EXPECT_EQ(sent,
context_.server_factory_context_.scope_.counter("tracing.skywalking.segments_sent")
.value());
EXPECT_EQ(dropped,
context_.server_factory_context_.scope_.counter("tracing.skywalking.segments_dropped")
.value());
EXPECT_EQ(flushed,
context_.server_factory_context_.scope_.counter("tracing.skywalking.segments_flushed")
.value());
EXPECT_EQ(cache_flushed,
context_.server_factory_context_.scope_.counter("tracing.skywalking.cache_flushed")
.value());
}
protected:
NiceMock<Stats::MockIsolatedStatsStore> stats_;
NiceMock<Server::Configuration::MockTracerFactoryContext> context_;
NiceMock<Tracing::MockConfig> mock_tracing_config_;
Event::SimulatedTimeSystem time_system_;
NiceMock<Grpc::MockAsyncStream> grpc_stream_;
envoy::config::trace::v3::SkyWalkingConfig config_;
DriverPtr driver_;
};
TEST(SkyWalkingSpanTest, Basic) {
NiceMock<Tracing::MockConfig> tracing_config;
NiceMock<Server::Configuration::MockTracerFactoryContext> context;
envoy::config::trace::v3::SkyWalkingConfig config;
Event::SimulatedTimeSystem time_system;
Http::TestRequestHeaderMapImpl request_headers;
Tracing::Decision default_decision;
default_decision.traced = true;
auto driver = std::make_unique<Driver>(config, context);
auto span = driver->startSpan(tracing_config, request_headers, "entry", time_system.systemTime(),
default_decision);
{
auto span_entity = dynamic_cast<Span*>(span.get())->spanEntity();
EXPECT_TRUE(span_entity->spanType() == skywalking::v3::SpanType::Entry);
EXPECT_EQ("", span->getBaggage("FakeStringAndNothingToDo"));
span->setOperation("FakeStringAndNothingToDo");
span->setBaggage("FakeStringAndNothingToDo", "FakeStringAndNothingToDo");
// This method is unimplemented and a noop.
ASSERT_EQ(span->getTraceIdAsHex(), "");
// Test whether the basic functions of Span are normal.
EXPECT_FALSE(span_entity->skipAnalysis());
span->setSampled(false);
EXPECT_TRUE(span_entity->skipAnalysis());
// The initial operation name is consistent with the 'operation' parameter in the 'startSpan'
// method call.
EXPECT_EQ("entry", span_entity->operationName());
// Test whether the tag can be set correctly.
span->setTag("TestTagKeyA", "TestTagValueA");
span->setTag("TestTagKeyB", "TestTagValueB");
EXPECT_EQ("TestTagValueA", span_entity->tags().at(0).second);
EXPECT_EQ("TestTagValueB", span_entity->tags().at(1).second);
// When setting the status code tag, the corresponding tag name will be rewritten as
// 'status_code'.
span->setTag(Tracing::Tags::get().HttpStatusCode, "200");
EXPECT_EQ("status_code", span_entity->tags().at(2).first);
EXPECT_EQ("200", span_entity->tags().at(2).second);
// When setting the error tag, the spanEntity object will also mark itself as an error.
span->setTag(Tracing::Tags::get().Error, Tracing::Tags::get().True);
EXPECT_EQ(Tracing::Tags::get().Error, span_entity->tags().at(3).first);
EXPECT_EQ(Tracing::Tags::get().True, span_entity->tags().at(3).second);
EXPECT_EQ(true, span_entity->errorStatus());
// When setting http url tag, the corresponding tag name will be rewritten as 'url'.
span->setTag(Tracing::Tags::get().HttpUrl, "http://test.com/test/path");
EXPECT_EQ("url", span_entity->tags().at(4).first);
span->log(SystemTime{std::chrono::duration<int, std::milli>(100)}, "abc");
EXPECT_EQ(1, span_entity->logs().size());
EXPECT_LT(0, span_entity->logs().at(0).time());
EXPECT_EQ("abc", span_entity->logs().at(0).data().at(0).value());
absl::string_view sample{"GETxx"};
sample.remove_suffix(2);
span->setTag(Tracing::Tags::get().HttpMethod, sample);
EXPECT_EQ("GET", span_entity->tags().at(5).second);
}
auto exit_span = span->spawnChild(tracing_config, "exit", time_system.systemTime());
{
auto span_entity = dynamic_cast<Span*>(exit_span.get())->spanEntity();
EXPECT_TRUE(span_entity->spanType() == skywalking::v3::SpanType::Exit);
EXPECT_FALSE(span_entity->skipAnalysis());
EXPECT_EQ(1, span_entity->spanId());
EXPECT_EQ(0, span_entity->parentSpanId());
}
}
TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) {
const std::string yaml_string = R"YAML(
grpc_service:
envoy_grpc:
cluster_name: fake_cluster
client_config:
backend_token: token
service_name: "service-a"
instance_name: "instance-a"
max_cache_size: 2333
)YAML";
setupDriver(yaml_string);
Tracing::Decision decision;
decision.traced = true;
ON_CALL(mock_tracing_config_, operationName())
.WillByDefault(Return(Tracing::OperationName::Ingress));
Http::TestRequestHeaderMapImpl request_headers;
{
// Create new span segment with no previous span context.
validateSpan(driver_->startSpan(mock_tracing_config_, request_headers, "",
time_system_.systemTime(), decision),
"service-a", "service-a", false, true);
validateStats(1, 0, 0, 0);
}
{
// Create root segment span with disabled tracing.
decision.traced = false;
validateSpan(driver_->startSpan(mock_tracing_config_, request_headers, "TEST_OP",
time_system_.systemTime(), decision),
"service-a", "service-a", true, true);
validateStats(2, 0, 0, 0);
}
{
request_headers.setByKey("sw8",
SkyWalkingTestHelper::createPropagatedSW8HeaderValue(false, ""));
validateSpan(driver_->startSpan(mock_tracing_config_, request_headers, "TEST_OP",
time_system_.systemTime(), decision),
"service-a", "service-a", false, true);
validateStats(3, 0, 0, 0);
}
{
// Create new span segment with error propagation header.
request_headers.setByKey("sw8", "error-propagation-header");
Tracing::SpanPtr org_null_span = driver_->startSpan(
mock_tracing_config_, request_headers, "TEST_OP", time_system_.systemTime(), decision);
EXPECT_EQ(nullptr, dynamic_cast<Span*>(org_null_span.get()));
auto& null_span = *org_null_span;
EXPECT_EQ(typeid(null_span).name(), typeid(Tracing::NullSpan).name());
validateStats(3, 0, 0, 0);
}
}
TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestNoClientConfig) {
const std::string yaml_string = R"YAML(
grpc_service:
envoy_grpc:
cluster_name: fake_cluster
)YAML";
setupDriver(yaml_string);
Http::TestRequestHeaderMapImpl request_headers;
validateSpan(driver_->startSpan(mock_tracing_config_, request_headers, "TEST_OP",
time_system_.systemTime(), Tracing::Decision()),
"cluster_name", "node_name", true, false);
validateStats(0, 0, 0, 0);
}
} // namespace
} // namespace SkyWalking
} // namespace Tracers
} // namespace Extensions
} // namespace Envoy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment