]>
Commit | Line | Data |
---|---|---|
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 | ||
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], | |
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 | ||
203 | BOOST_AUTO_TEST_SUITE_END() |