summaryrefslogtreecommitdiffstats
path: root/toolkit/components/osfile/tests/xpcshell/test_osfile_kill.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/osfile/tests/xpcshell/test_osfile_kill.js')
-rw-r--r--toolkit/components/osfile/tests/xpcshell/test_osfile_kill.js100
1 files changed, 0 insertions, 100 deletions
diff --git a/toolkit/components/osfile/tests/xpcshell/test_osfile_kill.js b/toolkit/components/osfile/tests/xpcshell/test_osfile_kill.js
deleted file mode 100644
index e32c37224..000000000
--- a/toolkit/components/osfile/tests/xpcshell/test_osfile_kill.js
+++ /dev/null
@@ -1,100 +0,0 @@
-"use strict";
-
-Components.utils.import("resource://gre/modules/osfile.jsm");
-
-// We want the actual global to get at the internals since Scheduler is not
-// exported.
-var AsyncFrontGlobal = Components.utils.import(
- "resource://gre/modules/osfile/osfile_async_front.jsm",
- null);
-var Scheduler = AsyncFrontGlobal.Scheduler;
-
-/**
- * Verify that Scheduler.kill() interacts with other OS.File requests correctly,
- * and that no requests are lost. This is relevant because on B2G we
- * auto-kill the worker periodically, making it very possible for valid requests
- * to be interleaved with the automatic kill().
- *
- * This test is being created with the fix for Bug 1125989 where `kill` queue
- * management was found to be buggy. It is a glass-box test that explicitly
- * re-creates the observed failure situation; it is not guaranteed to prevent
- * all future regressions. The following is a detailed explanation of the test
- * for your benefit if this test ever breaks or you are wondering what was the
- * point of all this. You might want to skim the code below first.
- *
- * OS.File maintains a `queue` of operations to be performed. This queue is
- * nominally implemented as a chain of promises. Every time a new job is
- * OS.File.push()ed, it effectively becomes the new `queue` promise. (An
- * extra promise is interposed with a rejection handler to avoid the rejection
- * cascading, but that does not matter for our purposes.)
- *
- * The flaw in `kill` was that it would wait for the `queue` to complete before
- * replacing `queue`. As a result, another OS.File operation could use `push`
- * (by way of OS.File.post()) to also use .then() on the same `queue` promise.
- * Accordingly, assuming that promise was not yet resolved (due to a pending
- * OS.File request), when it was resolved, both the task scheduled in `kill`
- * and in `post` would be triggered. Both of those tasks would run until
- * encountering a call to worker.post().
- *
- * Re-creating this race is not entirely trivial because of the large number of
- * promises used by the code causing control flow to repeatedly be deferred. In
- * a slightly simpler world we could run the follwing in the same turn of the
- * event loop and trigger the problem.
- * - any OS.File request
- * - Scheduler.kill()
- * - any OS.File request
- *
- * However, we need the Scheduler.kill task to reach the point where it is
- * waiting on the same `queue` that another task has been scheduled against.
- * Since the `kill` task yields on the `killQueue` promise prior to yielding
- * on `queue`, however, some turns of the event loop are required. Happily,
- * for us, as discussed above, the problem triggers when we have two promises
- * scheduled on the `queue`, so we can just wait to schedule the second OS.File
- * request on the queue. (Note that because of the additional then() added to
- * eat rejections, there is an important difference between the value of
- * `queue` and the value returned by the first OS.File request.)
- */
-add_task(function* test_kill_race() {
- // Ensure the worker has been created and that SET_DEBUG has taken effect.
- // We have chosen OS.File.exists for our tests because it does not trigger
- // a rejection and we absolutely do not care what the operation is other
- // than it does not invoke a native fast-path.
- yield OS.File.exists('foo.foo');
-
- do_print('issuing first request');
- let firstRequest = OS.File.exists('foo.bar');
- let secondRequest;
- let secondResolved = false;
-
- // As noted in our big block comment, we want to wait to schedule the
- // second request so that it races `kill`'s call to `worker.post`. Having
- // ourselves wait on the same promise, `queue`, and registering ourselves
- // before we issue the kill request means we will get run before the `kill`
- // task resumes and allow us to precisely create the desired race.
- Scheduler.queue.then(function() {
- do_print('issuing second request');
- secondRequest = OS.File.exists('foo.baz');
- secondRequest.then(function() {
- secondResolved = true;
- });
- });
-
- do_print('issuing kill request');
- let killRequest = Scheduler.kill({ reset: true, shutdown: false });
-
- // Wait on the killRequest so that we can schedule a new OS.File request
- // after it completes...
- yield killRequest;
- // ...because our ordering guarantee ensures that there is at most one
- // worker (and this usage here should not be vulnerable even with the
- // bug present), so when this completes the secondRequest has either been
- // resolved or lost.
- yield OS.File.exists('foo.goz');
-
- ok(secondResolved,
- 'The second request was resolved so we avoided the bug. Victory!');
-});
-
-function run_test() {
- run_next_test();
-}