Created
March 16, 2022 10:37
-
-
Save Shikugawa/fd154a816ad1ea2b3cfce78001effa0d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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