]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/test-mplexer.cc
8a7412fea6a87403a0091c8d2b885b7f8e000584
[thirdparty/pdns.git] / pdns / test-mplexer.cc
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
11 BOOST_AUTO_TEST_SUITE(mplexer)
12
13 BOOST_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],
93 readCB,
94 &readCBCalled,
95 &ttd);
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);
127 BOOST_REQUIRE_EQUAL(readyFDs.size(), 2);
128
129 readCBCalled = false;
130 writeCBCalled = false;
131 ready = mplexer->run(&now, 100);
132 BOOST_CHECK_EQUAL(ready, 2);
133 BOOST_CHECK_EQUAL(readCBCalled, true);
134 BOOST_CHECK_EQUAL(writeCBCalled, true);
135
136 /* both the read and write FD should be reported */
137 timeouts = mplexer->getTimeouts(now, false);
138 BOOST_REQUIRE_EQUAL(timeouts.size(), 1);
139 BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[0]);
140 timeouts = mplexer->getTimeouts(now, true);
141 BOOST_REQUIRE_EQUAL(timeouts.size(), 1);
142 BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[1]);
143
144 struct timeval past = ttd;
145 /* so five seconds before the actual TTD */
146 past.tv_sec -= 5;
147
148 /* no read timeouts */
149 timeouts = mplexer->getTimeouts(past, false);
150 BOOST_CHECK_EQUAL(timeouts.size(), 0);
151 /* and we should not have a write one either */
152 timeouts = mplexer->getTimeouts(past, true);
153 BOOST_CHECK_EQUAL(timeouts.size(), 0);
154
155 /* update the timeouts to now, they should not be reported anymore */
156 mplexer->setReadTTD(pipes[0], now, 0);
157 mplexer->setWriteTTD(pipes[1], now, 0);
158 timeouts = mplexer->getTimeouts(now, false);
159 BOOST_REQUIRE_EQUAL(timeouts.size(), 0);
160 timeouts = mplexer->getTimeouts(now, true);
161 BOOST_REQUIRE_EQUAL(timeouts.size(), 0);
162
163 /* put it back into the past */
164 mplexer->setReadTTD(pipes[0], now, -5);
165 mplexer->setWriteTTD(pipes[1], now, -5);
166 timeouts = mplexer->getTimeouts(now, false);
167 BOOST_REQUIRE_EQUAL(timeouts.size(), 1);
168 BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[0]);
169 timeouts = mplexer->getTimeouts(now, true);
170 BOOST_REQUIRE_EQUAL(timeouts.size(), 1);
171 BOOST_CHECK_EQUAL(timeouts.at(0).first, pipes[1]);
172
173 mplexer->removeReadFD(pipes[0]);
174 mplexer->removeWriteFD(pipes[1]);
175
176 /* clean up */
177 close(pipes[0]);
178 close(pipes[1]);
179 }
180
181
182 BOOST_AUTO_TEST_SUITE_END()