From 9674edb25e8bfa42e4080aae2af42a4a6e78bfc7 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Fri, 22 Mar 2019 18:25:44 +0100 Subject: [PATCH] mplexer: Add some unit tests for our multiplexers --- pdns/Makefile.am | 21 ++++ pdns/dnsdistdist/Makefile.am | 35 +++--- pdns/dnsdistdist/test-mplexer.cc | 1 + pdns/recursordist/Makefile.am | 7 ++ pdns/recursordist/test-mplexer.cc | 1 + pdns/test-mplexer.cc | 182 ++++++++++++++++++++++++++++++ 6 files changed, 233 insertions(+), 14 deletions(-) create mode 120000 pdns/dnsdistdist/test-mplexer.cc create mode 120000 pdns/recursordist/test-mplexer.cc create mode 100644 pdns/test-mplexer.cc diff --git a/pdns/Makefile.am b/pdns/Makefile.am index 080f0e552..6749e4cf6 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -1291,6 +1291,7 @@ testrunner_SOURCES = \ nameserver.cc \ nsecrecords.cc \ opensslsigners.cc opensslsigners.hh \ + pollmplexer.cc \ qtype.cc \ rcpgenerator.cc \ responsestats.cc \ @@ -1316,6 +1317,7 @@ testrunner_SOURCES = \ test-lock_hh.cc \ test-lua_auth4_cc.cc \ test-misc_hh.cc \ + test-mplexer.cc \ test-nameserver_cc.cc \ test-packetcache_cc.cc \ test-packetcache_hh.cc \ @@ -1360,6 +1362,25 @@ testrunner_SOURCES += decafsigners.cc testrunner_LDADD += $(LIBDECAF_LIBS) endif +if HAVE_FREEBSD +ixfrdist_SOURCES += kqueuemplexer.cc +testrunner_SOURCES += kqueuemplexer.cc +endif + +if HAVE_LINUX +ixfrdist_SOURCES += epollmplexer.cc +testrunner_SOURCES += epollmplexer.cc +endif + +if HAVE_SOLARIS +ixfrdist_SOURCES += \ + devpollmplexer.cc \ + portsmplexer.cc +testrunner_SOURCES += \ + devpollmplexer.cc \ + portsmplexer.cc +endif + pdns_control_SOURCES = \ arguments.cc \ dynloader.cc \ diff --git a/pdns/dnsdistdist/Makefile.am b/pdns/dnsdistdist/Makefile.am index 8c9e90b5c..b827fe03c 100644 --- a/pdns/dnsdistdist/Makefile.am +++ b/pdns/dnsdistdist/Makefile.am @@ -213,20 +213,6 @@ dnsdist.$(OBJEXT): dnsmessage.pb.cc dnstap.pb.cc endif endif -if HAVE_FREEBSD -dnsdist_SOURCES += kqueuemplexer.cc -endif - -if HAVE_LINUX -dnsdist_SOURCES += epollmplexer.cc -endif - -if HAVE_SOLARIS -dnsdist_SOURCES += \ - devpollmplexer.cc \ - portsmplexer.cc -endif - testrunner_SOURCES = \ base64.hh \ dns.hh \ @@ -240,6 +226,7 @@ testrunner_SOURCES = \ test-dnsdistrules_cc.cc \ test-dnsparser_cc.cc \ test-iputils_hh.cc \ + test-mplexer.cc \ cachecleaner.hh \ dnsdist.hh \ dnsdist-cache.cc dnsdist-cache.hh \ @@ -259,6 +246,7 @@ testrunner_SOURCES = \ misc.cc misc.hh \ namespaces.hh \ pdnsexception.hh \ + pollmplexer.cc \ qtype.cc qtype.hh \ sholder.hh \ sodcrypto.cc \ @@ -268,6 +256,25 @@ testrunner_SOURCES = \ testrunner.cc \ xpf.cc xpf.hh +if HAVE_FREEBSD +dnsdist_SOURCES += kqueuemplexer.cc +testrunner_SOURCES += kqueuemplexer.cc +endif + +if HAVE_LINUX +dnsdist_SOURCES += epollmplexer.cc +testrunner_SOURCES += epollmplexer.cc +endif + +if HAVE_SOLARIS +dnsdist_SOURCES += \ + devpollmplexer.cc \ + portsmplexer.cc +testrunner_SOURCES += \ + devpollmplexer.cc \ + portsmplexer.cc +endif + testrunner_LDFLAGS = \ $(AM_LDFLAGS) \ $(PROGRAM_LDFLAGS) \ diff --git a/pdns/dnsdistdist/test-mplexer.cc b/pdns/dnsdistdist/test-mplexer.cc new file mode 120000 index 000000000..f40626702 --- /dev/null +++ b/pdns/dnsdistdist/test-mplexer.cc @@ -0,0 +1 @@ +../test-mplexer.cc \ No newline at end of file diff --git a/pdns/recursordist/Makefile.am b/pdns/recursordist/Makefile.am index 92c8ae5a2..64adc379a 100644 --- a/pdns/recursordist/Makefile.am +++ b/pdns/recursordist/Makefile.am @@ -235,6 +235,7 @@ testrunner_SOURCES = \ nsecrecords.cc \ pdnsexception.hh \ opensslsigners.cc opensslsigners.hh \ + pollmplexer.cc \ protobuf.cc protobuf.hh \ qtype.cc qtype.hh \ rcpgenerator.cc \ @@ -263,6 +264,7 @@ testrunner_SOURCES = \ test-ixfr_cc.cc \ test-misc_hh.cc \ test-mtasker.cc \ + test-mplexer.cc \ test-negcache_cc.cc \ test-packetcache_hh.cc \ test-rcpgenerator_cc.cc \ @@ -335,16 +337,21 @@ endif if HAVE_FREEBSD pdns_recursor_SOURCES += kqueuemplexer.cc +testrunner_SOURCES += kqueuemplexer.cc endif if HAVE_LINUX pdns_recursor_SOURCES += epollmplexer.cc +testrunner_SOURCES += epollmplexer.cc endif if HAVE_SOLARIS pdns_recursor_SOURCES += \ devpollmplexer.cc \ portsmplexer.cc +testrunner_SOURCES += \ + devpollmplexer.cc \ + portsmplexer.cc endif if HAVE_PROTOBUF diff --git a/pdns/recursordist/test-mplexer.cc b/pdns/recursordist/test-mplexer.cc new file mode 120000 index 000000000..f40626702 --- /dev/null +++ b/pdns/recursordist/test-mplexer.cc @@ -0,0 +1 @@ +../test-mplexer.cc \ No newline at end of file diff --git a/pdns/test-mplexer.cc b/pdns/test-mplexer.cc new file mode 100644 index 000000000..8a7412fea --- /dev/null +++ b/pdns/test-mplexer.cc @@ -0,0 +1,182 @@ + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#include +#include + +#include "mplexer.hh" +#include "misc.hh" + +BOOST_AUTO_TEST_SUITE(mplexer) + +BOOST_AUTO_TEST_CASE(test_MPlexer) { + auto mplexer = std::unique_ptr(FDMultiplexer::getMultiplexerSilent()); + BOOST_REQUIRE(mplexer != nullptr); + + struct timeval now; + int ready = mplexer->run(&now, 100); + BOOST_CHECK_EQUAL(ready, 0); + + std::vector readyFDs; + mplexer->getAvailableFDs(readyFDs, 0); + BOOST_CHECK_EQUAL(readyFDs.size(), 0); + + auto timeouts = mplexer->getTimeouts(now); + BOOST_CHECK_EQUAL(timeouts.size(), 0); + + int pipes[2]; + int res = pipe(pipes); + BOOST_REQUIRE_EQUAL(res, 0); + BOOST_REQUIRE_EQUAL(setNonBlocking(pipes[0]), true); + BOOST_REQUIRE_EQUAL(setNonBlocking(pipes[1]), true); + + /* let's declare a TTD that expired 5s ago */ + struct timeval ttd = now; + ttd.tv_sec -= 5; + + bool writeCBCalled = false; + auto writeCB = [](int fd, FDMultiplexer::funcparam_t param) { + auto calledPtr = boost::any_cast(param); + BOOST_REQUIRE(calledPtr != nullptr); + *calledPtr = true; + }; + mplexer->addWriteFD(pipes[1], + writeCB, + &writeCBCalled, + &ttd); + /* we can't add it twice */ + BOOST_CHECK_THROW(mplexer->addWriteFD(pipes[1], + writeCB, + &writeCBCalled, + &ttd), + FDMultiplexerException); + + readyFDs.clear(); + mplexer->getAvailableFDs(readyFDs, 0); + BOOST_REQUIRE_EQUAL(readyFDs.size(), 1); + BOOST_CHECK_EQUAL(readyFDs.at(0), pipes[1]); + + ready = mplexer->run(&now, 100); + BOOST_CHECK_EQUAL(ready, 1); + BOOST_CHECK_EQUAL(writeCBCalled, true); + + /* no read timeouts */ + timeouts = mplexer->getTimeouts(now, false); + BOOST_CHECK_EQUAL(timeouts.size(), 0); + /* but we should have a write one */ + timeouts = mplexer->getTimeouts(now, true); + BOOST_REQUIRE_EQUAL(timeouts.size(), 1); + BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[1]); + + /* can't remove from the wrong type of FD */ + BOOST_CHECK_THROW(mplexer->removeReadFD(pipes[1]), FDMultiplexerException); + mplexer->removeWriteFD(pipes[1]); + /* can't remove a non-existing FD */ + BOOST_CHECK_THROW(mplexer->removeWriteFD(pipes[0]), FDMultiplexerException); + BOOST_CHECK_THROW(mplexer->removeWriteFD(pipes[1]), FDMultiplexerException); + + readyFDs.clear(); + mplexer->getAvailableFDs(readyFDs, 0); + BOOST_REQUIRE_EQUAL(readyFDs.size(), 0); + + ready = mplexer->run(&now, 100); + BOOST_CHECK_EQUAL(ready, 0); + + bool readCBCalled = false; + auto readCB = [](int fd, FDMultiplexer::funcparam_t param) { + auto calledPtr = boost::any_cast(param); + BOOST_REQUIRE(calledPtr != nullptr); + *calledPtr = true; + }; + mplexer->addReadFD(pipes[0], + readCB, + &readCBCalled, + &ttd); + + /* not ready for reading yet */ + readyFDs.clear(); + mplexer->getAvailableFDs(readyFDs, 0); + BOOST_REQUIRE_EQUAL(readyFDs.size(), 0); + + ready = mplexer->run(&now, 100); + BOOST_CHECK_EQUAL(ready, 0); + BOOST_CHECK_EQUAL(readCBCalled, false); + + /* let's make the pipe readable */ + BOOST_REQUIRE_EQUAL(write(pipes[1], "0", 1), 1); + + readyFDs.clear(); + mplexer->getAvailableFDs(readyFDs, 0); + BOOST_REQUIRE_EQUAL(readyFDs.size(), 1); + BOOST_CHECK_EQUAL(readyFDs.at(0), pipes[0]); + + ready = mplexer->run(&now, 100); + BOOST_CHECK_EQUAL(ready, 1); + BOOST_CHECK_EQUAL(readCBCalled, true); + + /* add back the write FD */ + mplexer->addWriteFD(pipes[1], + writeCB, + &writeCBCalled, + &ttd); + + /* both should be available */ + readyFDs.clear(); + mplexer->getAvailableFDs(readyFDs, 0); + BOOST_REQUIRE_EQUAL(readyFDs.size(), 2); + + readCBCalled = false; + writeCBCalled = false; + ready = mplexer->run(&now, 100); + BOOST_CHECK_EQUAL(ready, 2); + BOOST_CHECK_EQUAL(readCBCalled, true); + BOOST_CHECK_EQUAL(writeCBCalled, true); + + /* both the read and write FD should be reported */ + timeouts = mplexer->getTimeouts(now, false); + BOOST_REQUIRE_EQUAL(timeouts.size(), 1); + BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[0]); + timeouts = mplexer->getTimeouts(now, true); + BOOST_REQUIRE_EQUAL(timeouts.size(), 1); + BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[1]); + + struct timeval past = ttd; + /* so five seconds before the actual TTD */ + past.tv_sec -= 5; + + /* no read timeouts */ + timeouts = mplexer->getTimeouts(past, false); + BOOST_CHECK_EQUAL(timeouts.size(), 0); + /* and we should not have a write one either */ + timeouts = mplexer->getTimeouts(past, true); + BOOST_CHECK_EQUAL(timeouts.size(), 0); + + /* update the timeouts to now, they should not be reported anymore */ + mplexer->setReadTTD(pipes[0], now, 0); + mplexer->setWriteTTD(pipes[1], now, 0); + timeouts = mplexer->getTimeouts(now, false); + BOOST_REQUIRE_EQUAL(timeouts.size(), 0); + timeouts = mplexer->getTimeouts(now, true); + BOOST_REQUIRE_EQUAL(timeouts.size(), 0); + + /* put it back into the past */ + mplexer->setReadTTD(pipes[0], now, -5); + mplexer->setWriteTTD(pipes[1], now, -5); + timeouts = mplexer->getTimeouts(now, false); + BOOST_REQUIRE_EQUAL(timeouts.size(), 1); + BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[0]); + timeouts = mplexer->getTimeouts(now, true); + BOOST_REQUIRE_EQUAL(timeouts.size(), 1); + BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[1]); + + mplexer->removeReadFD(pipes[0]); + mplexer->removeWriteFD(pipes[1]); + + /* clean up */ + close(pipes[0]); + close(pipes[1]); +} + + +BOOST_AUTO_TEST_SUITE_END() -- 2.40.0