diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/config_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/config_test.cc index acd486727d75..6860df5c0ece 100644 --- a/test/extensions/tracers/opentelemetry/samplers/dynatrace/config_test.cc +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/config_test.cc @@ -12,6 +12,7 @@ namespace Extensions { namespace Tracers { namespace OpenTelemetry { +// Test creating a Dynatrace sampler via factory TEST(DynatraceSamplerFactoryTest, Test) { auto* factory = Registry::FactoryRegistry::getFactory( "envoy.tracers.opentelemetry.samplers.dynatrace"); @@ -29,7 +30,6 @@ TEST(DynatraceSamplerFactoryTest, Test) { NiceMock context; EXPECT_NE(factory->createSampler(typed_config.typed_config(), context), nullptr); - EXPECT_STREQ(factory->name().c_str(), "envoy.tracers.opentelemetry.samplers.dynatrace"); } } // namespace OpenTelemetry diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_integration_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_integration_test.cc index 163d95e3310b..73bd31e7360b 100644 --- a/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_integration_test.cc +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_integration_test.cc @@ -60,6 +60,7 @@ INSTANTIATE_TEST_SUITE_P(IpVersions, DynatraceSamplerIntegrationTest, // Sends a request with traceparent and tracestate header. TEST_P(DynatraceSamplerIntegrationTest, TestWithTraceparentAndTracestate) { + // tracestate does not contain a Dynatrace tag Http::TestRequestHeaderMapImpl request_headers{ {":method", "GET"}, {":path", "/test/long/url"}, {":scheme", "http"}, {":authority", "host"}, {"tracestate", "key=value"}, {"traceparent", TRACEPARENT_VALUE}}; @@ -77,12 +78,12 @@ TEST_P(DynatraceSamplerIntegrationTest, TestWithTraceparentAndTracestate) { .getStringView(); EXPECT_TRUE(absl::StartsWith(traceparent_value, TRACEPARENT_VALUE_START)); EXPECT_NE(TRACEPARENT_VALUE, traceparent_value); - // tracestate should be forwarded + // Dynatrace tracestate should be added to existing tracestate absl::string_view tracestate_value = upstream_request_->headers() .get(Http::LowerCaseString("tracestate"))[0] ->value() .getStringView(); - // use StartsWith because pathinfo (last element in trace state contains a random value) + // use StartsWith because pathinfo (last element in trace state) contains a random value EXPECT_TRUE(absl::StartsWith(tracestate_value, "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;")) << "Received tracestate: " << tracestate_value; EXPECT_TRUE(absl::StrContains(tracestate_value, ",key=value")) @@ -109,7 +110,7 @@ TEST_P(DynatraceSamplerIntegrationTest, TestWithTraceparentOnly) { .getStringView(); EXPECT_TRUE(absl::StartsWith(traceparent_value, TRACEPARENT_VALUE_START)); EXPECT_NE(TRACEPARENT_VALUE, traceparent_value); - // OTLP tracer adds an empty tracestate + // Dynatrace tag should be added to tracestate absl::string_view tracestate_value = upstream_request_->headers() .get(Http::LowerCaseString("tracestate"))[0] ->value() @@ -134,7 +135,7 @@ TEST_P(DynatraceSamplerIntegrationTest, TestWithoutTraceparentAndTracestate) { // assert EXPECT_EQ(upstream_request_->headers().get(::Envoy::Http::LowerCaseString("traceparent")).size(), 1); - // OTLP tracer adds an empty tracestate + // Dynatrace tag should be added to tracestate absl::string_view tracestate_value = upstream_request_->headers() .get(Http::LowerCaseString("tracestate"))[0] ->value() diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_test.cc index 8d98000ab207..29bb74a22404 100644 --- a/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_test.cc +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_test.cc @@ -85,23 +85,7 @@ TEST_F(DynatraceSamplerTest, TestWithoutParentContext) { EXPECT_TRUE(sampling_result.isSampled()); } -// Verify sampler being invoked with existing Dynatrace trace state tag set -TEST_F(DynatraceSamplerTest, TestWithParentContext) { - SpanContext parent_context = SpanContext("00", trace_id, "b7ad6b7169203331", true, - "ot=foo:bar,5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;ad"); - - SamplingResult sampling_result = - sampler_->shouldSample(parent_context, trace_id, "parent_span", - ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); - EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); - EXPECT_EQ(sampling_result.attributes->size(), 1); - EXPECT_STREQ(sampling_result.tracestate.c_str(), - "ot=foo:bar,5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;ad"); - EXPECT_TRUE(sampling_result.isRecording()); - EXPECT_TRUE(sampling_result.isSampled()); -} - -// Verify sampler being invoked with parent span context +// Verify sampler being invoked without a Dynatrace tracestate TEST_F(DynatraceSamplerTest, TestWithUnknownParentContext) { SpanContext parent_context("00", trace_id, parent_span_id, true, "some_vendor=some_value"); @@ -110,13 +94,14 @@ TEST_F(DynatraceSamplerTest, TestWithUnknownParentContext) { ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); EXPECT_EQ(sampling_result.attributes->size(), 1); + // Dynatrace tracesate should be prepended EXPECT_STREQ(sampling_result.tracestate.c_str(), "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;95,some_vendor=some_value"); EXPECT_TRUE(sampling_result.isRecording()); EXPECT_TRUE(sampling_result.isSampled()); } -// Verify sampler being invoked with dynatrace trace parent +// Verify sampler being invoked with dynatrace trace state TEST_F(DynatraceSamplerTest, TestWithDynatraceParentContextSampled) { SpanContext parent_context("00", trace_id, parent_span_id, true, dt_tracestate_sampled); @@ -125,7 +110,9 @@ TEST_F(DynatraceSamplerTest, TestWithDynatraceParentContextSampled) { ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); EXPECT_EQ(sampling_result.attributes->size(), 1); + // tracestate should be forwarded EXPECT_STREQ(sampling_result.tracestate.c_str(), dt_tracestate_sampled); + // sampling decision from parent should be respected EXPECT_TRUE(sampling_result.isRecording()); EXPECT_TRUE(sampling_result.isSampled()); } @@ -139,7 +126,9 @@ TEST_F(DynatraceSamplerTest, TestWithDynatraceParentContextIgnored) { ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); EXPECT_EQ(sampling_result.decision, Decision::Drop); EXPECT_EQ(sampling_result.attributes->size(), 1); + // tracestate should be forwarded EXPECT_STREQ(sampling_result.tracestate.c_str(), dt_tracestate_ignored); + // sampling decision from parent should be respected EXPECT_FALSE(sampling_result.isRecording()); EXPECT_FALSE(sampling_result.isSampled()); } @@ -155,6 +144,7 @@ TEST_F(DynatraceSamplerTest, TestWithDynatraceParentContextFromDifferentTenant) // sampling decision on tracestate should be ignored because it is from a different tenant. EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); EXPECT_EQ(sampling_result.attributes->size(), 1); + // new Dynatrace tag should be prepended, already existing tag should be kept const char* exptected = "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;95,6666ad40-980df25c@dt=fw4;4;4af38366;0;0;1;2;123;" "8eae;2h01;3h4af38366;4h00;5h01;6h67a9a23155e1741b5b35368e08e6ece5;7h9d83def9a4939b7b"; @@ -192,29 +182,36 @@ TEST_F(DynatraceSamplerTest, TestWarmup) { trace_context_1, {}); result.isSampled() ? sampled++ : ignored++; } - // should be 50, but the used "random" in shouldSample does not produce the same odd/even numbers. + // should be 50 ignored, but the used "random" in shouldSample does not produce the same odd/even + // numbers. EXPECT_EQ(ignored, 41); EXPECT_EQ(sampled, 158); + // send more requests for (int i = 0; i < 100; i++) { auto result = sampler_->shouldSample({}, std::to_string(1000 + i), "operation_name", ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, trace_context_1, {}); result.isSampled() ? sampled++ : ignored++; } + // exponent should be 2, with a perfect random we would get 25 sampled and 75 ignored. EXPECT_EQ(ignored, 113); EXPECT_EQ(sampled, 186); + // send more requests. for (int i = 0; i < 700; i++) { auto result = sampler_->shouldSample({}, std::to_string(1000 + i), "operation_name", ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, trace_context_1, {}); result.isSampled() ? sampled++ : ignored++; } + // with a perfect random, the number of sampled paths would be lower than threshold (200) + // We don't care about exceeding the threshold because it is not a hard limit EXPECT_EQ(ignored, 791); EXPECT_EQ(sampled, 208); } +// Verify sampling if number of configured spans per minute is exceeded. TEST_F(DynatraceSamplerTest, TestSampling) { // config should allow 200 root spans per minute sampler_config_.parse("{\n \"rootSpansPerMinute\" : 200 \n }"); @@ -229,7 +226,7 @@ TEST_F(DynatraceSamplerTest, TestSampling) { trace_context_3.context_method_ = "POST"; trace_context_3.context_path_ = "/another_path"; - // send requests + // simulate requests for (int i = 0; i < 180; i++) { sampler_->shouldSample({}, trace_id, "operation_name", ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, @@ -243,7 +240,7 @@ TEST_F(DynatraceSamplerTest, TestSampling) { ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, trace_context_3, {}); - // sampler should read update sampling exponents + // sampler should update sampling exponents based on number of requests in the previous period timer_->invokeCallback(); // the sampler should not sample every span for 'trace_context_1' @@ -261,7 +258,7 @@ TEST_F(DynatraceSamplerTest, TestSampling) { } EXPECT_TRUE(ignored); - // trace_context_3 should be sampled + // trace_context_3 should always be sampled. for (int i = 0; i < 10; i++) { auto result = sampler_->shouldSample({}, std::to_string(i), "operation_name", ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_fetcher_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_fetcher_test.cc index 04650a62040c..4f8b8bb5737c 100644 --- a/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_fetcher_test.cc +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_fetcher_test.cc @@ -63,17 +63,17 @@ MATCHER_P(MessageMatcher, unusedArg, "") { (arg->headers().get(Http::Headers::get().Method)[0]->value().getStringView() == "GET"); } -// Test a request is sent if timer fires +// Test that a request is sent if timer fires TEST_F(SamplerConfigFetcherTest, TestRequestIsSent) { EXPECT_CALL(tracer_factory_context_.server_factory_context_.cluster_manager_.thread_local_cluster_ .async_client_, - send_(MessageMatcher("unused-but-machtes-requires-an-arg"), _, _)); + send_(MessageMatcher("unused-arg"), _, _)); SamplerConfigFetcherImpl config_fetcher(tracer_factory_context_, http_uri_, "tokenval"); timer_->invokeCallback(); } -// Test receiving a response with code 200 and valid json -TEST_F(SamplerConfigFetcherTest, TestResponseOk) { +// Test receiving http response code 200 and valid json +TEST_F(SamplerConfigFetcherTest, TestResponseOkValidJson) { SamplerConfigFetcherImpl config_fetcher(tracer_factory_context_, http_uri_, "tokenXASSD"); timer_->invokeCallback(); @@ -85,7 +85,7 @@ TEST_F(SamplerConfigFetcherTest, TestResponseOk) { EXPECT_TRUE(timer_->enabled()); } -// Test receiving a response with code 200 and unexpected json +// Test receiving http response code 200 and invalid json TEST_F(SamplerConfigFetcherTest, TestResponseOkInvalidJson) { SamplerConfigFetcherImpl config_fetcher(tracer_factory_context_, http_uri_, "tokenXASSD"); timer_->invokeCallback(); @@ -99,7 +99,7 @@ TEST_F(SamplerConfigFetcherTest, TestResponseOkInvalidJson) { EXPECT_TRUE(timer_->enabled()); } -// Test receiving a response with code != 200 +// Test receiving http response code != 200 TEST_F(SamplerConfigFetcherTest, TestResponseErrorCode) { SamplerConfigFetcherImpl config_fetcher(tracer_factory_context_, http_uri_, "tokenXASSD"); timer_->invokeCallback(); @@ -127,7 +127,7 @@ TEST_F(SamplerConfigFetcherTest, TestOnFailure) { TEST_F(SamplerConfigFetcherTest, TestOnBeforeFinalizeUpstreamSpan) { Tracing::MockSpan child_span_; SamplerConfigFetcherImpl config_fetcher(tracer_factory_context_, http_uri_, "tokenXASSD"); - // onBeforeFinalizeUpstreamSpan() is an empty method, nothing should happen + // onBeforeFinalizeUpstreamSpan() is an empty method, nothing to ASSERT, nothing should happen config_fetcher.onBeforeFinalizeUpstreamSpan(child_span_, nullptr); } @@ -139,7 +139,7 @@ TEST_F(SamplerConfigFetcherTest, TestNoCluster) { .WillByDefault(Return(nullptr)); SamplerConfigFetcherImpl config_fetcher(tracer_factory_context_, http_uri_, "tokenXASSD"); timer_->invokeCallback(); - // should not crash or throw. + // nothing to assert, should not crash or throw. } } // namespace OpenTelemetry diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_test.cc index 704396fde979..2bea3ad7c610 100644 --- a/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_test.cc +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_test.cc @@ -11,7 +11,7 @@ namespace Tracers { namespace OpenTelemetry { // Test sampler config json parsing -TEST(SamplerConfigTest, test) { +TEST(SamplerConfigTest, TestParsing) { SamplerConfig config; config.parse("{\n \"rootSpansPerMinute\" : 2000 \n }"); EXPECT_EQ(config.getRootSpansPerMinute(), 2000u); @@ -31,7 +31,13 @@ TEST(SamplerConfigTest, test) { config.parse(" { "); EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); - config.parse(" } "); + config.parse("{\n \"rootSpansPerMinute\" : 10000 "); // closing } is missing + EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); +} + +// Test default sampler config (not yet parsed a json) +TEST(SamplerConfigTest, TestDefaultConfig) { + SamplerConfig config; EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); } diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller_test.cc index 12668ee59a6b..96f2d90f0d41 100644 --- a/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller_test.cc +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller_test.cc @@ -18,6 +18,7 @@ namespace OpenTelemetry { namespace { +// helper to offer a value multiple times to SamplingController void offerEntry(SamplingController& sc, const std::string& value, int count) { for (int i = 0; i < count; i++) { sc.offer(value); @@ -28,13 +29,12 @@ void offerEntry(SamplingController& sc, const std::string& value, int count) { class TestSamplerConfigFetcher : public SamplerConfigFetcher { public: - const SamplerConfig& getSamplerConfig() const { return config; } + const SamplerConfig& getSamplerConfig() const override { return config; } SamplerConfig config; }; -class SamplingControllerTest : public testing::Test {}; - -TEST_F(SamplingControllerTest, TestManyDifferentRequests) { +// Test with multiple different sampling keys (StreamSummary size exceeded) +TEST(SamplingControllerTest, TestStreamSummarySizeExceeded) { auto scf = std::make_unique(); SamplingController sc(std::move(scf)); @@ -43,6 +43,7 @@ TEST_F(SamplingControllerTest, TestManyDifferentRequests) { offerEntry(sc, "3", 750); offerEntry(sc, "4", 100); offerEntry(sc, "5", 50); + // add unique sampling keys for (int64_t i = 0; i < 2100; i++) { sc.offer(std::to_string(i + 1000000)); } @@ -60,7 +61,8 @@ TEST_F(SamplingControllerTest, TestManyDifferentRequests) { EXPECT_EQ(sc.getSamplingState("1000002").getMultiplicity(), 2); } -TEST_F(SamplingControllerTest, TestManyRequests) { +// Test with StreamSummary size not exceeded +TEST(SamplingControllerTest, TestStreamSummarySizeNotExceeded) { auto scf = std::make_unique(); SamplingController sc(std::move(scf)); @@ -86,7 +88,8 @@ TEST_F(SamplingControllerTest, TestManyRequests) { EXPECT_EQ(sc.getSamplingState("8").getMultiplicity(), 1); } -TEST_F(SamplingControllerTest, TestSomeRequests) { +// Test with StreamSummary size not exceeded +TEST(SamplingControllerTest, TestStreamSummarySizeNotExceeded1) { auto scf = std::make_unique(); SamplingController sc(std::move(scf)); @@ -113,7 +116,8 @@ TEST_F(SamplingControllerTest, TestSomeRequests) { EXPECT_EQ(sc.getSamplingState("1000003").getMultiplicity(), 1); } -TEST_F(SamplingControllerTest, TestSimple) { +// Test using a sampler config having non-default root spans per minute +TEST(SamplingControllerTest, TestNonDefaultRootSpansPerMinute) { auto scf = std::make_unique(); scf->config.parse("{\n \"rootSpansPerMinute\" : 100 \n }"); SamplingController sc(std::move(scf)); @@ -134,55 +138,61 @@ TEST_F(SamplingControllerTest, TestSimple) { EXPECT_EQ(sc.getSamplingState("GET_asdf").getMultiplicity(), 2); } -TEST_F(SamplingControllerTest, TestWarmup) { +// Test warm up phase (no SamplingState available) +TEST(SamplingControllerTest, TestWarmup) { auto scf = std::make_unique(); SamplingController sc(std::move(scf)); // offer entries, but don't call update(); // sampling exponents table will be empty - // exponent will be calculated based on count. + // exponent will be calculated based on total count. + // same exponent for both exising and non-excisting keys. + offerEntry(sc, "GET_0", 10); + EXPECT_EQ(sc.getSamplingState("GET_0").getExponent(), 0); EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 0); EXPECT_EQ(sc.getSamplingState("GET_2").getExponent(), 0); - EXPECT_EQ(sc.getSamplingState("GET_3").getExponent(), 0); offerEntry(sc, "GET_1", 540); + // threshold/2 reached, sampling exponent is set to 1 EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 1); EXPECT_EQ(sc.getSamplingState("GET_2").getExponent(), 1); EXPECT_EQ(sc.getSamplingState("GET_3").getExponent(), 1); - offerEntry(sc, "GET_0", 300); - EXPECT_EQ(sc.getSamplingState("GET_0").getExponent(), 1); + offerEntry(sc, "GET_2", 300); EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 1); - EXPECT_EQ(sc.getSamplingState("GET_10").getExponent(), 1); + EXPECT_EQ(sc.getSamplingState("GET_2").getExponent(), 1); + EXPECT_EQ(sc.getSamplingState("GET_123").getExponent(), 1); offerEntry(sc, "GET_4", 550); EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 2); - EXPECT_EQ(sc.getSamplingState("GET_2").getExponent(), 2); - EXPECT_EQ(sc.getSamplingState("GET_3").getExponent(), 2); + EXPECT_EQ(sc.getSamplingState("GET_4").getExponent(), 2); + EXPECT_EQ(sc.getSamplingState("GET_234").getExponent(), 2); offerEntry(sc, "GET_5", 1000); EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 4); - EXPECT_EQ(sc.getSamplingState("GET_2").getExponent(), 4); - EXPECT_EQ(sc.getSamplingState("GET_3").getExponent(), 4); + EXPECT_EQ(sc.getSamplingState("GET_5").getExponent(), 4); + EXPECT_EQ(sc.getSamplingState("GET_456").getExponent(), 4); - offerEntry(sc, "GET_7", 2000); + offerEntry(sc, "GET_6", 2000); EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 8); - EXPECT_EQ(sc.getSamplingState("GET_2").getExponent(), 8); - EXPECT_EQ(sc.getSamplingState("GET_3").getExponent(), 8); + EXPECT_EQ(sc.getSamplingState("GET_6").getExponent(), 8); + EXPECT_EQ(sc.getSamplingState("GET_789").getExponent(), 8); } -TEST_F(SamplingControllerTest, TestEmpty) { +// Test getting sampling state from an empty SamplingController +TEST(SamplingControllerTest, TestEmpty) { auto scf = std::make_unique(); SamplingController sc(std::move(scf)); sc.update(); - + // default SamplingState is expected EXPECT_EQ(sc.getSamplingState("GET_something").getExponent(), 0); EXPECT_EQ(sc.getSamplingState("GET_something").getMultiplicity(), 1); } -TEST_F(SamplingControllerTest, TestNonExisting) { +// Test getting sampling state for an unknwon key from a non-empty SamplingController +TEST(SamplingControllerTest, TestUnknown) { auto scf = std::make_unique(); SamplingController sc(std::move(scf)); @@ -191,8 +201,19 @@ TEST_F(SamplingControllerTest, TestNonExisting) { EXPECT_EQ(sc.getSamplingState("key2").getExponent(), 0); EXPECT_EQ(sc.getSamplingState("key2").getMultiplicity(), 1); + + // Exceed capacity, + for (uint32_t i = 0; i < SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT * 2; i++) { + sc.offer("key1"); + } + sc.update(); + // "key1" will get exponent 1 + EXPECT_EQ(sc.getSamplingState("key1").getExponent(), 1); + // unknown "key2" will get the same exponent + EXPECT_EQ(sc.getSamplingState("key2").getExponent(), 1); } +// Test increasing and decreasing sampling exponent TEST(SamplingStateTest, TestIncreaseDecrease) { SamplingState sst{}; EXPECT_EQ(sst.getExponent(), 0); @@ -217,14 +238,17 @@ TEST(SamplingStateTest, TestIncreaseDecrease) { EXPECT_EQ(sst.getMultiplicity(), 128); } +// Test SamplingState shouldSample() TEST(SamplingStateTest, TestShouldSample) { - // default sampling state should sample + // default sampling state should sample every request SamplingState sst{}; EXPECT_TRUE(sst.shouldSample(1234)); + EXPECT_TRUE(sst.shouldSample(2345)); EXPECT_TRUE(sst.shouldSample(3456)); - EXPECT_TRUE(sst.shouldSample(12345)); + EXPECT_TRUE(sst.shouldSample(4567)); - // exponent 2, multiplicity 1, even (=not odd) random numbers should be sampled + // exponent 1, multiplicity 2, + // we are using % for sampling decision, so even (=not odd) random numbers should be sampled sst.increaseExponent(); EXPECT_TRUE(sst.shouldSample(22)); EXPECT_TRUE(sst.shouldSample(4444444)); @@ -245,7 +269,8 @@ TEST(SamplingStateTest, TestShouldSample) { EXPECT_FALSE(sst.shouldSample(2049)); } -TEST_F(SamplingControllerTest, TestGetSamplingKey) { +// Test creating sampling key used to identify a request +TEST(SamplingControllerTest, TestGetSamplingKey) { std::string key = SamplingController::getSamplingKey("somepath", "GET"); EXPECT_STREQ(key.c_str(), "GET_somepath"); @@ -254,6 +279,12 @@ TEST_F(SamplingControllerTest, TestGetSamplingKey) { key = SamplingController::getSamplingKey("anotherpath", "PUT"); EXPECT_STREQ(key.c_str(), "PUT_anotherpath"); + + key = SamplingController::getSamplingKey("", "PUT"); + EXPECT_STREQ(key.c_str(), "PUT_"); + + key = SamplingController::getSamplingKey("anotherpath", ""); + EXPECT_STREQ(key.c_str(), "_anotherpath"); } } // namespace OpenTelemetry diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary_test.cc index e610bf10b652..f7f80cf68b93 100644 --- a/test/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary_test.cc +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary_test.cc @@ -18,8 +18,9 @@ namespace OpenTelemetry { namespace { +// helper function to compare counters template -void CompareCounter(typename std::list>::iterator counter, T item, uint64_t value, +void compareCounter(typename std::list>::iterator counter, T item, uint64_t value, uint64_t error, int line_num) { SCOPED_TRACE(absl::StrCat(__FUNCTION__, " called from line ", line_num)); EXPECT_EQ(counter->getValue(), value); @@ -29,6 +30,7 @@ void CompareCounter(typename std::list>::iterator counter, T item, ui } // namespace +// Test an empty StreamSummary TEST(StreamSummaryTest, TestEmpty) { StreamSummary summary(4); EXPECT_EQ(summary.getN(), 0); @@ -38,6 +40,7 @@ TEST(StreamSummaryTest, TestEmpty) { EXPECT_TRUE(summary.validate().ok()); } +// Test adding values, capacity not exceeded TEST(StreamSummaryTest, TestSimple) { StreamSummary summary(4); summary.offer('a'); @@ -55,23 +58,14 @@ TEST(StreamSummaryTest, TestSimple) { auto top_k = summary.getTopK(); EXPECT_EQ(top_k.size(), 4); auto it = top_k.begin(); - CompareCounter(it, 'a', 4, 0, __LINE__); - CompareCounter(++it, 'b', 2, 0, __LINE__); - CompareCounter(++it, 'c', 1, 0, __LINE__); - CompareCounter(++it, 'd', 1, 0, __LINE__); + compareCounter(it, 'a', 4, 0, __LINE__); + compareCounter(++it, 'b', 2, 0, __LINE__); + compareCounter(++it, 'c', 1, 0, __LINE__); + compareCounter(++it, 'd', 1, 0, __LINE__); } -// TODO: remove -template std::string toString(T const& list) { - std::ostringstream oss; - for (auto const& counter : list) { - oss << counter.getItem() << ":(" << counter.getValue() << "/" << counter.getError() << ")" - << " "; - } - return oss.str(); -} - -TEST(StreamSummaryTest, TestExtendCapacity) { +// Test adding values, capacity exceeded +TEST(StreamSummaryTest, TestExceedCapacity) { StreamSummary summary(3); EXPECT_TRUE(summary.validate().ok()); summary.offer('d'); @@ -81,7 +75,7 @@ TEST(StreamSummaryTest, TestExtendCapacity) { summary.offer('a'); summary.offer('a'); summary.offer('b'); - summary.offer('c'); + summary.offer('c'); // 'd' will be dropped summary.offer('b'); summary.offer('c'); EXPECT_TRUE(summary.validate().ok()); @@ -90,23 +84,24 @@ TEST(StreamSummaryTest, TestExtendCapacity) { auto top_k = summary.getTopK(); auto it = top_k.begin(); EXPECT_EQ(top_k.size(), 3); - CompareCounter(it, 'a', 4, 0, __LINE__); - CompareCounter(++it, 'b', 3, 0, __LINE__); - CompareCounter(++it, 'c', 3, 1, __LINE__); + compareCounter(it, 'a', 4, 0, __LINE__); + compareCounter(++it, 'b', 3, 0, __LINE__); + compareCounter(++it, 'c', 3, 1, __LINE__); } - // add item 'e', 'c' should be removed. + // add item 'e', 'c' should be removed. value for 'c' will be added to error for 'e' summary.offer('e'); { auto top_k = summary.getTopK(); auto it = top_k.begin(); EXPECT_EQ(top_k.size(), 3); - CompareCounter(it, 'a', 4, 0, __LINE__); - CompareCounter(++it, 'e', 4, 3, __LINE__); - CompareCounter(++it, 'b', 3, 0, __LINE__); + compareCounter(it, 'a', 4, 0, __LINE__); + compareCounter(++it, 'e', 4, 3, __LINE__); + compareCounter(++it, 'b', 3, 0, __LINE__); } } +// Test inserting items in random order. topK should not depend on the insert order. TEST(StreamSummaryTest, TestRandomInsertOrder) { std::vector v{'a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'e', 'e', 'f'}; @@ -119,16 +114,17 @@ TEST(StreamSummaryTest, TestRandomInsertOrder) { } auto top_k = summary.getTopK(); auto it = top_k.begin(); - CompareCounter(it, 'a', 6, 0, __LINE__); - CompareCounter(++it, 'b', 5, 0, __LINE__); - CompareCounter(++it, 'c', 4, 0, __LINE__); - CompareCounter(++it, 'd', 3, 0, __LINE__); - CompareCounter(++it, 'e', 2, 0, __LINE__); - CompareCounter(++it, 'f', 1, 0, __LINE__); + compareCounter(it, 'a', 6, 0, __LINE__); + compareCounter(++it, 'b', 5, 0, __LINE__); + compareCounter(++it, 'c', 4, 0, __LINE__); + compareCounter(++it, 'd', 3, 0, __LINE__); + compareCounter(++it, 'e', 2, 0, __LINE__); + compareCounter(++it, 'f', 1, 0, __LINE__); } } -TEST(StreamSummaryTest, TestGetK) { +// Test getTopK size parameter is handled as expected +TEST(StreamSummaryTest, TestGetTopKSize) { std::vector v{'a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'e', 'e', 'f'}; std::shuffle(v.begin(), v.end(), std::default_random_engine()); diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id_test.cc index 244e949b06ef..c7edbe6466c1 100644 --- a/test/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id_test.cc +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id_test.cc @@ -9,16 +9,16 @@ namespace Tracers { namespace OpenTelemetry { // Test calculation using an empty string -TEST(TenantIdTest, testEmpty) { EXPECT_EQ(absl::StrCat(calculateTenantId("")), "0"); } +TEST(TenantIdTest, TestEmpty) { EXPECT_EQ(absl::StrCat(calculateTenantId("")), "0"); } // Test calculation using strings with whitespace -TEST(TenantIdTest, testWhitespace) { +TEST(TenantIdTest, TestWhitespace) { EXPECT_EQ(absl::StrCat(calculateTenantId("abc 1234")), "182ccac"); EXPECT_EQ(absl::StrCat(calculateTenantId(" ")), "b173ef2e"); } // Test calculation using some expected strings -TEST(TenantIdTest, testValues) { +TEST(TenantIdTest, TestValues) { EXPECT_EQ(absl::StrCat(calculateTenantId("jmw13303")), "4d10bede"); EXPECT_EQ(absl::StrCat(calculateTenantId("abc12345")), "5b3f9fed"); EXPECT_EQ(absl::StrCat(calculateTenantId("?pfel")), "7712d29d");