toolkit/modules/tests/xpcshell/test_DeferredTask.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:b1d6d31a81cf
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
3
4 /**
5 * This file tests the DeferredTask.jsm module.
6 */
7
8 ////////////////////////////////////////////////////////////////////////////////
9 /// Globals
10
11 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
12
13 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
14
15 XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
16 "resource://gre/modules/DeferredTask.jsm");
17 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
18 "resource://gre/modules/Promise.jsm");
19
20 /**
21 * Due to the nature of this module, most of the tests are time-dependent. All
22 * the timeouts are designed to occur at multiples of this granularity value,
23 * in milliseconds, that should be high enough to prevent intermittent failures,
24 * but low enough to prevent an excessive overall test execution time.
25 */
26 const T = 100;
27
28 /**
29 * Waits for the specified timeout before resolving the returned promise.
30 */
31 function promiseTimeout(aTimeoutMs)
32 {
33 let deferred = Promise.defer();
34 do_timeout(aTimeoutMs, deferred.resolve);
35 return deferred.promise;
36 }
37
38 function run_test()
39 {
40 run_next_test();
41 }
42
43 ////////////////////////////////////////////////////////////////////////////////
44 //// Tests
45
46 /**
47 * Creates a simple DeferredTask and executes it once.
48 */
49 add_test(function test_arm_simple()
50 {
51 new DeferredTask(run_next_test, 10).arm();
52 });
53
54 /**
55 * Checks that the delay set for the task is respected.
56 */
57 add_test(function test_arm_delay_respected()
58 {
59 let executed1 = false;
60 let executed2 = false;
61
62 new DeferredTask(function () {
63 executed1 = true;
64 do_check_false(executed2);
65 }, 1*T).arm();
66
67 new DeferredTask(function () {
68 executed2 = true;
69 do_check_true(executed1);
70 run_next_test();
71 }, 2*T).arm();
72 });
73
74 /**
75 * Checks that calling "arm" again does not introduce further delay.
76 */
77 add_test(function test_arm_delay_notrestarted()
78 {
79 let executed = false;
80
81 // Create a task that will run later.
82 let deferredTask = new DeferredTask(() => { executed = true; }, 4*T);
83 deferredTask.arm();
84
85 // Before the task starts, call "arm" again.
86 do_timeout(2*T, () => deferredTask.arm());
87
88 // The "arm" call should not have introduced further delays.
89 do_timeout(5*T, function () {
90 do_check_true(executed);
91 run_next_test();
92 });
93 });
94
95 /**
96 * Checks that a task runs only once when armed multiple times synchronously.
97 */
98 add_test(function test_arm_coalesced()
99 {
100 let executed = false;
101
102 let deferredTask = new DeferredTask(function () {
103 do_check_false(executed);
104 executed = true;
105 run_next_test();
106 }, 50);
107
108 deferredTask.arm();
109 deferredTask.arm();
110 });
111
112 /**
113 * Checks that a task runs only once when armed multiple times synchronously,
114 * even when it has been created with a delay of zero milliseconds.
115 */
116 add_test(function test_arm_coalesced_nodelay()
117 {
118 let executed = false;
119
120 let deferredTask = new DeferredTask(function () {
121 do_check_false(executed);
122 executed = true;
123 run_next_test();
124 }, 0);
125
126 deferredTask.arm();
127 deferredTask.arm();
128 });
129
130 /**
131 * Checks that a task can be armed again while running.
132 */
133 add_test(function test_arm_recursive()
134 {
135 let executed = false;
136
137 let deferredTask = new DeferredTask(function () {
138 if (!executed) {
139 executed = true;
140 deferredTask.arm();
141 } else {
142 run_next_test();
143 }
144 }, 50);
145
146 deferredTask.arm();
147 });
148
149 /**
150 * Checks that calling "arm" while an asynchronous task is running waits until
151 * the task is finished before restarting the delay.
152 */
153 add_test(function test_arm_async()
154 {
155 let finishedExecution = false;
156 let finishedExecutionAgain = false;
157
158 // Create a task that will run later.
159 let deferredTask = new DeferredTask(function () {
160 yield promiseTimeout(4*T);
161 if (!finishedExecution) {
162 finishedExecution = true;
163 } else if (!finishedExecutionAgain) {
164 finishedExecutionAgain = true;
165 }
166 }, 2*T);
167 deferredTask.arm();
168
169 // While the task is running, call "arm" again. This will result in a wait
170 // of 2*T until the task finishes, then another 2*T for the normal task delay
171 // specified on construction.
172 do_timeout(4*T, function () {
173 do_check_true(deferredTask.isRunning);
174 do_check_false(finishedExecution);
175 deferredTask.arm();
176 });
177
178 // This will fail in case the task was started without waiting 2*T after it
179 // has finished.
180 do_timeout(7*T, function () {
181 do_check_false(deferredTask.isRunning);
182 do_check_true(finishedExecution);
183 });
184
185 // This is in the middle of the second execution.
186 do_timeout(10*T, function () {
187 do_check_true(deferredTask.isRunning);
188 do_check_false(finishedExecutionAgain);
189 });
190
191 // Wait enough time to verify that the task was executed as expected.
192 do_timeout(13*T, function () {
193 do_check_false(deferredTask.isRunning);
194 do_check_true(finishedExecutionAgain);
195 run_next_test();
196 });
197 });
198
199 /**
200 * Checks that an armed task can be disarmed.
201 */
202 add_test(function test_disarm()
203 {
204 // Create a task that will run later.
205 let deferredTask = new DeferredTask(function () {
206 do_throw("This task should not run.");
207 }, 2*T);
208 deferredTask.arm();
209
210 // Disable execution later, but before the task starts.
211 do_timeout(1*T, () => deferredTask.disarm());
212
213 // Wait enough time to verify that the task did not run.
214 do_timeout(3*T, run_next_test);
215 });
216
217 /**
218 * Checks that calling "disarm" allows the delay to be restarted.
219 */
220 add_test(function test_disarm_delay_restarted()
221 {
222 let executed = false;
223
224 let deferredTask = new DeferredTask(() => { executed = true; }, 4*T);
225 deferredTask.arm();
226
227 do_timeout(2*T, function () {
228 deferredTask.disarm();
229 deferredTask.arm();
230 });
231
232 do_timeout(5*T, function () {
233 do_check_false(executed);
234 });
235
236 do_timeout(7*T, function () {
237 do_check_true(executed);
238 run_next_test();
239 });
240 });
241
242 /**
243 * Checks that calling "disarm" while an asynchronous task is running does not
244 * prevent the task to finish.
245 */
246 add_test(function test_disarm_async()
247 {
248 let finishedExecution = false;
249
250 let deferredTask = new DeferredTask(function () {
251 deferredTask.arm();
252 yield promiseTimeout(2*T);
253 finishedExecution = true;
254 }, 1*T);
255 deferredTask.arm();
256
257 do_timeout(2*T, function () {
258 do_check_true(deferredTask.isRunning);
259 do_check_true(deferredTask.isArmed);
260 do_check_false(finishedExecution);
261 deferredTask.disarm();
262 });
263
264 do_timeout(4*T, function () {
265 do_check_false(deferredTask.isRunning);
266 do_check_false(deferredTask.isArmed);
267 do_check_true(finishedExecution);
268 run_next_test();
269 });
270 });
271
272 /**
273 * Checks that calling "arm" immediately followed by "disarm" while an
274 * asynchronous task is running does not cause it to run again.
275 */
276 add_test(function test_disarm_immediate_async()
277 {
278 let executed = false;
279
280 let deferredTask = new DeferredTask(function () {
281 do_check_false(executed);
282 executed = true;
283 yield promiseTimeout(2*T);
284 }, 1*T);
285 deferredTask.arm();
286
287 do_timeout(2*T, function () {
288 do_check_true(deferredTask.isRunning);
289 do_check_false(deferredTask.isArmed);
290 deferredTask.arm();
291 deferredTask.disarm();
292 });
293
294 do_timeout(4*T, function () {
295 do_check_true(executed);
296 do_check_false(deferredTask.isRunning);
297 do_check_false(deferredTask.isArmed);
298 run_next_test();
299 });
300 });
301
302 /**
303 * Checks the isArmed and isRunning properties with a synchronous task.
304 */
305 add_test(function test_isArmed_isRunning()
306 {
307 let deferredTask = new DeferredTask(function () {
308 do_check_true(deferredTask.isRunning);
309 do_check_false(deferredTask.isArmed);
310 deferredTask.arm();
311 do_check_true(deferredTask.isArmed);
312 deferredTask.disarm();
313 do_check_false(deferredTask.isArmed);
314 run_next_test();
315 }, 50);
316
317 do_check_false(deferredTask.isArmed);
318 deferredTask.arm();
319 do_check_true(deferredTask.isArmed);
320 do_check_false(deferredTask.isRunning);
321 });
322
323 /**
324 * Checks that the "finalize" method executes a synchronous task.
325 */
326 add_test(function test_finalize()
327 {
328 let executed = false;
329 let timePassed = false;
330
331 let deferredTask = new DeferredTask(function () {
332 do_check_false(timePassed);
333 executed = true;
334 }, 2*T);
335 deferredTask.arm();
336
337 do_timeout(1*T, () => { timePassed = true; });
338
339 // This should trigger the immediate execution of the task.
340 deferredTask.finalize().then(function () {
341 do_check_true(executed);
342 run_next_test();
343 });
344 });
345
346 /**
347 * Checks that the "finalize" method executes the task again from start to
348 * finish in case it is already running.
349 */
350 add_test(function test_finalize_executes_entirely()
351 {
352 let executed = false;
353 let executedAgain = false;
354 let timePassed = false;
355
356 let deferredTask = new DeferredTask(function () {
357 // The first time, we arm the timer again and set up the finalization.
358 if (!executed) {
359 deferredTask.arm();
360 do_check_true(deferredTask.isArmed);
361 do_check_true(deferredTask.isRunning);
362
363 deferredTask.finalize().then(function () {
364 // When we reach this point, the task must be finished.
365 do_check_true(executedAgain);
366 do_check_false(timePassed);
367 do_check_false(deferredTask.isArmed);
368 do_check_false(deferredTask.isRunning);
369 run_next_test();
370 });
371
372 // The second execution triggered by the finalization waits 1*T for the
373 // current task to finish (see the timeout below), but then it must not
374 // wait for the 2*T specified on construction as normal task delay. The
375 // second execution will finish after the timeout below has passed again,
376 // for a total of 2*T of wait time.
377 do_timeout(3*T, () => { timePassed = true; });
378 }
379
380 yield promiseTimeout(1*T);
381
382 // Just before finishing, indicate if we completed the second execution.
383 if (executed) {
384 do_check_true(deferredTask.isRunning);
385 executedAgain = true;
386 } else {
387 executed = true;
388 }
389 }, 2*T);
390
391 deferredTask.arm();
392 });

mercurial