]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/test-mplexer.cc
Merge pull request #8141 from rgacogne/dnsdist-ocsp
[thirdparty/pdns.git] / pdns / test-mplexer.cc
CommitLineData
9674edb2
RG
1
2#define BOOST_TEST_DYN_LINK
3#define BOOST_TEST_NO_MAIN
4
5#include <thread>
6#include <boost/test/unit_test.hpp>
7
8#include "mplexer.hh"
9#include "misc.hh"
10
11BOOST_AUTO_TEST_SUITE(mplexer)
12
13BOOST_AUTO_TEST_CASE(test_MPlexer) {
14 auto mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent());
15 BOOST_REQUIRE(mplexer != nullptr);
16
17 struct timeval now;
18 int ready = mplexer->run(&now, 100);
19 BOOST_CHECK_EQUAL(ready, 0);
20
21 std::vector<int> readyFDs;
22 mplexer->getAvailableFDs(readyFDs, 0);
23 BOOST_CHECK_EQUAL(readyFDs.size(), 0);
24
25 auto timeouts = mplexer->getTimeouts(now);
26 BOOST_CHECK_EQUAL(timeouts.size(), 0);
27
28 int pipes[2];
29 int res = pipe(pipes);
30 BOOST_REQUIRE_EQUAL(res, 0);
31 BOOST_REQUIRE_EQUAL(setNonBlocking(pipes[0]), true);
32 BOOST_REQUIRE_EQUAL(setNonBlocking(pipes[1]), true);
33
34 /* let's declare a TTD that expired 5s ago */
35 struct timeval ttd = now;
36 ttd.tv_sec -= 5;
37
38 bool writeCBCalled = false;
39 auto writeCB = [](int fd, FDMultiplexer::funcparam_t param) {
40 auto calledPtr = boost::any_cast<bool*>(param);
41 BOOST_REQUIRE(calledPtr != nullptr);
42 *calledPtr = true;
43 };
44 mplexer->addWriteFD(pipes[1],
45 writeCB,
46 &writeCBCalled,
47 &ttd);
48 /* we can't add it twice */
49 BOOST_CHECK_THROW(mplexer->addWriteFD(pipes[1],
50 writeCB,
51 &writeCBCalled,
52 &ttd),
53 FDMultiplexerException);
54
55 readyFDs.clear();
56 mplexer->getAvailableFDs(readyFDs, 0);
57 BOOST_REQUIRE_EQUAL(readyFDs.size(), 1);
58 BOOST_CHECK_EQUAL(readyFDs.at(0), pipes[1]);
59
60 ready = mplexer->run(&now, 100);
61 BOOST_CHECK_EQUAL(ready, 1);
62 BOOST_CHECK_EQUAL(writeCBCalled, true);
63
64 /* no read timeouts */
65 timeouts = mplexer->getTimeouts(now, false);
66 BOOST_CHECK_EQUAL(timeouts.size(), 0);
67 /* but we should have a write one */
68 timeouts = mplexer->getTimeouts(now, true);
69 BOOST_REQUIRE_EQUAL(timeouts.size(), 1);
70 BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[1]);
71
72 /* can't remove from the wrong type of FD */
73 BOOST_CHECK_THROW(mplexer->removeReadFD(pipes[1]), FDMultiplexerException);
74 mplexer->removeWriteFD(pipes[1]);
75 /* can't remove a non-existing FD */
76 BOOST_CHECK_THROW(mplexer->removeWriteFD(pipes[0]), FDMultiplexerException);
77 BOOST_CHECK_THROW(mplexer->removeWriteFD(pipes[1]), FDMultiplexerException);
78
79 readyFDs.clear();
80 mplexer->getAvailableFDs(readyFDs, 0);
81 BOOST_REQUIRE_EQUAL(readyFDs.size(), 0);
82
83 ready = mplexer->run(&now, 100);
84 BOOST_CHECK_EQUAL(ready, 0);
85
86 bool readCBCalled = false;
87 auto readCB = [](int fd, FDMultiplexer::funcparam_t param) {
88 auto calledPtr = boost::any_cast<bool*>(param);
89 BOOST_REQUIRE(calledPtr != nullptr);
90 *calledPtr = true;
91 };
92 mplexer->addReadFD(pipes[0],
9f79f5d1
RG
93 readCB,
94 &readCBCalled,
95 &ttd);
9674edb2
RG
96
97 /* not ready for reading yet */
98 readyFDs.clear();
99 mplexer->getAvailableFDs(readyFDs, 0);
100 BOOST_REQUIRE_EQUAL(readyFDs.size(), 0);
101
102 ready = mplexer->run(&now, 100);
103 BOOST_CHECK_EQUAL(ready, 0);
104 BOOST_CHECK_EQUAL(readCBCalled, false);
105
106 /* let's make the pipe readable */
107 BOOST_REQUIRE_EQUAL(write(pipes[1], "0", 1), 1);
108
109 readyFDs.clear();
110 mplexer->getAvailableFDs(readyFDs, 0);
111 BOOST_REQUIRE_EQUAL(readyFDs.size(), 1);
112 BOOST_CHECK_EQUAL(readyFDs.at(0), pipes[0]);
113
114 ready = mplexer->run(&now, 100);
115 BOOST_CHECK_EQUAL(ready, 1);
116 BOOST_CHECK_EQUAL(readCBCalled, true);
117
118 /* add back the write FD */
119 mplexer->addWriteFD(pipes[1],
120 writeCB,
121 &writeCBCalled,
122 &ttd);
123
124 /* both should be available */
125 readyFDs.clear();
126 mplexer->getAvailableFDs(readyFDs, 0);
9f79f5d1
RG
127 if (readyFDs.size() == 1) {
128 /* something is wrong, we need some debug infos */
129 cerr<<"FDMultiPlexer implementation is "<<mplexer->getName()<<endl;
130 cerr<<"Watching "<<mplexer->getWatchedFDCount(false)<<" FDs for read and "<<mplexer->getWatchedFDCount(true)<<" for write"<<endl;
131 cerr<<"pipes[0] is "<<pipes[0]<<endl;
132 cerr<<"pipes[1] is "<<pipes[1]<<endl;
0b5fa1e1 133 cerr<<"The file descriptor returned as ready is "<<readyFDs.at(0)<<endl;
9f79f5d1 134 char buffer[2];
0b5fa1e1 135 ssize_t res = write(pipes[1], "0", 1);
61e4d52d 136 int saved = errno;
0b5fa1e1 137 cerr<<"Writing to pipes[1] returns "<<res<<endl;
9f79f5d1 138 if (res == -1) {
61e4d52d 139 cerr<<"errno is "<<saved<<endl;
9f79f5d1 140 }
0b5fa1e1 141 res = read(pipes[0], &buffer[0], sizeof(buffer));
61e4d52d 142 saved = errno;
0b5fa1e1 143 cerr<<"Reading from pipes[0] returns "<<res<<endl;
9f79f5d1 144 if (res == -1) {
61e4d52d 145 cerr<<"errno is "<<saved<<endl;
9f79f5d1
RG
146 }
147 }
0b5fa1e1 148 BOOST_CHECK_EQUAL(readyFDs.size(), 2);
9674edb2
RG
149
150 readCBCalled = false;
151 writeCBCalled = false;
152 ready = mplexer->run(&now, 100);
153 BOOST_CHECK_EQUAL(ready, 2);
154 BOOST_CHECK_EQUAL(readCBCalled, true);
155 BOOST_CHECK_EQUAL(writeCBCalled, true);
156
157 /* both the read and write FD should be reported */
158 timeouts = mplexer->getTimeouts(now, false);
159 BOOST_REQUIRE_EQUAL(timeouts.size(), 1);
160 BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[0]);
161 timeouts = mplexer->getTimeouts(now, true);
162 BOOST_REQUIRE_EQUAL(timeouts.size(), 1);
163 BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[1]);
164
165 struct timeval past = ttd;
166 /* so five seconds before the actual TTD */
167 past.tv_sec -= 5;
168
169 /* no read timeouts */
170 timeouts = mplexer->getTimeouts(past, false);
171 BOOST_CHECK_EQUAL(timeouts.size(), 0);
172 /* and we should not have a write one either */
173 timeouts = mplexer->getTimeouts(past, true);
174 BOOST_CHECK_EQUAL(timeouts.size(), 0);
175
176 /* update the timeouts to now, they should not be reported anymore */
177 mplexer->setReadTTD(pipes[0], now, 0);
178 mplexer->setWriteTTD(pipes[1], now, 0);
179 timeouts = mplexer->getTimeouts(now, false);
180 BOOST_REQUIRE_EQUAL(timeouts.size(), 0);
181 timeouts = mplexer->getTimeouts(now, true);
182 BOOST_REQUIRE_EQUAL(timeouts.size(), 0);
183
184 /* put it back into the past */
185 mplexer->setReadTTD(pipes[0], now, -5);
186 mplexer->setWriteTTD(pipes[1], now, -5);
187 timeouts = mplexer->getTimeouts(now, false);
188 BOOST_REQUIRE_EQUAL(timeouts.size(), 1);
189 BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[0]);
190 timeouts = mplexer->getTimeouts(now, true);
191 BOOST_REQUIRE_EQUAL(timeouts.size(), 1);
192 BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[1]);
193
194 mplexer->removeReadFD(pipes[0]);
195 mplexer->removeWriteFD(pipes[1]);
196
197 /* clean up */
198 close(pipes[0]);
199 close(pipes[1]);
200}
201
202
203BOOST_AUTO_TEST_SUITE_END()