Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
4 package org.mozilla.gecko.background.common;
6 import junit.framework.AssertionFailedError;
8 import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
9 import org.mozilla.gecko.background.testhelpers.WaitHelper;
10 import org.mozilla.gecko.background.testhelpers.WaitHelper.InnerError;
11 import org.mozilla.gecko.background.testhelpers.WaitHelper.TimeoutError;
12 import org.mozilla.gecko.sync.ThreadPool;
14 public class TestWaitHelper extends AndroidSyncTestCase {
15 private static final String ERROR_UNIQUE_IDENTIFIER = "error unique identifier";
17 public static int NO_WAIT = 1; // Milliseconds.
18 public static int SHORT_WAIT = 100; // Milliseconds.
19 public static int LONG_WAIT = 3 * SHORT_WAIT;
21 private Object notifyMonitor = new Object();
22 // Guarded by notifyMonitor.
23 private boolean performNotifyCalled = false;
24 private boolean performNotifyErrorCalled = false;
25 private void setPerformNotifyCalled() {
26 synchronized (notifyMonitor) {
27 performNotifyCalled = true;
28 }
29 }
30 private void setPerformNotifyErrorCalled() {
31 synchronized (notifyMonitor) {
32 performNotifyErrorCalled = true;
33 }
34 }
35 private void resetNotifyCalled() {
36 synchronized (notifyMonitor) {
37 performNotifyCalled = false;
38 performNotifyErrorCalled = false;
39 }
40 }
41 private void assertBothCalled() {
42 synchronized (notifyMonitor) {
43 assertTrue(performNotifyCalled);
44 assertTrue(performNotifyErrorCalled);
45 }
46 }
47 private void assertErrorCalled() {
48 synchronized (notifyMonitor) {
49 assertFalse(performNotifyCalled);
50 assertTrue(performNotifyErrorCalled);
51 }
52 }
53 private void assertCalled() {
54 synchronized (notifyMonitor) {
55 assertTrue(performNotifyCalled);
56 assertFalse(performNotifyErrorCalled);
57 }
58 }
60 public WaitHelper waitHelper;
62 public TestWaitHelper() {
63 super();
64 }
66 public void setUp() {
67 WaitHelper.resetTestWaiter();
68 waitHelper = WaitHelper.getTestWaiter();
69 resetNotifyCalled();
70 }
72 public void tearDown() {
73 assertTrue(waitHelper.isIdle());
74 }
76 public Runnable performNothingRunnable() {
77 return new Runnable() {
78 public void run() {
79 }
80 };
81 }
83 public Runnable performNotifyRunnable() {
84 return new Runnable() {
85 public void run() {
86 setPerformNotifyCalled();
87 waitHelper.performNotify();
88 }
89 };
90 }
92 public Runnable performNotifyAfterDelayRunnable(final int delayInMillis) {
93 return new Runnable() {
94 public void run() {
95 try {
96 Thread.sleep(delayInMillis);
97 } catch (InterruptedException e) {
98 fail("Interrupted.");
99 }
101 setPerformNotifyCalled();
102 waitHelper.performNotify();
103 }
104 };
105 }
107 public Runnable performNotifyErrorRunnable() {
108 return new Runnable() {
109 public void run() {
110 setPerformNotifyCalled();
111 waitHelper.performNotify(new AssertionFailedError(ERROR_UNIQUE_IDENTIFIER));
112 }
113 };
114 }
116 public Runnable inThreadPool(final Runnable runnable) {
117 return new Runnable() {
118 @Override
119 public void run() {
120 ThreadPool.run(runnable);
121 }
122 };
123 }
125 public Runnable inThread(final Runnable runnable) {
126 return new Runnable() {
127 @Override
128 public void run() {
129 new Thread(runnable).start();
130 }
131 };
132 }
134 protected void expectAssertionFailedError(Runnable runnable) {
135 try {
136 waitHelper.performWait(runnable);
137 } catch (InnerError e) {
138 AssertionFailedError inner = (AssertionFailedError)e.innerError;
139 setPerformNotifyErrorCalled();
140 String message = inner.getMessage();
141 assertTrue("Expected '" + message + "' to contain '" + ERROR_UNIQUE_IDENTIFIER + "'",
142 message.contains(ERROR_UNIQUE_IDENTIFIER));
143 }
144 }
146 protected void expectAssertionFailedErrorAfterDelay(int wait, Runnable runnable) {
147 try {
148 waitHelper.performWait(wait, runnable);
149 } catch (InnerError e) {
150 AssertionFailedError inner = (AssertionFailedError)e.innerError;
151 setPerformNotifyErrorCalled();
152 String message = inner.getMessage();
153 assertTrue("Expected '" + message + "' to contain '" + ERROR_UNIQUE_IDENTIFIER + "'",
154 message.contains(ERROR_UNIQUE_IDENTIFIER));
155 }
156 }
158 public void testPerformWait() {
159 waitHelper.performWait(performNotifyRunnable());
160 assertCalled();
161 }
163 public void testPerformWaitInThread() {
164 waitHelper.performWait(inThread(performNotifyRunnable()));
165 assertCalled();
166 }
168 public void testPerformWaitInThreadPool() {
169 waitHelper.performWait(inThreadPool(performNotifyRunnable()));
170 assertCalled();
171 }
173 public void testPerformTimeoutWait() {
174 waitHelper.performWait(SHORT_WAIT, performNotifyRunnable());
175 assertCalled();
176 }
178 public void testPerformTimeoutWaitInThread() {
179 waitHelper.performWait(SHORT_WAIT, inThread(performNotifyRunnable()));
180 assertCalled();
181 }
183 public void testPerformTimeoutWaitInThreadPool() {
184 waitHelper.performWait(SHORT_WAIT, inThreadPool(performNotifyRunnable()));
185 assertCalled();
186 }
188 public void testPerformErrorWaitInThread() {
189 expectAssertionFailedError(inThread(performNotifyErrorRunnable()));
190 assertBothCalled();
191 }
193 public void testPerformErrorWaitInThreadPool() {
194 expectAssertionFailedError(inThreadPool(performNotifyErrorRunnable()));
195 assertBothCalled();
196 }
198 public void testPerformErrorTimeoutWaitInThread() {
199 expectAssertionFailedErrorAfterDelay(SHORT_WAIT, inThread(performNotifyErrorRunnable()));
200 assertBothCalled();
201 }
203 public void testPerformErrorTimeoutWaitInThreadPool() {
204 expectAssertionFailedErrorAfterDelay(SHORT_WAIT, inThreadPool(performNotifyErrorRunnable()));
205 assertBothCalled();
206 }
208 public void testTimeout() {
209 try {
210 waitHelper.performWait(SHORT_WAIT, performNothingRunnable());
211 } catch (TimeoutError e) {
212 setPerformNotifyErrorCalled();
213 assertEquals(SHORT_WAIT, e.waitTimeInMillis);
214 }
215 assertErrorCalled();
216 }
218 /**
219 * This will pass. The sequence in the main thread is:
220 * - A short delay.
221 * - performNotify is called.
222 * - performWait is called and immediately finds that performNotify was called before.
223 */
224 public void testDelay() {
225 try {
226 waitHelper.performWait(1, performNotifyAfterDelayRunnable(SHORT_WAIT));
227 } catch (AssertionFailedError e) {
228 setPerformNotifyErrorCalled();
229 assertTrue(e.getMessage(), e.getMessage().contains("TIMEOUT"));
230 }
231 assertCalled();
232 }
234 public Runnable performNotifyMultipleTimesRunnable() {
235 return new Runnable() {
236 public void run() {
237 waitHelper.performNotify();
238 setPerformNotifyCalled();
239 waitHelper.performNotify();
240 }
241 };
242 }
244 public void testPerformNotifyMultipleTimesFails() {
245 try {
246 waitHelper.performWait(NO_WAIT, performNotifyMultipleTimesRunnable()); // Not run on thread, so runnable executes before performWait looks for notifications.
247 } catch (WaitHelper.MultipleNotificationsError e) {
248 setPerformNotifyErrorCalled();
249 }
250 assertBothCalled();
251 assertFalse(waitHelper.isIdle()); // First perform notify should be hanging around.
252 waitHelper.performWait(NO_WAIT, performNothingRunnable());
253 }
255 public void testNestedWaitsAndNotifies() {
256 waitHelper.performWait(new Runnable() {
257 @Override
258 public void run() {
259 waitHelper.performWait(new Runnable() {
260 public void run() {
261 setPerformNotifyCalled();
262 waitHelper.performNotify();
263 }
264 });
265 setPerformNotifyErrorCalled();
266 waitHelper.performNotify();
267 }
268 });
269 assertBothCalled();
270 }
272 public void testAssertIsReported() {
273 try {
274 waitHelper.performWait(1, new Runnable() {
275 @Override
276 public void run() {
277 assertTrue("unique identifier", false);
278 }
279 });
280 } catch (AssertionFailedError e) {
281 setPerformNotifyErrorCalled();
282 assertTrue(e.getMessage(), e.getMessage().contains("unique identifier"));
283 }
284 assertErrorCalled();
285 }
287 /**
288 * The inner wait will timeout, but the outer wait will succeed. The sequence in the helper thread is:
289 * - A short delay.
290 * - performNotify is called.
291 *
292 * The sequence in the main thread is:
293 * - performWait is called and times out because the helper thread does not call
294 * performNotify quickly enough.
295 */
296 public void testDelayInThread() throws InterruptedException {
297 waitHelper.performWait(new Runnable() {
298 @Override
299 public void run() {
300 try {
301 waitHelper.performWait(NO_WAIT, inThread(new Runnable() {
302 public void run() {
303 try {
304 Thread.sleep(SHORT_WAIT);
305 } catch (InterruptedException e) {
306 fail("Interrupted.");
307 }
309 setPerformNotifyCalled();
310 waitHelper.performNotify();
311 }
312 }));
313 } catch (WaitHelper.TimeoutError e) {
314 setPerformNotifyErrorCalled();
315 assertEquals(NO_WAIT, e.waitTimeInMillis);
316 }
317 }
318 });
319 assertBothCalled();
320 }
322 /**
323 * The inner wait will timeout, but the outer wait will succeed. The sequence in the helper thread is:
324 * - A short delay.
325 * - performNotify is called.
326 *
327 * The sequence in the main thread is:
328 * - performWait is called and times out because the helper thread does not call
329 * performNotify quickly enough.
330 */
331 public void testDelayInThreadPool() throws InterruptedException {
332 waitHelper.performWait(new Runnable() {
333 @Override
334 public void run() {
335 try {
336 waitHelper.performWait(NO_WAIT, inThreadPool(new Runnable() {
337 public void run() {
338 try {
339 Thread.sleep(SHORT_WAIT);
340 } catch (InterruptedException e) {
341 fail("Interrupted.");
342 }
344 setPerformNotifyCalled();
345 waitHelper.performNotify();
346 }
347 }));
348 } catch (WaitHelper.TimeoutError e) {
349 setPerformNotifyErrorCalled();
350 assertEquals(NO_WAIT, e.waitTimeInMillis);
351 }
352 }
353 });
354 assertBothCalled();
355 }
356 }