dom/base/test/test_domrequesthelper.xul

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/base/test/test_domrequesthelper.xul	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,491 @@
     1.4 +<?xml version="1.0"?>
     1.5 +<!--
     1.6 +  Any copyright is dedicated to the Public Domain.
     1.7 +  http://creativecommons.org/publicdomain/zero/1.0/
     1.8 +-->
     1.9 +<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
    1.10 +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
    1.11 +
    1.12 +<window title="DOMRequestHelper Test"
    1.13 +        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    1.14 +        onload="start();">
    1.15 +
    1.16 +  <script type="application/javascript"
    1.17 +          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
    1.18 +
    1.19 +  <script type="application/javascript">
    1.20 +  <![CDATA[
    1.21 +    const Cc = Components.classes;
    1.22 +    const Cu = Components.utils;
    1.23 +    const Ci = Components.interfaces;
    1.24 +    Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
    1.25 +    let obs = Cc["@mozilla.org/observer-service;1"].
    1.26 +              getService(Ci.nsIObserverService);
    1.27 +
    1.28 +    function DummyHelperSubclass() {
    1.29 +      this.onuninit = null;
    1.30 +    }
    1.31 +    DummyHelperSubclass.prototype = {
    1.32 +      __proto__: DOMRequestIpcHelper.prototype,
    1.33 +      uninit: function() {
    1.34 +        if (typeof this.onuninit === "function") {
    1.35 +          this.onuninit();
    1.36 +        }
    1.37 +        this.onuninit = null;
    1.38 +      }
    1.39 +    };
    1.40 +
    1.41 +    var dummy = new DummyHelperSubclass();
    1.42 +
    1.43 +    /**
    1.44 +     * Init & destroy.
    1.45 +     */
    1.46 +    function initDOMRequestHelperTest(aMessages) {
    1.47 +      is(dummy._requests, undefined, "Request is undefined");
    1.48 +      is(dummy._messages, undefined, "Messages is undefined");
    1.49 +      is(dummy._window, undefined, "Window is undefined");
    1.50 +
    1.51 +      dummy.initDOMRequestHelper(window, aMessages);
    1.52 +
    1.53 +      ok(dummy._window, "Window exists");
    1.54 +      is(dummy._window, window, "Correct window");
    1.55 +      if (aMessages) {
    1.56 +        is(typeof dummy._listeners, "object", "Listeners is an object");
    1.57 +      }
    1.58 +    }
    1.59 +
    1.60 +    function destroyDOMRequestHelperTest() {
    1.61 +      dummy.destroyDOMRequestHelper();
    1.62 +
    1.63 +      is(dummy._requests, undefined, "Request is undefined");
    1.64 +      is(dummy._messages, undefined, "Messages is undefined");
    1.65 +      is(dummy._window, undefined, "Window is undefined");
    1.66 +    }
    1.67 +
    1.68 +    /**
    1.69 +     * Message listeners.
    1.70 +     */
    1.71 +    function checkMessageListeners(aExpectedListeners, aCount) {
    1.72 +      ok(true, "Checking message listeners\n" + "Expected listeners " +
    1.73 +         JSON.stringify(aExpectedListeners) + " \nExpected count " + aCount);
    1.74 +      let count = 0;
    1.75 +      Object.keys(dummy._listeners).forEach(function(name) {
    1.76 +        count++;
    1.77 +        is(aExpectedListeners[name], dummy._listeners[name],
    1.78 +           "Message found " + name + " - Same listeners");
    1.79 +      });
    1.80 +      is(aCount, count, "Correct number of listeners");
    1.81 +    }
    1.82 +
    1.83 +    function addMessageListenersTest(aMessages, aExpectedListeners, aCount) {
    1.84 +      dummy.addMessageListeners(aMessages);
    1.85 +      ok(true, JSON.stringify(dummy._listeners));
    1.86 +      checkMessageListeners(aExpectedListeners, aCount);
    1.87 +    }
    1.88 +
    1.89 +    function removeMessageListenersTest(aMessages, aExpectedListeners, aCount) {
    1.90 +      dummy.removeMessageListeners(aMessages);
    1.91 +      checkMessageListeners(aExpectedListeners, aCount);
    1.92 +    }
    1.93 +
    1.94 +    /**
    1.95 +     * Utility function to test window destruction behavior.  In general this
    1.96 +     * function does the following:
    1.97 +     *
    1.98 +     *  1) Create a new iframe
    1.99 +     *  2) Create a new DOMRequestHelper
   1.100 +     *  3) initDOMRequestHelper(), optionally with weak or strong listeners
   1.101 +     *  4) Optionally force a garbage collection to reap weak references
   1.102 +     *  5) Destroy the iframe triggering an inner-window-destroyed event
   1.103 +     *  6) Callback with a boolean indicating if DOMRequestHelper.uninit() was
   1.104 +     *     called.
   1.105 +     *
   1.106 +     * Example usage:
   1.107 +     *
   1.108 +     *    checkWindowDestruction({ messages: ["foo"], gc: true },
   1.109 +     *                           function(uninitCalled) {
   1.110 +     *      // expect uninitCalled === false since GC with only weak refs
   1.111 +     *    });
   1.112 +     */
   1.113 +    const TOPIC = "inner-window-destroyed";
   1.114 +    function checkWindowDestruction(aOptions, aCallback) {
   1.115 +      aOptions = aOptions || {};
   1.116 +      aOptions.messages = aOptions.messages || [];
   1.117 +      aOptions.gc = !!aOptions.gc;
   1.118 +
   1.119 +      if (typeof aCallback !== "function") {
   1.120 +        aCallback = function() { };
   1.121 +      }
   1.122 +
   1.123 +      let uninitCalled = false;
   1.124 +
   1.125 +      // Use a secondary observer so we know when to expect the uninit().  We
   1.126 +      // can then reasonably expect uninitCalled to be set properly on the
   1.127 +      // next tick.
   1.128 +      let observer = {
   1.129 +        observe: function(aSubject, aTopic, aData) {
   1.130 +          if (aTopic !== TOPIC) {
   1.131 +            return;
   1.132 +          }
   1.133 +          obs.removeObserver(observer, TOPIC);
   1.134 +          setTimeout(function() {
   1.135 +            aCallback(uninitCalled);
   1.136 +          });
   1.137 +        }
   1.138 +      };
   1.139 +
   1.140 +      let frame = document.createElement("iframe");
   1.141 +      frame.onload = function() {
   1.142 +        obs.addObserver(observer, TOPIC, false);
   1.143 +        // Create dummy DOMRequestHelper specific to checkWindowDestruction()
   1.144 +        let cwdDummy = new DummyHelperSubclass();
   1.145 +        cwdDummy.onuninit = function() {
   1.146 +          uninitCalled = true;
   1.147 +        };
   1.148 +        cwdDummy.initDOMRequestHelper(frame.contentWindow, aOptions.messages);
   1.149 +        // Make sure to clear our strong ref here so that we can test our
   1.150 +        // weak reference listeners and observer.
   1.151 +        cwdDummy = null;
   1.152 +        if (aOptions.gc) {
   1.153 +          Cu.schedulePreciseGC(function() {
   1.154 +            SpecialPowers.DOMWindowUtils.cycleCollect();
   1.155 +            SpecialPowers.DOMWindowUtils.garbageCollect();
   1.156 +            SpecialPowers.DOMWindowUtils.garbageCollect();
   1.157 +            document.documentElement.removeChild(frame);
   1.158 +          });
   1.159 +          return;
   1.160 +        }
   1.161 +        document.documentElement.removeChild(frame);
   1.162 +      };
   1.163 +      document.documentElement.appendChild(frame);
   1.164 +    }
   1.165 +
   1.166 +    /**
   1.167 +     * Test steps.
   1.168 +     */
   1.169 +    var tests = [
   1.170 +      function() {
   1.171 +        ok(true, "== InitDOMRequestHelper no messages");
   1.172 +        initDOMRequestHelperTest(null);
   1.173 +        next();
   1.174 +      },
   1.175 +      function() {
   1.176 +        ok(true, "== DestroyDOMRequestHelper");
   1.177 +        destroyDOMRequestHelperTest();
   1.178 +        next();
   1.179 +      },
   1.180 +      function() {
   1.181 +        ok(true, "== InitDOMRequestHelper empty array");
   1.182 +        initDOMRequestHelperTest([]);
   1.183 +        checkMessageListeners({}, 0);
   1.184 +        next();
   1.185 +      },
   1.186 +      function() {
   1.187 +        ok(true, "== DestroyDOMRequestHelper");
   1.188 +        destroyDOMRequestHelperTest();
   1.189 +        next();
   1.190 +      },
   1.191 +      function() {
   1.192 +        ok(true, "== InitDOMRequestHelper with strings array");
   1.193 +        initDOMRequestHelperTest(["name1", "nameN"]);
   1.194 +        checkMessageListeners({"name1": false, "nameN": false}, 2);
   1.195 +        next();
   1.196 +      },
   1.197 +      function() {
   1.198 +        ok(true, "== DestroyDOMRequestHelper");
   1.199 +        destroyDOMRequestHelperTest();
   1.200 +        next();
   1.201 +      },
   1.202 +      function() {
   1.203 +        ok(true, "== InitDOMRequestHelper with objects array");
   1.204 +        initDOMRequestHelperTest([{
   1.205 +          name: "name1",
   1.206 +          weakRef: false
   1.207 +        }, {
   1.208 +          name: "nameN",
   1.209 +          weakRef: true
   1.210 +        }]);
   1.211 +        checkMessageListeners({"name1": false, "nameN": true}, 2);
   1.212 +        next();
   1.213 +      },
   1.214 +      function() {
   1.215 +        ok(true, "== AddMessageListeners empty array");
   1.216 +        addMessageListenersTest([], {"name1": false, "nameN": true}, 2);
   1.217 +        next();
   1.218 +      },
   1.219 +      function() {
   1.220 +        ok(true, "== AddMessageListeners null");
   1.221 +        addMessageListenersTest(null, {"name1": false, "nameN": true}, 2);
   1.222 +        next();
   1.223 +      },
   1.224 +      function() {
   1.225 +        ok(true, "== AddMessageListeners new listener, string only");
   1.226 +        addMessageListenersTest("name2", {
   1.227 +          "name1": false,
   1.228 +          "name2": false,
   1.229 +          "nameN": true
   1.230 +        }, 3);
   1.231 +        next();
   1.232 +      },
   1.233 +      function() {
   1.234 +        ok(true, "== AddMessageListeners new listeners, strings array");
   1.235 +        addMessageListenersTest(["name3", "name4"], {
   1.236 +          "name1": false,
   1.237 +          "name2": false,
   1.238 +          "name3": false,
   1.239 +          "name4": false,
   1.240 +          "nameN": true
   1.241 +        }, 5);
   1.242 +        next();
   1.243 +      },
   1.244 +      function() {
   1.245 +        ok(true, "== AddMessageListeners new listeners, objects array");
   1.246 +        addMessageListenersTest([{
   1.247 +          name: "name5",
   1.248 +          weakRef: true
   1.249 +        }, {
   1.250 +          name: "name6",
   1.251 +          weakRef: false
   1.252 +        }], {
   1.253 +          "name1": false,
   1.254 +          "name2": false,
   1.255 +          "name3": false,
   1.256 +          "name4": false,
   1.257 +          "name5": true,
   1.258 +          "name6": false,
   1.259 +          "nameN": true
   1.260 +        }, 7);
   1.261 +        next();
   1.262 +      },
   1.263 +      function() {
   1.264 +        ok(true, "== RemoveMessageListeners, null");
   1.265 +        removeMessageListenersTest(null, {
   1.266 +          "name1": false,
   1.267 +          "name2": false,
   1.268 +          "name3": false,
   1.269 +          "name4": false,
   1.270 +          "name5": true,
   1.271 +          "name6": false,
   1.272 +          "nameN": true
   1.273 +        }, 7);
   1.274 +        next();
   1.275 +      },
   1.276 +      function() {
   1.277 +        ok(true, "== RemoveMessageListeners, one message");
   1.278 +        removeMessageListenersTest("name1", {
   1.279 +          "name2": false,
   1.280 +          "name3": false,
   1.281 +          "name4": false,
   1.282 +          "name5": true,
   1.283 +          "name6": false,
   1.284 +          "nameN": true
   1.285 +        }, 6);
   1.286 +        next();
   1.287 +      },
   1.288 +      function() {
   1.289 +        ok(true, "== RemoveMessageListeners, array of messages");
   1.290 +        removeMessageListenersTest(["name2", "name3"], {
   1.291 +          "name4": false,
   1.292 +          "name5": true,
   1.293 +          "name6": false,
   1.294 +          "nameN": true
   1.295 +        }, 4);
   1.296 +        next();
   1.297 +      },
   1.298 +      function() {
   1.299 +        ok(true, "== RemoveMessageListeners, unknown message");
   1.300 +        removeMessageListenersTest("unknown", {
   1.301 +          "name4": false,
   1.302 +          "name5": true,
   1.303 +          "name6": false,
   1.304 +          "nameN": true
   1.305 +        }, 4);
   1.306 +        next();
   1.307 +      },
   1.308 +      function() {
   1.309 +        try {
   1.310 +          ok(true, "== AddMessageListeners, same message, same kind");
   1.311 +          addMessageListenersTest("name4", {
   1.312 +            "name4": false,
   1.313 +            "name5": true,
   1.314 +            "name6": false,
   1.315 +            "nameN": true
   1.316 +          }, 4);
   1.317 +          next();
   1.318 +        } catch (ex) {
   1.319 +          ok(false, "Unexpected exception " + ex);
   1.320 +        }
   1.321 +      },
   1.322 +      function() {
   1.323 +        ok(true, "== AddMessageListeners, same message, different kind");
   1.324 +        try {
   1.325 +          addMessageListenersTest({name: "name4", weakRef: true}, {
   1.326 +            "name4": true,
   1.327 +            "name5": true,
   1.328 +            "name6": false,
   1.329 +            "nameN": true
   1.330 +          }, 4);
   1.331 +          ok(false, "Should have thrown an exception");
   1.332 +        } catch (ex) {
   1.333 +          ok(true, "Expected exception");
   1.334 +          next();
   1.335 +        }
   1.336 +      },
   1.337 +      function() {
   1.338 +        ok(true, "== Test createRequest()");
   1.339 +        ok(DOMRequest, "DOMRequest object exists");
   1.340 +        var req = dummy.createRequest();
   1.341 +        ok(req instanceof DOMRequest, "Returned a DOMRequest");
   1.342 +        next();
   1.343 +      },
   1.344 +      function() {
   1.345 +        ok(true, "== Test getRequestId(), removeRequest() and getRequest()");
   1.346 +        var req = dummy.createRequest();
   1.347 +        var id = dummy.getRequestId(req);
   1.348 +        is(typeof id, "string", "id is a string");
   1.349 +        var req_ = dummy.getRequest(id);
   1.350 +        is(req, req_, "Got correct request");
   1.351 +        dummy.removeRequest(id);
   1.352 +        req = dummy.getRequest(id);
   1.353 +        is(req, null, "No request");
   1.354 +        next();
   1.355 +      },
   1.356 +      function() {
   1.357 +        ok(true, "== Test createPromise()");
   1.358 +        ok(Promise, "Promise object exists");
   1.359 +        var promise = dummy.createPromise(function(resolve, reject) {
   1.360 +          resolve(true);
   1.361 +        });
   1.362 +        ok(promise instanceof Promise, "Returned a Promise");
   1.363 +        promise.then(next);
   1.364 +      },
   1.365 +      function() {
   1.366 +        ok(true, "== Test getResolver()");
   1.367 +        var id;
   1.368 +        var resolver;
   1.369 +        var promise = dummy.createPromise(function(resolve, reject) {
   1.370 +          var r = { resolve: resolve, reject: reject };
   1.371 +          id = dummy.getPromiseResolverId(r);
   1.372 +          resolver = r;
   1.373 +          ok(typeof id === "string", "id is a string");
   1.374 +          r.resolve(true);
   1.375 +        }).then(function(unused) {
   1.376 +          var r = dummy.getPromiseResolver(id);
   1.377 +          ok(resolver === r, "Get succeeded");
   1.378 +          next();
   1.379 +        });
   1.380 +      },
   1.381 +      function() {
   1.382 +        ok(true, "== Test removeResolver");
   1.383 +        var id;
   1.384 +        var promise = dummy.createPromise(function(resolve, reject) {
   1.385 +          var r = { resolve: resolve, reject: reject };
   1.386 +          id = dummy.getPromiseResolverId(r);
   1.387 +          ok(typeof id === "string", "id is a string");
   1.388 +
   1.389 +          var resolver = dummy.getPromiseResolver(id);
   1.390 +          ok(true, "Got resolver " + JSON.stringify(resolver));
   1.391 +          ok(resolver === r, "Resolver get succeeded");
   1.392 +
   1.393 +          r.resolve(true);
   1.394 +        }).then(function(unused) {
   1.395 +          dummy.removePromiseResolver(id);
   1.396 +          var resolver = dummy.getPromiseResolver(id);
   1.397 +          ok(resolver === undefined, "removeResolver: get failed");
   1.398 +          next();
   1.399 +        });
   1.400 +      },
   1.401 +      function() {
   1.402 +        ok(true, "== Test takeResolver");
   1.403 +        var id;
   1.404 +        var resolver;
   1.405 +        var promise = dummy.createPromise(function(resolve, reject) {
   1.406 +          var r = { resolve: resolve, reject: reject };
   1.407 +          id = dummy.getPromiseResolverId(r);
   1.408 +          resolver = r;
   1.409 +          ok(typeof id === "string", "id is a string");
   1.410 +
   1.411 +          var gotR = dummy.getPromiseResolver(id);
   1.412 +          ok(gotR === r, "resolver get succeeded");
   1.413 +
   1.414 +          r.resolve(true);
   1.415 +        }).then(function(unused) {
   1.416 +          var r = dummy.takePromiseResolver(id);
   1.417 +          ok(resolver === r, "take should succeed");
   1.418 +
   1.419 +          r = dummy.getPromiseResolver(id);
   1.420 +          ok(r === undefined, "takeResolver: get failed");
   1.421 +          next();
   1.422 +        });
   1.423 +      },
   1.424 +      function() {
   1.425 +        ok(true, "== Test window destroyed without messages and without GC");
   1.426 +        checkWindowDestruction({ gc: false }, function(uninitCalled) {
   1.427 +          ok(uninitCalled, "uninit() should have been called");
   1.428 +          next();
   1.429 +        });
   1.430 +      },
   1.431 +      function() {
   1.432 +        ok(true, "== Test window destroyed without messages and with GC");
   1.433 +        checkWindowDestruction({ gc: true }, function(uninitCalled) {
   1.434 +          ok(!uninitCalled, "uninit() should NOT have been called");
   1.435 +          next();
   1.436 +        });
   1.437 +      },
   1.438 +      function() {
   1.439 +        ok(true, "== Test window destroyed with weak messages and without GC");
   1.440 +        checkWindowDestruction({ messages: [{ name: "foo", weakRef: true }],
   1.441 +                                 gc: false }, function(uninitCalled) {
   1.442 +          ok(uninitCalled, "uninit() should have been called");
   1.443 +          next();
   1.444 +        });
   1.445 +      },
   1.446 +      function() {
   1.447 +        ok(true, "== Test window destroyed with weak messages and with GC");
   1.448 +        checkWindowDestruction({ messages: [{ name: "foo", weakRef: true }],
   1.449 +                                 gc: true }, function(uninitCalled) {
   1.450 +          ok(!uninitCalled, "uninit() should NOT have been called");
   1.451 +          next();
   1.452 +        });
   1.453 +      },
   1.454 +      function() {
   1.455 +        ok(true, "== Test window destroyed with strong messages and without GC");
   1.456 +        checkWindowDestruction({ messages: [{ name: "foo", weakRef: false }],
   1.457 +                                 gc: false }, function(uninitCalled) {
   1.458 +          ok(uninitCalled, "uninit() should have been called");
   1.459 +          next();
   1.460 +        });
   1.461 +      },
   1.462 +      function() {
   1.463 +        ok(true, "== Test window destroyed with strong messages and with GC");
   1.464 +        checkWindowDestruction({ messages: [{ name: "foo", weakRef: false }],
   1.465 +                                 gc: true }, function(uninitCalled) {
   1.466 +          ok(uninitCalled, "uninit() should have been called");
   1.467 +          next();
   1.468 +        });
   1.469 +      }
   1.470 +    ];
   1.471 +
   1.472 +    function next() {
   1.473 +      if (!tests.length) {
   1.474 +        SimpleTest.finish();
   1.475 +        return;
   1.476 +      }
   1.477 +
   1.478 +      var test = tests.shift();
   1.479 +      test();
   1.480 +    }
   1.481 +
   1.482 +    function start() {
   1.483 +      SimpleTest.waitForExplicitFinish();
   1.484 +      next();
   1.485 +    }
   1.486 +  ]]>
   1.487 +  </script>
   1.488 +
   1.489 +  <body xmlns="http://www.w3.org/1999/xhtml">
   1.490 +    <p id="display"></p>
   1.491 +    <div id="content" style="display: none"></div>
   1.492 +    <pre id="test"></pre>
   1.493 +  </body>
   1.494 +</window>

mercurial