diff options
Diffstat (limited to 'image/test/unit/async_load_tests.js')
-rw-r--r-- | image/test/unit/async_load_tests.js | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/image/test/unit/async_load_tests.js b/image/test/unit/async_load_tests.js new file mode 100644 index 0000000000..f19e146314 --- /dev/null +++ b/image/test/unit/async_load_tests.js @@ -0,0 +1,302 @@ +/* + * Test to ensure that image loading/decoding notifications are always + * delivered async, and in the order we expect. + * + * Must be included from a file that has a uri of the image to test defined in + * var uri. + */ +/* import-globals-from image_load_helpers.js */ + +const { HttpServer } = ChromeUtils.importESModule( + "resource://testing-common/httpd.sys.mjs" +); +const { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs" +); +const ReferrerInfo = Components.Constructor( + "@mozilla.org/referrer-info;1", + "nsIReferrerInfo", + "init" +); + +var server = new HttpServer(); +server.registerDirectory("/", do_get_file("")); +server.registerContentType("sjs", "sjs"); +server.start(-1); + +load("image_load_helpers.js"); + +var requests = []; +/* global uri */ + +// Return a closure that holds on to the listener from the original +// imgIRequest, and compares its results to the cloned one. +function getCloneStopCallback(original_listener) { + return function cloneStop(listener) { + Assert.equal(original_listener.state, listener.state); + + // Sanity check to make sure we didn't accidentally use the same listener + // twice. + Assert.notEqual(original_listener, listener); + do_test_finished(); + }; +} + +// Make sure that cloned requests get all the same callbacks as the original, +// but they aren't synchronous right now. +function checkClone(other_listener, aRequest) { + do_test_pending(); + + // For as long as clone notification is synchronous, we can't test the clone state reliably. + var listener = new ImageListener( + null, + function (foo, bar) { + do_test_finished(); + } /* getCloneStopCallback(other_listener)*/ + ); + listener.synchronous = false; + var outer = Cc["@mozilla.org/image/tools;1"] + .getService(Ci.imgITools) + .createScriptedObserver(listener); + var clone = aRequest.clone(outer); + requests.push({ request: clone, locked: false }); +} + +// Ensure that all the callbacks were called on aRequest. +function checkSizeAndLoad(listener, aRequest) { + Assert.notEqual(listener.state & SIZE_AVAILABLE, 0); + Assert.notEqual(listener.state & LOAD_COMPLETE, 0); + + do_test_finished(); +} + +function secondLoadDone(oldlistener, aRequest) { + do_test_pending(); + + try { + var staticrequest = aRequest.getStaticRequest(); + + // For as long as clone notification is synchronous, we can't test the + // clone state reliably. + var listener = new ImageListener(null, checkSizeAndLoad); + listener.synchronous = false; + var outer = Cc["@mozilla.org/image/tools;1"] + .getService(Ci.imgITools) + .createScriptedObserver(listener); + var staticrequestclone = staticrequest.clone(outer); + requests.push({ request: staticrequestclone, locked: false }); + } catch (e) { + // We can't create a static request. Most likely the request we started + // with didn't load successfully. + do_test_finished(); + } + + run_loadImageWithChannel_tests(); + + do_test_finished(); +} + +// Load the request a second time. This should come from the image cache, and +// therefore would be at most risk of being served synchronously. +function checkSecondLoad() { + do_test_pending(); + + var listener = new ImageListener(checkClone, secondLoadDone); + var outer = Cc["@mozilla.org/image/tools;1"] + .getService(Ci.imgITools) + .createScriptedObserver(listener); + var referrerInfo = new ReferrerInfo( + Ci.nsIReferrerInfo.NO_REFERRER_WHEN_DOWNGRADE, + true, + null + ); + requests.push({ + request: gCurrentLoader.loadImageXPCOM( + uri, + null, + referrerInfo, + null, + null, + outer, + null, + 0, + null + ), + locked: false, + }); + listener.synchronous = false; +} + +function firstLoadDone(oldlistener, aRequest) { + checkSecondLoad(uri); + + do_test_finished(); +} + +// Return a closure that allows us to check the stream listener's status when the +// image finishes loading. +function getChannelLoadImageStopCallback(streamlistener, next) { + return function channelLoadStop(imglistener, aRequest) { + next(); + + do_test_finished(); + }; +} + +// Load the request a second time. This should come from the image cache, and +// therefore would be at most risk of being served synchronously. +function checkSecondChannelLoad() { + do_test_pending(); + var channel = NetUtil.newChannel({ uri, loadUsingSystemPrincipal: true }); + var channellistener = new ChannelListener(); + channel.asyncOpen(channellistener); + + var listener = new ImageListener( + null, + getChannelLoadImageStopCallback(channellistener, all_done_callback) + ); + var outer = Cc["@mozilla.org/image/tools;1"] + .getService(Ci.imgITools) + .createScriptedObserver(listener); + var outlistener = {}; + requests.push({ + request: gCurrentLoader.loadImageWithChannelXPCOM( + channel, + outer, + null, + outlistener + ), + locked: false, + }); + channellistener.outputListener = outlistener.value; + + listener.synchronous = false; +} + +function run_loadImageWithChannel_tests() { + // To ensure we're testing what we expect to, create a new loader and cache. + gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance( + Ci.imgILoader + ); + + do_test_pending(); + var channel = NetUtil.newChannel({ uri, loadUsingSystemPrincipal: true }); + var channellistener = new ChannelListener(); + channel.asyncOpen(channellistener); + + var listener = new ImageListener( + null, + getChannelLoadImageStopCallback(channellistener, checkSecondChannelLoad) + ); + var outer = Cc["@mozilla.org/image/tools;1"] + .getService(Ci.imgITools) + .createScriptedObserver(listener); + var outlistener = {}; + requests.push({ + request: gCurrentLoader.loadImageWithChannelXPCOM( + channel, + outer, + null, + outlistener + ), + locked: false, + }); + channellistener.outputListener = outlistener.value; + + listener.synchronous = false; +} + +function all_done_callback() { + server.stop(function () { + do_test_finished(); + }); +} + +function startImageCallback(otherCb) { + return function (listener, request) { + // Make sure we can load the same image immediately out of the cache. + do_test_pending(); + var listener2 = new ImageListener(null, function (foo, bar) { + do_test_finished(); + }); + var outer = Cc["@mozilla.org/image/tools;1"] + .getService(Ci.imgITools) + .createScriptedObserver(listener2); + var referrerInfo = new ReferrerInfo( + Ci.nsIReferrerInfo.NO_REFERRER_WHEN_DOWNGRADE, + true, + null + ); + requests.push({ + request: gCurrentLoader.loadImageXPCOM( + uri, + null, + referrerInfo, + null, + null, + outer, + null, + 0, + null + ), + locked: false, + }); + listener2.synchronous = false; + + // Now that we've started another load, chain to the callback. + otherCb(listener, request); + }; +} + +var gCurrentLoader; + +function cleanup() { + for (let { request, locked } of requests) { + if (locked) { + try { + request.unlockImage(); + } catch (e) {} + } + request.cancelAndForgetObserver(0); + } +} + +function run_test() { + registerCleanupFunction(cleanup); + + gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance( + Ci.imgILoader + ); + + do_test_pending(); + var listener = new ImageListener( + startImageCallback(checkClone), + firstLoadDone + ); + var outer = Cc["@mozilla.org/image/tools;1"] + .getService(Ci.imgITools) + .createScriptedObserver(listener); + var referrerInfo = new ReferrerInfo( + Ci.nsIReferrerInfo.NO_REFERRER_WHEN_DOWNGRADE, + true, + null + ); + var req = gCurrentLoader.loadImageXPCOM( + uri, + null, + referrerInfo, + null, + null, + outer, + null, + 0, + null + ); + + // Ensure that we don't cause any mayhem when we lock an image. + req.lockImage(); + + requests.push({ request: req, locked: true }); + + listener.synchronous = false; +} |