toolkit/modules/tests/xpcshell/test_DeferredTask.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/modules/tests/xpcshell/test_DeferredTask.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,392 @@
     1.4 +/* Any copyright is dedicated to the Public Domain.
     1.5 +   http://creativecommons.org/publicdomain/zero/1.0/ */
     1.6 +
     1.7 +/**
     1.8 + * This file tests the DeferredTask.jsm module.
     1.9 + */
    1.10 +
    1.11 +////////////////////////////////////////////////////////////////////////////////
    1.12 +/// Globals
    1.13 +
    1.14 +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
    1.15 +
    1.16 +Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    1.17 +
    1.18 +XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
    1.19 +                                  "resource://gre/modules/DeferredTask.jsm");
    1.20 +XPCOMUtils.defineLazyModuleGetter(this, "Promise",
    1.21 +                                  "resource://gre/modules/Promise.jsm");
    1.22 +
    1.23 +/**
    1.24 + * Due to the nature of this module, most of the tests are time-dependent.  All
    1.25 + * the timeouts are designed to occur at multiples of this granularity value,
    1.26 + * in milliseconds, that should be high enough to prevent intermittent failures,
    1.27 + * but low enough to prevent an excessive overall test execution time.
    1.28 + */
    1.29 +const T = 100;
    1.30 +
    1.31 +/**
    1.32 + * Waits for the specified timeout before resolving the returned promise.
    1.33 + */
    1.34 +function promiseTimeout(aTimeoutMs)
    1.35 +{
    1.36 +  let deferred = Promise.defer();
    1.37 +  do_timeout(aTimeoutMs, deferred.resolve);
    1.38 +  return deferred.promise;
    1.39 +}
    1.40 +
    1.41 +function run_test()
    1.42 +{
    1.43 +  run_next_test();
    1.44 +}
    1.45 +
    1.46 +////////////////////////////////////////////////////////////////////////////////
    1.47 +//// Tests
    1.48 +
    1.49 +/**
    1.50 + * Creates a simple DeferredTask and executes it once.
    1.51 + */
    1.52 +add_test(function test_arm_simple()
    1.53 +{
    1.54 +  new DeferredTask(run_next_test, 10).arm();
    1.55 +});
    1.56 +
    1.57 +/**
    1.58 + * Checks that the delay set for the task is respected.
    1.59 + */
    1.60 +add_test(function test_arm_delay_respected()
    1.61 +{
    1.62 +  let executed1 = false;
    1.63 +  let executed2 = false;
    1.64 +
    1.65 +  new DeferredTask(function () {
    1.66 +    executed1 = true;
    1.67 +    do_check_false(executed2);
    1.68 +  }, 1*T).arm();
    1.69 +
    1.70 +  new DeferredTask(function () {
    1.71 +    executed2 = true;
    1.72 +    do_check_true(executed1);
    1.73 +    run_next_test();
    1.74 +  }, 2*T).arm();
    1.75 +});
    1.76 +
    1.77 +/**
    1.78 + * Checks that calling "arm" again does not introduce further delay.
    1.79 + */
    1.80 +add_test(function test_arm_delay_notrestarted()
    1.81 +{
    1.82 +  let executed = false;
    1.83 +
    1.84 +  // Create a task that will run later.
    1.85 +  let deferredTask = new DeferredTask(() => { executed = true; }, 4*T);
    1.86 +  deferredTask.arm();
    1.87 +
    1.88 +  // Before the task starts, call "arm" again.
    1.89 +  do_timeout(2*T, () => deferredTask.arm());
    1.90 +
    1.91 +  // The "arm" call should not have introduced further delays.
    1.92 +  do_timeout(5*T, function () {
    1.93 +    do_check_true(executed);
    1.94 +    run_next_test();
    1.95 +  });
    1.96 +});
    1.97 +
    1.98 +/**
    1.99 + * Checks that a task runs only once when armed multiple times synchronously.
   1.100 + */
   1.101 +add_test(function test_arm_coalesced()
   1.102 +{
   1.103 +  let executed = false;
   1.104 +
   1.105 +  let deferredTask = new DeferredTask(function () {
   1.106 +    do_check_false(executed);
   1.107 +    executed = true;
   1.108 +    run_next_test();
   1.109 +  }, 50);
   1.110 +
   1.111 +  deferredTask.arm();
   1.112 +  deferredTask.arm();
   1.113 +});
   1.114 +
   1.115 +/**
   1.116 + * Checks that a task runs only once when armed multiple times synchronously,
   1.117 + * even when it has been created with a delay of zero milliseconds.
   1.118 + */
   1.119 +add_test(function test_arm_coalesced_nodelay()
   1.120 +{
   1.121 +  let executed = false;
   1.122 +
   1.123 +  let deferredTask = new DeferredTask(function () {
   1.124 +    do_check_false(executed);
   1.125 +    executed = true;
   1.126 +    run_next_test();
   1.127 +  }, 0);
   1.128 +
   1.129 +  deferredTask.arm();
   1.130 +  deferredTask.arm();
   1.131 +});
   1.132 +
   1.133 +/**
   1.134 + * Checks that a task can be armed again while running.
   1.135 + */
   1.136 +add_test(function test_arm_recursive()
   1.137 +{
   1.138 +  let executed = false;
   1.139 +
   1.140 +  let deferredTask = new DeferredTask(function () {
   1.141 +    if (!executed) {
   1.142 +      executed = true;
   1.143 +      deferredTask.arm();
   1.144 +    } else {
   1.145 +      run_next_test();
   1.146 +    }
   1.147 +  }, 50);
   1.148 +
   1.149 +  deferredTask.arm();
   1.150 +});
   1.151 +
   1.152 +/**
   1.153 + * Checks that calling "arm" while an asynchronous task is running waits until
   1.154 + * the task is finished before restarting the delay.
   1.155 + */
   1.156 +add_test(function test_arm_async()
   1.157 +{
   1.158 +  let finishedExecution = false;
   1.159 +  let finishedExecutionAgain = false;
   1.160 +
   1.161 +  // Create a task that will run later.
   1.162 +  let deferredTask = new DeferredTask(function () {
   1.163 +    yield promiseTimeout(4*T);
   1.164 +    if (!finishedExecution) {
   1.165 +      finishedExecution = true;
   1.166 +    } else if (!finishedExecutionAgain) {
   1.167 +      finishedExecutionAgain = true;
   1.168 +    }
   1.169 +  }, 2*T);
   1.170 +  deferredTask.arm();
   1.171 +
   1.172 +  // While the task is running, call "arm" again.  This will result in a wait
   1.173 +  // of 2*T until the task finishes, then another 2*T for the normal task delay
   1.174 +  // specified on construction.
   1.175 +  do_timeout(4*T, function () {
   1.176 +    do_check_true(deferredTask.isRunning);
   1.177 +    do_check_false(finishedExecution);
   1.178 +    deferredTask.arm();
   1.179 +  });
   1.180 +
   1.181 +  // This will fail in case the task was started without waiting 2*T after it
   1.182 +  // has finished.
   1.183 +  do_timeout(7*T, function () {
   1.184 +    do_check_false(deferredTask.isRunning);
   1.185 +    do_check_true(finishedExecution);
   1.186 +  });
   1.187 +
   1.188 +  // This is in the middle of the second execution.
   1.189 +  do_timeout(10*T, function () {
   1.190 +    do_check_true(deferredTask.isRunning);
   1.191 +    do_check_false(finishedExecutionAgain);
   1.192 +  });
   1.193 +
   1.194 +  // Wait enough time to verify that the task was executed as expected.
   1.195 +  do_timeout(13*T, function () {
   1.196 +    do_check_false(deferredTask.isRunning);
   1.197 +    do_check_true(finishedExecutionAgain);
   1.198 +    run_next_test();
   1.199 +  });
   1.200 +});
   1.201 +
   1.202 +/**
   1.203 + * Checks that an armed task can be disarmed.
   1.204 + */
   1.205 +add_test(function test_disarm()
   1.206 +{
   1.207 +  // Create a task that will run later.
   1.208 +  let deferredTask = new DeferredTask(function () {
   1.209 +    do_throw("This task should not run.");
   1.210 +  }, 2*T);
   1.211 +  deferredTask.arm();
   1.212 +
   1.213 +  // Disable execution later, but before the task starts.
   1.214 +  do_timeout(1*T, () => deferredTask.disarm());
   1.215 +
   1.216 +  // Wait enough time to verify that the task did not run.
   1.217 +  do_timeout(3*T, run_next_test);
   1.218 +});
   1.219 +
   1.220 +/**
   1.221 + * Checks that calling "disarm" allows the delay to be restarted.
   1.222 + */
   1.223 +add_test(function test_disarm_delay_restarted()
   1.224 +{
   1.225 +  let executed = false;
   1.226 +
   1.227 +  let deferredTask = new DeferredTask(() => { executed = true; }, 4*T);
   1.228 +  deferredTask.arm();
   1.229 +
   1.230 +  do_timeout(2*T, function () {
   1.231 +    deferredTask.disarm();
   1.232 +    deferredTask.arm();
   1.233 +  });
   1.234 +
   1.235 +  do_timeout(5*T, function () {
   1.236 +    do_check_false(executed);
   1.237 +  });
   1.238 +
   1.239 +  do_timeout(7*T, function () {
   1.240 +    do_check_true(executed);
   1.241 +    run_next_test();
   1.242 +  });
   1.243 +});
   1.244 +
   1.245 +/**
   1.246 + * Checks that calling "disarm" while an asynchronous task is running does not
   1.247 + * prevent the task to finish.
   1.248 + */
   1.249 +add_test(function test_disarm_async()
   1.250 +{
   1.251 +  let finishedExecution = false;
   1.252 +
   1.253 +  let deferredTask = new DeferredTask(function () {
   1.254 +    deferredTask.arm();
   1.255 +    yield promiseTimeout(2*T);
   1.256 +    finishedExecution = true;
   1.257 +  }, 1*T);
   1.258 +  deferredTask.arm();
   1.259 +
   1.260 +  do_timeout(2*T, function () {
   1.261 +    do_check_true(deferredTask.isRunning);
   1.262 +    do_check_true(deferredTask.isArmed);
   1.263 +    do_check_false(finishedExecution);
   1.264 +    deferredTask.disarm();
   1.265 +  });
   1.266 +
   1.267 +  do_timeout(4*T, function () {
   1.268 +    do_check_false(deferredTask.isRunning);
   1.269 +    do_check_false(deferredTask.isArmed);
   1.270 +    do_check_true(finishedExecution);
   1.271 +    run_next_test();
   1.272 +  });
   1.273 +});
   1.274 +
   1.275 +/**
   1.276 + * Checks that calling "arm" immediately followed by "disarm" while an
   1.277 + * asynchronous task is running does not cause it to run again.
   1.278 + */
   1.279 +add_test(function test_disarm_immediate_async()
   1.280 +{
   1.281 +  let executed = false;
   1.282 +
   1.283 +  let deferredTask = new DeferredTask(function () {
   1.284 +    do_check_false(executed);
   1.285 +    executed = true;
   1.286 +    yield promiseTimeout(2*T);
   1.287 +  }, 1*T);
   1.288 +  deferredTask.arm();
   1.289 +
   1.290 +  do_timeout(2*T, function () {
   1.291 +    do_check_true(deferredTask.isRunning);
   1.292 +    do_check_false(deferredTask.isArmed);
   1.293 +    deferredTask.arm();
   1.294 +    deferredTask.disarm();
   1.295 +  });
   1.296 +
   1.297 +  do_timeout(4*T, function () {
   1.298 +    do_check_true(executed);
   1.299 +    do_check_false(deferredTask.isRunning);
   1.300 +    do_check_false(deferredTask.isArmed);
   1.301 +    run_next_test();
   1.302 +  });
   1.303 +});
   1.304 +
   1.305 +/**
   1.306 + * Checks the isArmed and isRunning properties with a synchronous task.
   1.307 + */
   1.308 +add_test(function test_isArmed_isRunning()
   1.309 +{
   1.310 +  let deferredTask = new DeferredTask(function () {
   1.311 +    do_check_true(deferredTask.isRunning);
   1.312 +    do_check_false(deferredTask.isArmed);
   1.313 +    deferredTask.arm();
   1.314 +    do_check_true(deferredTask.isArmed);
   1.315 +    deferredTask.disarm();
   1.316 +    do_check_false(deferredTask.isArmed);
   1.317 +    run_next_test();
   1.318 +  }, 50);
   1.319 +
   1.320 +  do_check_false(deferredTask.isArmed);
   1.321 +  deferredTask.arm();
   1.322 +  do_check_true(deferredTask.isArmed);
   1.323 +  do_check_false(deferredTask.isRunning);
   1.324 +});
   1.325 +
   1.326 +/**
   1.327 + * Checks that the "finalize" method executes a synchronous task.
   1.328 + */
   1.329 +add_test(function test_finalize()
   1.330 +{
   1.331 +  let executed = false;
   1.332 +  let timePassed = false;
   1.333 +
   1.334 +  let deferredTask = new DeferredTask(function () {
   1.335 +    do_check_false(timePassed);
   1.336 +    executed = true;
   1.337 +  }, 2*T);
   1.338 +  deferredTask.arm();
   1.339 +
   1.340 +  do_timeout(1*T, () => { timePassed = true; });
   1.341 +
   1.342 +  // This should trigger the immediate execution of the task.
   1.343 +  deferredTask.finalize().then(function () {
   1.344 +    do_check_true(executed);
   1.345 +    run_next_test();
   1.346 +  });
   1.347 +});
   1.348 +
   1.349 +/**
   1.350 + * Checks that the "finalize" method executes the task again from start to
   1.351 + * finish in case it is already running.
   1.352 + */
   1.353 +add_test(function test_finalize_executes_entirely()
   1.354 +{
   1.355 +  let executed = false;
   1.356 +  let executedAgain = false;
   1.357 +  let timePassed = false;
   1.358 +
   1.359 +  let deferredTask = new DeferredTask(function () {
   1.360 +    // The first time, we arm the timer again and set up the finalization.
   1.361 +    if (!executed) {
   1.362 +      deferredTask.arm();
   1.363 +      do_check_true(deferredTask.isArmed);
   1.364 +      do_check_true(deferredTask.isRunning);
   1.365 +
   1.366 +      deferredTask.finalize().then(function () {
   1.367 +        // When we reach this point, the task must be finished.
   1.368 +        do_check_true(executedAgain);
   1.369 +        do_check_false(timePassed);
   1.370 +        do_check_false(deferredTask.isArmed);
   1.371 +        do_check_false(deferredTask.isRunning);
   1.372 +        run_next_test();
   1.373 +      });
   1.374 +
   1.375 +      // The second execution triggered by the finalization waits 1*T for the
   1.376 +      // current task to finish (see the timeout below), but then it must not
   1.377 +      // wait for the 2*T specified on construction as normal task delay.  The
   1.378 +      // second execution will finish after the timeout below has passed again,
   1.379 +      // for a total of 2*T of wait time.
   1.380 +      do_timeout(3*T, () => { timePassed = true; });
   1.381 +    }
   1.382 +
   1.383 +    yield promiseTimeout(1*T);
   1.384 +
   1.385 +    // Just before finishing, indicate if we completed the second execution.
   1.386 +    if (executed) {
   1.387 +      do_check_true(deferredTask.isRunning);
   1.388 +      executedAgain = true;
   1.389 +    } else {
   1.390 +      executed = true;
   1.391 +    }
   1.392 +  }, 2*T);
   1.393 +
   1.394 +  deferredTask.arm();
   1.395 +});

mercurial