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