blob: 6c719c85c78cdbd071561c6363b92efa65504686 [file] [log] [blame]
Jeff Browne839a582010-04-22 18:58:52 -07001//
2// Copyright 2010 The Android Open Source Project
3//
4
5#include <utils/PollLoop.h>
6#include <utils/Timers.h>
7#include <utils/StopWatch.h>
8#include <gtest/gtest.h>
9#include <unistd.h>
10#include <time.h>
11
12#include "TestHelpers.h"
13
14// # of milliseconds to fudge stopwatch measurements
15#define TIMING_TOLERANCE_MS 25
16
17namespace android {
18
19class Pipe {
20public:
21 int sendFd;
22 int receiveFd;
23
24 Pipe() {
25 int fds[2];
26 ::pipe(fds);
27
28 receiveFd = fds[0];
29 sendFd = fds[1];
30 }
31
32 ~Pipe() {
33 ::close(sendFd);
34 ::close(receiveFd);
35 }
36
37 bool writeSignal() {
38 return ::write(sendFd, "*", 1) == 1;
39 }
40
41 bool readSignal() {
42 char buf[1];
43 return ::read(receiveFd, buf, 1) == 1;
44 }
45};
46
47class DelayedWake : public DelayedTask {
48 sp<PollLoop> mPollLoop;
49
50public:
51 DelayedWake(int delayMillis, const sp<PollLoop> pollLoop) :
52 DelayedTask(delayMillis), mPollLoop(pollLoop) {
53 }
54
55protected:
56 virtual void doTask() {
57 mPollLoop->wake();
58 }
59};
60
61class DelayedWriteSignal : public DelayedTask {
62 Pipe* mPipe;
63
64public:
65 DelayedWriteSignal(int delayMillis, Pipe* pipe) :
66 DelayedTask(delayMillis), mPipe(pipe) {
67 }
68
69protected:
70 virtual void doTask() {
71 mPipe->writeSignal();
72 }
73};
74
75class CallbackHandler {
76public:
77 void setCallback(const sp<PollLoop>& pollLoop, int fd, int events) {
78 pollLoop->setCallback(fd, events, staticHandler, this);
79 }
80
81protected:
82 virtual ~CallbackHandler() { }
83
84 virtual bool handler(int fd, int events) = 0;
85
86private:
87 static bool staticHandler(int fd, int events, void* data) {
88 return static_cast<CallbackHandler*>(data)->handler(fd, events);
89 }
90};
91
92class StubCallbackHandler : public CallbackHandler {
93public:
94 bool nextResult;
95 int callbackCount;
96
97 int fd;
98 int events;
99
100 StubCallbackHandler(bool nextResult) : nextResult(nextResult),
101 callbackCount(0), fd(-1), events(-1) {
102 }
103
104protected:
105 virtual bool handler(int fd, int events) {
106 callbackCount += 1;
107 this->fd = fd;
108 this->events = events;
109 return nextResult;
110 }
111};
112
113class PollLoopTest : public testing::Test {
114protected:
115 sp<PollLoop> mPollLoop;
116
117 virtual void SetUp() {
118 mPollLoop = new PollLoop();
119 }
120
121 virtual void TearDown() {
122 mPollLoop.clear();
123 }
124};
125
126
127TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeoutAndReturnsFalse) {
128 StopWatch stopWatch("pollOnce");
129 bool result = mPollLoop->pollOnce(100);
130 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
131
132 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
133 << "elapsed time should approx. equal timeout";
134 EXPECT_FALSE(result)
135 << "pollOnce result should be false because timeout occurred";
136}
137
138TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturnsTrue) {
139 mPollLoop->wake();
140
141 StopWatch stopWatch("pollOnce");
142 bool result = mPollLoop->pollOnce(1000);
143 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
144
145 EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
146 << "elapsed time should approx. zero because wake() was called before waiting";
147 EXPECT_TRUE(result)
148 << "pollOnce result should be true because loop was awoken";
149}
150
151TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturnsTrue) {
152 sp<DelayedWake> delayedWake = new DelayedWake(100, mPollLoop);
153 delayedWake->run();
154
155 StopWatch stopWatch("pollOnce");
156 bool result = mPollLoop->pollOnce(1000);
157 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
158
159 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
160 << "elapsed time should approx. equal wake delay";
161 EXPECT_TRUE(result)
162 << "pollOnce result should be true because loop was awoken";
163}
164
165TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturnsFalse) {
166 StopWatch stopWatch("pollOnce");
167 bool result = mPollLoop->pollOnce(0);
168 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
169
170 EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
171 << "elapsed time should be approx. zero";
172 EXPECT_FALSE(result)
173 << "pollOnce result should be false because timeout occurred";
174}
175
176TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturnsFalse) {
177 Pipe pipe;
178 StubCallbackHandler handler(true);
179
180 handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
181
182 StopWatch stopWatch("pollOnce");
183 bool result = mPollLoop->pollOnce(0);
184 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
185
186 EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
187 << "elapsed time should be approx. zero";
188 EXPECT_FALSE(result)
189 << "pollOnce result should be false because timeout occurred";
190 EXPECT_EQ(0, handler.callbackCount)
191 << "callback should not have been invoked because FD was not signalled";
192}
193
194TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCallbackAndReturnsTrue) {
195 Pipe pipe;
196 StubCallbackHandler handler(true);
197
198 ASSERT_TRUE(pipe.writeSignal());
199 handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
200
201 StopWatch stopWatch("pollOnce");
202 bool result = mPollLoop->pollOnce(0);
203 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
204
205 EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
206 << "elapsed time should be approx. zero";
207 EXPECT_TRUE(result)
208 << "pollOnce result should be true because FD was signalled";
209 EXPECT_EQ(1, handler.callbackCount)
210 << "callback should be invoked exactly once";
211 EXPECT_EQ(pipe.receiveFd, handler.fd)
212 << "callback should have received pipe fd as parameter";
213 EXPECT_EQ(POLL_IN, handler.events)
214 << "callback should have received POLL_IN as events";
215}
216
217TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturnsFalse) {
218 Pipe pipe;
219 StubCallbackHandler handler(true);
220
221 handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
222
223 StopWatch stopWatch("pollOnce");
224 bool result = mPollLoop->pollOnce(100);
225 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
226
227 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
228 << "elapsed time should approx. equal timeout";
229 EXPECT_FALSE(result)
230 << "pollOnce result should be false because timeout occurred";
231 EXPECT_EQ(0, handler.callbackCount)
232 << "callback should not have been invoked because FD was not signalled";
233}
234
235TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_ImmediatelyInvokesCallbackAndReturnsTrue) {
236 Pipe pipe;
237 StubCallbackHandler handler(true);
238
239 pipe.writeSignal();
240 handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
241
242 StopWatch stopWatch("pollOnce");
243 bool result = mPollLoop->pollOnce(100);
244 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
245
246 ASSERT_TRUE(pipe.readSignal())
247 << "signal should actually have been written";
248 EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
249 << "elapsed time should be approx. zero";
250 EXPECT_TRUE(result)
251 << "pollOnce result should be true because FD was signalled";
252 EXPECT_EQ(1, handler.callbackCount)
253 << "callback should be invoked exactly once";
254 EXPECT_EQ(pipe.receiveFd, handler.fd)
255 << "callback should have received pipe fd as parameter";
256 EXPECT_EQ(POLL_IN, handler.events)
257 << "callback should have received POLL_IN as events";
258}
259
260TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_PromptlyInvokesCallbackAndReturnsTrue) {
261 Pipe pipe;
262 StubCallbackHandler handler(true);
263 sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe);
264
265 handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
266 delayedWriteSignal->run();
267
268 StopWatch stopWatch("pollOnce");
269 bool result = mPollLoop->pollOnce(1000);
270 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
271
272 ASSERT_TRUE(pipe.readSignal())
273 << "signal should actually have been written";
274 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
275 << "elapsed time should approx. equal signal delay";
276 EXPECT_TRUE(result)
277 << "pollOnce result should be true because FD was signalled";
278 EXPECT_EQ(1, handler.callbackCount)
279 << "callback should be invoked exactly once";
280 EXPECT_EQ(pipe.receiveFd, handler.fd)
281 << "callback should have received pipe fd as parameter";
282 EXPECT_EQ(POLL_IN, handler.events)
283 << "callback should have received POLL_IN as events";
284}
285
286TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) {
287 Pipe pipe;
288 StubCallbackHandler handler(true);
289
290 handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
291 pipe.writeSignal(); // would cause FD to be considered signalled
292 mPollLoop->removeCallback(pipe.receiveFd);
293
294 StopWatch stopWatch("pollOnce");
295 bool result = mPollLoop->pollOnce(100);
296 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
297
298 ASSERT_TRUE(pipe.readSignal())
299 << "signal should actually have been written";
300 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
301 << "elapsed time should approx. equal timeout because FD was no longer registered";
302 EXPECT_FALSE(result)
303 << "pollOnce result should be false because timeout occurred";
304 EXPECT_EQ(0, handler.callbackCount)
305 << "callback should not be invoked";
306}
307
308TEST_F(PollLoopTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvokedAgainLater) {
309 Pipe pipe;
310 StubCallbackHandler handler(false);
311
312 handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
313
314 // First loop: Callback is registered and FD is signalled.
315 pipe.writeSignal();
316
317 StopWatch stopWatch("pollOnce");
318 bool result = mPollLoop->pollOnce(0);
319 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
320
321 ASSERT_TRUE(pipe.readSignal())
322 << "signal should actually have been written";
323 EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
324 << "elapsed time should approx. equal zero because FD was already signalled";
325 EXPECT_TRUE(result)
326 << "pollOnce result should be true because FD was signalled";
327 EXPECT_EQ(1, handler.callbackCount)
328 << "callback should be invoked";
329
330 // Second loop: Callback is no longer registered and FD is signalled.
331 pipe.writeSignal();
332
333 stopWatch.reset();
334 result = mPollLoop->pollOnce(0);
335 elapsedMillis = ns2ms(stopWatch.elapsedTime());
336
337 ASSERT_TRUE(pipe.readSignal())
338 << "signal should actually have been written";
339 EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
340 << "elapsed time should approx. equal zero because timeout was zero";
341 EXPECT_FALSE(result)
342 << "pollOnce result should be false because timeout occurred";
343 EXPECT_EQ(1, handler.callbackCount)
344 << "callback should not be invoked this time";
345}
346
347TEST_F(PollLoopTest, RemoveCallback_WhenCallbackNotAdded_ReturnsFalse) {
348 bool result = mPollLoop->removeCallback(1);
349
350 EXPECT_FALSE(result)
351 << "removeCallback should return false because FD not registered";
352}
353
354TEST_F(PollLoopTest, RemoveCallback_WhenCallbackAddedThenRemovedTwice_ReturnsTrueFirstTimeAndReturnsFalseSecondTime) {
355 Pipe pipe;
356 StubCallbackHandler handler(false);
357 handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
358
359 // First time.
360 bool result = mPollLoop->removeCallback(pipe.receiveFd);
361
362 EXPECT_TRUE(result)
363 << "removeCallback should return true first time because FD was registered";
364
365 // Second time.
366 result = mPollLoop->removeCallback(pipe.receiveFd);
367
368 EXPECT_FALSE(result)
369 << "removeCallback should return false second time because FD was no longer registered";
370}
371
372TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInvoked) {
373 Pipe pipe;
374 StubCallbackHandler handler1(true);
375 StubCallbackHandler handler2(true);
376
377 handler1.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
378 handler2.setCallback(mPollLoop, pipe.receiveFd, POLL_IN); // replace it
379 pipe.writeSignal(); // would cause FD to be considered signalled
380
381 StopWatch stopWatch("pollOnce");
382 bool result = mPollLoop->pollOnce(100);
383 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
384
385 ASSERT_TRUE(pipe.readSignal())
386 << "signal should actually have been written";
387 EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
388 << "elapsed time should approx. zero because FD was already signalled";
389 EXPECT_TRUE(result)
390 << "pollOnce result should be true because FD was signalled";
391 EXPECT_EQ(0, handler1.callbackCount)
392 << "original handler callback should not be invoked because it was replaced";
393 EXPECT_EQ(1, handler2.callbackCount)
394 << "replacement handler callback should be invoked";
395}
396
397
398} // namespace android