blob: afc92f8cdffa045094cf36dd3d57fb3639f67c5c [file] [log] [blame]
Jeff Brown7901eb22010-09-13 23:17:30 -07001//
2// Copyright 2010 The Android Open Source Project
3//
4
5#include <utils/Looper.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 DelayedWake : public DelayedTask {
20 sp<Looper> mLooper;
21
22public:
23 DelayedWake(int delayMillis, const sp<Looper> looper) :
24 DelayedTask(delayMillis), mLooper(looper) {
25 }
26
27protected:
28 virtual void doTask() {
29 mLooper->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<Looper>& looper, int fd, int events) {
50 looper->addFd(fd, 0, events, staticHandler, this);
51 }
52
53protected:
54 virtual ~CallbackHandler() { }
55
56 virtual int handler(int fd, int events) = 0;
57
58private:
59 static int 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 int nextResult;
67 int callbackCount;
68
69 int fd;
70 int events;
71
72 StubCallbackHandler(int nextResult) : nextResult(nextResult),
73 callbackCount(0), fd(-1), events(-1) {
74 }
75
76protected:
77 virtual int handler(int fd, int events) {
78 callbackCount += 1;
79 this->fd = fd;
80 this->events = events;
81 return nextResult;
82 }
83};
84
85class LooperTest : public testing::Test {
86protected:
87 sp<Looper> mLooper;
88
89 virtual void SetUp() {
90 mLooper = new Looper(true);
91 }
92
93 virtual void TearDown() {
94 mLooper.clear();
95 }
96};
97
98
99TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeout) {
100 StopWatch stopWatch("pollOnce");
101 int result = mLooper->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_EQ(ALOOPER_POLL_TIMEOUT, result)
107 << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
108}
109
110TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturns) {
111 mLooper->wake();
112
113 StopWatch stopWatch("pollOnce");
114 int result = mLooper->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_EQ(ALOOPER_POLL_WAKE, result)
120 << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
121}
122
123TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturns) {
124 sp<DelayedWake> delayedWake = new DelayedWake(100, mLooper);
125 delayedWake->run();
126
127 StopWatch stopWatch("pollOnce");
128 int result = mLooper->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_EQ(ALOOPER_POLL_WAKE, result)
134 << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
135}
136
137TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturns) {
138 StopWatch stopWatch("pollOnce");
139 int result = mLooper->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_EQ(ALOOPER_POLL_TIMEOUT, result)
145 << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
146}
147
148TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturns) {
149 Pipe pipe;
150 StubCallbackHandler handler(true);
151
152 handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
153
154 StopWatch stopWatch("pollOnce");
155 int result = mLooper->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_EQ(ALOOPER_POLL_TIMEOUT, result)
161 << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
162 EXPECT_EQ(0, handler.callbackCount)
163 << "callback should not have been invoked because FD was not signalled";
164}
165
166TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCallbackAndReturns) {
167 Pipe pipe;
168 StubCallbackHandler handler(true);
169
170 ASSERT_EQ(OK, pipe.writeSignal());
171 handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
172
173 StopWatch stopWatch("pollOnce");
174 int result = mLooper->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_EQ(ALOOPER_POLL_CALLBACK, result)
180 << "pollOnce result should be ALOOPER_POLL_CALLBACK 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(ALOOPER_EVENT_INPUT, handler.events)
186 << "callback should have received ALOOPER_EVENT_INPUT as events";
187}
188
189TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturns) {
190 Pipe pipe;
191 StubCallbackHandler handler(true);
192
193 handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
194
195 StopWatch stopWatch("pollOnce");
196 int result = mLooper->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_EQ(ALOOPER_POLL_TIMEOUT, result)
202 << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
203 EXPECT_EQ(0, handler.callbackCount)
204 << "callback should not have been invoked because FD was not signalled";
205}
206
207TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_ImmediatelyInvokesCallbackAndReturns) {
208 Pipe pipe;
209 StubCallbackHandler handler(true);
210
211 pipe.writeSignal();
212 handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
213
214 StopWatch stopWatch("pollOnce");
215 int result = mLooper->pollOnce(100);
216 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
217
218 ASSERT_EQ(OK, pipe.readSignal())
219 << "signal should actually have been written";
220 EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
221 << "elapsed time should be approx. zero";
222 EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
223 << "pollOnce result should be ALOOPER_POLL_CALLBACK 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(ALOOPER_EVENT_INPUT, handler.events)
229 << "callback should have received ALOOPER_EVENT_INPUT as events";
230}
231
232TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_PromptlyInvokesCallbackAndReturns) {
233 Pipe pipe;
234 StubCallbackHandler handler(true);
235 sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe);
236
237 handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
238 delayedWriteSignal->run();
239
240 StopWatch stopWatch("pollOnce");
241 int result = mLooper->pollOnce(1000);
242 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
243
244 ASSERT_EQ(OK, pipe.readSignal())
245 << "signal should actually have been written";
246 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
247 << "elapsed time should approx. equal signal delay";
248 EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
249 << "pollOnce result should be ALOOPER_POLL_CALLBACK 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(ALOOPER_EVENT_INPUT, handler.events)
255 << "callback should have received ALOOPER_EVENT_INPUT as events";
256}
257
258TEST_F(LooperTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) {
259 Pipe pipe;
260 StubCallbackHandler handler(true);
261
262 handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
263 pipe.writeSignal(); // would cause FD to be considered signalled
264 mLooper->removeFd(pipe.receiveFd);
265
266 StopWatch stopWatch("pollOnce");
267 int result = mLooper->pollOnce(100);
268 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
269
270 ASSERT_EQ(OK, pipe.readSignal())
271 << "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_EQ(ALOOPER_POLL_TIMEOUT, result)
275 << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
276 EXPECT_EQ(0, handler.callbackCount)
277 << "callback should not be invoked";
278}
279
280TEST_F(LooperTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvokedAgainLater) {
281 Pipe pipe;
282 StubCallbackHandler handler(false);
283
284 handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
285
286 // First loop: Callback is registered and FD is signalled.
287 pipe.writeSignal();
288
289 StopWatch stopWatch("pollOnce");
290 int result = mLooper->pollOnce(0);
291 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
292
293 ASSERT_EQ(OK, pipe.readSignal())
294 << "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_EQ(ALOOPER_POLL_CALLBACK, result)
298 << "pollOnce result should be ALOOPER_POLL_CALLBACK 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 = mLooper->pollOnce(0);
307 elapsedMillis = ns2ms(stopWatch.elapsedTime());
308
309 ASSERT_EQ(OK, pipe.readSignal())
310 << "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_EQ(ALOOPER_POLL_TIMEOUT, result)
314 << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
315 EXPECT_EQ(1, handler.callbackCount)
316 << "callback should not be invoked this time";
317}
318
319TEST_F(LooperTest, PollOnce_WhenNonCallbackFdIsSignalled_ReturnsIdent) {
320 const int expectedIdent = 5;
321 void* expectedData = this;
322
323 Pipe pipe;
324
325 pipe.writeSignal();
326 mLooper->addFd(pipe.receiveFd, expectedIdent, ALOOPER_EVENT_INPUT, NULL, expectedData);
327
328 StopWatch stopWatch("pollOnce");
329 int fd;
330 int events;
331 void* data;
332 int result = mLooper->pollOnce(100, &fd, &events, &data);
333 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
334
335 ASSERT_EQ(OK, pipe.readSignal())
336 << "signal should actually have been written";
337 EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
338 << "elapsed time should be approx. zero";
339 EXPECT_EQ(expectedIdent, result)
340 << "pollOnce result should be the ident of the FD that was signalled";
341 EXPECT_EQ(pipe.receiveFd, fd)
342 << "pollOnce should have returned the received pipe fd";
343 EXPECT_EQ(ALOOPER_EVENT_INPUT, events)
344 << "pollOnce should have returned ALOOPER_EVENT_INPUT as events";
345 EXPECT_EQ(expectedData, data)
346 << "pollOnce should have returned the data";
347}
348
349TEST_F(LooperTest, AddFd_WhenCallbackAdded_ReturnsOne) {
350 Pipe pipe;
351 int result = mLooper->addFd(pipe.receiveFd, 0, ALOOPER_EVENT_INPUT, NULL, NULL);
352
353 EXPECT_EQ(1, result)
354 << "addFd should return 1 because FD was added";
355}
356
357TEST_F(LooperTest, AddFd_WhenEventsIsZero_ReturnsError) {
358 Pipe pipe;
359 int result = mLooper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
360
361 EXPECT_EQ(-1, result)
362 << "addFd should return -1 because arguments were invalid";
363}
364
365TEST_F(LooperTest, AddFd_WhenIdentIsNegativeAndCallbackIsNull_ReturnsError) {
366 Pipe pipe;
367 int result = mLooper->addFd(pipe.receiveFd, -1, ALOOPER_EVENT_INPUT, NULL, NULL);
368
369 EXPECT_EQ(-1, result)
370 << "addFd should return -1 because arguments were invalid";
371}
372
373TEST_F(LooperTest, AddFd_WhenNoCallbackAndAllowNonCallbacksIsFalse_ReturnsError) {
374 Pipe pipe;
375 sp<Looper> looper = new Looper(false /*allowNonCallbacks*/);
376 int result = looper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
377
378 EXPECT_EQ(-1, result)
379 << "addFd should return -1 because arguments were invalid";
380}
381
382TEST_F(LooperTest, RemoveFd_WhenCallbackNotAdded_ReturnsZero) {
383 int result = mLooper->removeFd(1);
384
385 EXPECT_EQ(0, result)
386 << "removeFd should return 0 because FD not registered";
387}
388
389TEST_F(LooperTest, RemoveFd_WhenCallbackAddedThenRemovedTwice_ReturnsOnceFirstTimeAndReturnsZeroSecondTime) {
390 Pipe pipe;
391 StubCallbackHandler handler(false);
392 handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
393
394 // First time.
395 int result = mLooper->removeFd(pipe.receiveFd);
396
397 EXPECT_EQ(1, result)
398 << "removeFd should return 1 first time because FD was registered";
399
400 // Second time.
401 result = mLooper->removeFd(pipe.receiveFd);
402
403 EXPECT_EQ(0, result)
404 << "removeFd should return 0 second time because FD was no longer registered";
405}
406
407TEST_F(LooperTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInvoked) {
408 Pipe pipe;
409 StubCallbackHandler handler1(true);
410 StubCallbackHandler handler2(true);
411
412 handler1.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
413 handler2.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); // replace it
414 pipe.writeSignal(); // would cause FD to be considered signalled
415
416 StopWatch stopWatch("pollOnce");
417 int result = mLooper->pollOnce(100);
418 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
419
420 ASSERT_EQ(OK, pipe.readSignal())
421 << "signal should actually have been written";
422 EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
423 << "elapsed time should approx. zero because FD was already signalled";
424 EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
425 << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
426 EXPECT_EQ(0, handler1.callbackCount)
427 << "original handler callback should not be invoked because it was replaced";
428 EXPECT_EQ(1, handler2.callbackCount)
429 << "replacement handler callback should be invoked";
430}
431
432
433} // namespace android