From: Pieter Lexis Date: Thu, 25 Sep 2025 11:33:02 +0000 (+0200) Subject: tests(dnsdist): add OT Telemetry tests X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=97eb25c97d897c722fc3a74caa7e1ac42946fc64;p=thirdparty%2Fpdns.git tests(dnsdist): add OT Telemetry tests --- diff --git a/pdns/dnsdistdist/Makefile.am b/pdns/dnsdistdist/Makefile.am index ab423885d1..cef13c50ef 100644 --- a/pdns/dnsdistdist/Makefile.am +++ b/pdns/dnsdistdist/Makefile.am @@ -354,6 +354,7 @@ testrunner_SOURCES = \ dnsdist-metrics.cc dnsdist-metrics.hh \ dnsdist-nghttp2-in.hh \ dnsdist-nghttp2.hh \ + dnsdist-opentelemetry.cc dnsdist-opentelemetry.hh \ dnsdist-protocols.cc dnsdist-protocols.hh \ dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \ dnsdist-random.cc dnsdist-random.hh \ @@ -387,6 +388,8 @@ testrunner_SOURCES = \ noinitvector.hh \ pdnsexception.hh \ pollmplexer.cc \ + protozero-trace.cc protozero-trace.hh \ + protozero.cc protozero.hh \ proxy-protocol.cc proxy-protocol.hh \ qtype.cc qtype.hh \ sholder.hh \ @@ -405,6 +408,7 @@ testrunner_SOURCES = \ test-dnsdist-dnsparser.cc \ test-dnsdist-ipcrypt2_cc.cc \ test-dnsdist-lua-ffi.cc \ + test-dnsdist-opentelemetry_cc.cc \ test-dnsdist_cc.cc \ test-dnsdistasync.cc \ test-dnsdistbackend_cc.cc \ diff --git a/pdns/dnsdistdist/meson.build b/pdns/dnsdistdist/meson.build index 1ddd5797a4..69e42d5b3b 100644 --- a/pdns/dnsdistdist/meson.build +++ b/pdns/dnsdistdist/meson.build @@ -539,6 +539,7 @@ test_sources += files( src_dir / 'test-dnsdistluanetwork.cc', src_dir / 'test-dnsdistnghttp2_cc.cc', src_dir / 'test-dnsdistnghttp2-in_cc.cc', + src_dir / 'test-dnsdist-opentelemetry_cc.cc', src_dir / 'test-dnsdistpacketcache_cc.cc', src_dir / 'test-dnsdistrings_cc.cc', src_dir / 'test-dnsdistrules_cc.cc', diff --git a/pdns/dnsdistdist/test-dnsdist-opentelemetry_cc.cc b/pdns/dnsdistdist/test-dnsdist-opentelemetry_cc.cc new file mode 100644 index 0000000000..4e9c534e1b --- /dev/null +++ b/pdns/dnsdistdist/test-dnsdist-opentelemetry_cc.cc @@ -0,0 +1,246 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef DISABLE_PROTOBUF +#ifndef BOOST_TEST_DYN_LINK +#define BOOST_TEST_DYN_LINK +#include +#endif + +#include +#include +#include + +#include "dnsdist-opentelemetry.hh" + +#define BOOST_TEST_NO_MAIN + +BOOST_AUTO_TEST_SUITE(dnsdistopentelemetry_cc) +BOOST_AUTO_TEST_CASE(getTraceID) +{ + // Ensure we always have a TraceID after activation + auto tracer = pdns::trace::dnsdist::Tracer(); + BOOST_CHECK_EQUAL(tracer.getTraceID(), TraceID{}); + + // Ensure we have one *after* activation + tracer.activate(); + auto traceid = tracer.getTraceID(); + BOOST_CHECK_NE(traceid, TraceID{}); + + // Ensure we have the same one *after* deactivation + tracer.deactivate(); + BOOST_CHECK_EQUAL(tracer.getTraceID(), traceid); + + // Ensure we have the same one *after* reactivation + tracer.deactivate(); + BOOST_CHECK_EQUAL(tracer.getTraceID(), traceid); +} + +BOOST_AUTO_TEST_CASE(getLastSpanID) +{ + auto tracer = pdns::trace::dnsdist::Tracer(); + + // Empty SpanID returned when there are no spans + auto lastSpanID = tracer.getLastSpanID(); + BOOST_CHECK_EQUAL(lastSpanID, SpanID{}); + + // Add event before activation + auto spanid = tracer.openSpan("myevent").getSpanID(); + lastSpanID = tracer.getLastSpanID(); + BOOST_CHECK_EQUAL(spanid, lastSpanID); + + for (auto i = 0; i < 4; i++) { + spanid = tracer.openSpan("myevent" + std::to_string(i)).getSpanID(); + } + lastSpanID = tracer.getLastSpanID(); + BOOST_CHECK_EQUAL(spanid, lastSpanID); + + tracer.activate(); + spanid = tracer.openSpan("post-activation-myevent").getSpanID(); + lastSpanID = tracer.getLastSpanID(); + BOOST_CHECK_EQUAL(spanid, lastSpanID); + + for (auto i = 0; i < 4; i++) { + spanid = tracer.openSpan("post-activation-myevent" + std::to_string(i)).getSpanID(); + } + lastSpanID = tracer.getLastSpanID(); + BOOST_CHECK_EQUAL(spanid, lastSpanID); +} + +BOOST_AUTO_TEST_CASE(getLastSpanIDForName) +{ + // We only create spans with the same name + std::string eventName{"myEvent"}; + auto tracer = pdns::trace::dnsdist::Tracer(); + + // Empty SpanID returned when there are no spans + auto lastSpanID = tracer.getLastSpanIDForName(eventName); + BOOST_CHECK_EQUAL(lastSpanID, SpanID{}); + + // Add event before activation + auto spanid = tracer.openSpan(eventName).getSpanID(); + lastSpanID = tracer.getLastSpanIDForName(eventName); + BOOST_CHECK_EQUAL(spanid, lastSpanID); + + for (auto i = 0; i < 4; i++) { + spanid = tracer.openSpan(eventName).getSpanID(); + } + lastSpanID = tracer.getLastSpanIDForName(eventName); + BOOST_CHECK_EQUAL(spanid, lastSpanID); + auto preactivationSpanID = spanid; + + tracer.activate(); + spanid = tracer.openSpan(eventName).getSpanID(); + lastSpanID = tracer.getLastSpanIDForName(eventName); + BOOST_CHECK_EQUAL(spanid, lastSpanID); + + for (auto i = 0; i < 4; i++) { + spanid = tracer.openSpan(eventName).getSpanID(); + } + lastSpanID = tracer.getLastSpanIDForName(eventName); + BOOST_CHECK_EQUAL(spanid, lastSpanID); + + tracer.deactivate(); + lastSpanID = tracer.getLastSpanIDForName(eventName); + BOOST_CHECK_EQUAL(preactivationSpanID, lastSpanID); +} + +BOOST_AUTO_TEST_CASE(activate) +{ + auto tracer = pdns::trace::dnsdist::Tracer(); + + // We don't actually check the internal state, but we infer it from the order + // of the output. + auto preActivationSpanID = tracer.openSpan("pre-activation-event").getSpanID(); + tracer.activate(); + auto postActivationSpanID = tracer.openSpan("post-activation-event").getSpanID(); + + // Ensure order is pre1, post1 + auto trace = tracer.getTracesData(); + BOOST_ASSERT(trace.resource_spans.at(0).scope_spans.at(0).spans.size() == 2); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).span_id, preActivationSpanID); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(1).span_id, postActivationSpanID); + + // Now deactivate and check if the order will be pre1, pre2, post1 + tracer.deactivate(); + auto preActivationSpanID2 = tracer.openSpan("pre-activation-event2").getSpanID(); + + trace = tracer.getTracesData(); + BOOST_ASSERT(trace.resource_spans.at(0).scope_spans.at(0).spans.size() == 3); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).span_id, preActivationSpanID); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(1).span_id, preActivationSpanID2); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(2).span_id, postActivationSpanID); +} + +BOOST_AUTO_TEST_CASE(Closer) +{ + auto tracer = pdns::trace::dnsdist::Tracer(); + + auto prespanid = tracer.openSpan("foo").getSpanID(); + tracer.activate(); + auto postspanid = tracer.openSpan("bar").getSpanID(); + + SpanID openeventSpanID; + SpanID openevent2SpanID; + + { + auto precloser = tracer.getCloser(prespanid); + auto postcloser = tracer.getCloser(postspanid); + + auto openEventCloser = tracer.openSpan("openEvent"); + openeventSpanID = openEventCloser.getSpanID(); + auto openEventCloser2 = tracer.openSpan("openEvent2", openeventSpanID); + openevent2SpanID = openEventCloser2.getSpanID(); + + // Make sure the destructor does not segfault when it is empty + pdns::trace::dnsdist::Tracer::Closer emptyCloser; + } + + // Closer is out of scope, so each event should have a closing time + auto trace = tracer.getTracesData(); + BOOST_ASSERT(trace.resource_spans.at(0).scope_spans.at(0).spans.size() == 4); + + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).span_id, prespanid); + BOOST_CHECK_NE(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).end_time_unix_nano, 0); + + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(1).span_id, postspanid); + BOOST_CHECK_NE(trace.resource_spans.at(0).scope_spans.at(0).spans.at(1).end_time_unix_nano, 0); + + BOOST_CHECK_NE(trace.resource_spans.at(0).scope_spans.at(0).spans.at(2).end_time_unix_nano, 0); + BOOST_CHECK_NE(trace.resource_spans.at(0).scope_spans.at(0).spans.at(3).end_time_unix_nano, 0); + + // Check the parent span_id for the second closer + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(3).span_id, openevent2SpanID); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(3).parent_span_id, openeventSpanID); + + pdns::trace::dnsdist::Tracer::Closer emptyCloser; + BOOST_CHECK_EQUAL(emptyCloser.getSpanID(), SpanID{}); +} + +BOOST_AUTO_TEST_CASE(attributes) +{ + auto tracer = pdns::trace::dnsdist::Tracer(); + tracer.setTraceAttribute("foo", AnyValue{"bar"}); + + // Test that no attributes are added when the tracer is not activated + auto trace = tracer.getTracesData(); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).resource.attributes.size(), 1); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).resource.attributes.at(0).key, "service.name"); + + // Now activate and add 2 attributes + tracer.activate(); + tracer.setTraceAttribute("foo", AnyValue{"bar"}); + tracer.setTraceAttribute("baz", AnyValue{256}); + + trace = tracer.getTracesData(); + + BOOST_ASSERT(trace.resource_spans.at(0).resource.attributes.size() == 3); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).resource.attributes.at(1).key, "foo"); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).resource.attributes.at(1).value, AnyValue{"bar"}); + + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).resource.attributes.at(2).key, "baz"); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).resource.attributes.at(2).value, AnyValue{256}); + + // Add a span and some attributes + auto spanid = tracer.openSpan("anEvent").getSpanID(); + tracer.setSpanAttribute(spanid, "spanattr", AnyValue{"exciting"}); + + trace = tracer.getTracesData(); + + BOOST_ASSERT(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.size() == 1); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.front().key, "spanattr"); + BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.front().value, AnyValue{"exciting"}); +} + +BOOST_AUTO_TEST_CASE(getOTProtobuf) +{ + auto tracer = pdns::trace::dnsdist::Tracer(); + auto data = tracer.getOTProtobuf(); + BOOST_TEST(data.size() == 31U); + + tracer.activate(); + tracer.setTraceAttribute("foo", AnyValue{"bar"}); + data = tracer.getOTProtobuf(); + BOOST_TEST(data.size() == 45U); +} + +BOOST_AUTO_TEST_SUITE_END() +#endif // DISABLE_PROTOBUF