michael@0: /* michael@0: * Test to ensure that image loading/decoding notifications are always michael@0: * delivered async, and in the order we expect. michael@0: * michael@0: * Must be included from a file that has a uri of the image to test defined in michael@0: * var uri. michael@0: */ michael@0: michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cu = Components.utils; michael@0: const Cr = Components.results; michael@0: michael@0: Cu.import("resource://testing-common/httpd.js"); michael@0: michael@0: var server = new HttpServer(); michael@0: server.registerDirectory("/", do_get_file('')); michael@0: server.registerContentType("sjs", "sjs"); michael@0: server.start(-1); michael@0: michael@0: michael@0: load('image_load_helpers.js'); michael@0: michael@0: var requests = []; michael@0: michael@0: // Return a closure that holds on to the listener from the original michael@0: // imgIRequest, and compares its results to the cloned one. michael@0: function getCloneStopCallback(original_listener) michael@0: { michael@0: return function cloneStop(listener) { michael@0: do_check_eq(original_listener.state, listener.state); michael@0: michael@0: // Sanity check to make sure we didn't accidentally use the same listener michael@0: // twice. michael@0: do_check_neq(original_listener, listener); michael@0: do_test_finished(); michael@0: } michael@0: } michael@0: michael@0: // Make sure that cloned requests get all the same callbacks as the original, michael@0: // but they aren't synchronous right now. michael@0: function checkClone(other_listener, aRequest) michael@0: { michael@0: do_test_pending(); michael@0: michael@0: // For as long as clone notification is synchronous, we can't test the clone state reliably. michael@0: var listener = new ImageListener(null, function(foo, bar) { do_test_finished(); } /*getCloneStopCallback(other_listener)*/); michael@0: listener.synchronous = false; michael@0: var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) michael@0: .createScriptedObserver(listener); michael@0: var clone = aRequest.clone(outer); michael@0: requests.push(clone); michael@0: } michael@0: michael@0: // Ensure that all the callbacks were called on aRequest. michael@0: function checkSizeAndLoad(listener, aRequest) michael@0: { michael@0: do_check_neq(listener.state & SIZE_AVAILABLE, 0); michael@0: do_check_neq(listener.state & LOAD_COMPLETE, 0); michael@0: michael@0: do_test_finished(); michael@0: } michael@0: michael@0: function secondLoadDone(oldlistener, aRequest) michael@0: { michael@0: do_test_pending(); michael@0: michael@0: try { michael@0: var staticrequest = aRequest.getStaticRequest(); michael@0: michael@0: // For as long as clone notification is synchronous, we can't test the michael@0: // clone state reliably. michael@0: var listener = new ImageListener(null, checkSizeAndLoad); michael@0: listener.synchronous = false; michael@0: var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) michael@0: .createScriptedObserver(listener); michael@0: var staticrequestclone = staticrequest.clone(outer); michael@0: requests.push(staticrequestclone); michael@0: } catch(e) { michael@0: // We can't create a static request. Most likely the request we started michael@0: // with didn't load successfully. michael@0: do_test_finished(); michael@0: } michael@0: michael@0: run_loadImageWithChannel_tests(); michael@0: michael@0: do_test_finished(); michael@0: } michael@0: michael@0: // Load the request a second time. This should come from the image cache, and michael@0: // therefore would be at most risk of being served synchronously. michael@0: function checkSecondLoad() michael@0: { michael@0: do_test_pending(); michael@0: michael@0: var listener = new ImageListener(checkClone, secondLoadDone); michael@0: var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) michael@0: .createScriptedObserver(listener); michael@0: requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null)); michael@0: listener.synchronous = false; michael@0: } michael@0: michael@0: function firstLoadDone(oldlistener, aRequest) michael@0: { michael@0: checkSecondLoad(uri); michael@0: michael@0: do_test_finished(); michael@0: } michael@0: michael@0: // Return a closure that allows us to check the stream listener's status when the michael@0: // image starts loading. michael@0: function getChannelLoadImageStartCallback(streamlistener) michael@0: { michael@0: return function channelLoadStart(imglistener, aRequest) { michael@0: // We must not have received all status before we get this start callback. michael@0: // If we have, we've broken people's expectations by delaying events from a michael@0: // channel we were given. michael@0: do_check_eq(streamlistener.requestStatus & STOP_REQUEST, 0); michael@0: michael@0: checkClone(imglistener, aRequest); michael@0: } michael@0: } michael@0: michael@0: // Return a closure that allows us to check the stream listener's status when the michael@0: // image finishes loading. michael@0: function getChannelLoadImageStopCallback(streamlistener, next) michael@0: { michael@0: return function channelLoadStop(imglistener, aRequest) { michael@0: michael@0: next(); michael@0: michael@0: do_test_finished(); michael@0: } michael@0: } michael@0: michael@0: // Load the request a second time. This should come from the image cache, and michael@0: // therefore would be at most risk of being served synchronously. michael@0: function checkSecondChannelLoad() michael@0: { michael@0: do_test_pending(); michael@0: michael@0: var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); michael@0: var channel = ioService.newChannelFromURI(uri); michael@0: var channellistener = new ChannelListener(); michael@0: channel.asyncOpen(channellistener, null); michael@0: michael@0: var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener), michael@0: getChannelLoadImageStopCallback(channellistener, michael@0: all_done_callback)); michael@0: var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) michael@0: .createScriptedObserver(listener); michael@0: var outlistener = {}; michael@0: requests.push(gCurrentLoader.loadImageWithChannelXPCOM(channel, outer, null, outlistener)); michael@0: channellistener.outputListener = outlistener.value; michael@0: michael@0: listener.synchronous = false; michael@0: } michael@0: michael@0: function run_loadImageWithChannel_tests() michael@0: { michael@0: // To ensure we're testing what we expect to, create a new loader and cache. michael@0: gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); michael@0: michael@0: do_test_pending(); michael@0: michael@0: var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); michael@0: var channel = ioService.newChannelFromURI(uri); michael@0: var channellistener = new ChannelListener(); michael@0: channel.asyncOpen(channellistener, null); michael@0: michael@0: var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener), michael@0: getChannelLoadImageStopCallback(channellistener, michael@0: checkSecondChannelLoad)); michael@0: var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) michael@0: .createScriptedObserver(listener); michael@0: var outlistener = {}; michael@0: requests.push(gCurrentLoader.loadImageWithChannelXPCOM(channel, outer, null, outlistener)); michael@0: channellistener.outputListener = outlistener.value; michael@0: michael@0: listener.synchronous = false; michael@0: } michael@0: michael@0: function all_done_callback() michael@0: { michael@0: server.stop(function() { do_test_finished(); }); michael@0: } michael@0: michael@0: function startImageCallback(otherCb) michael@0: { michael@0: return function(listener, request) michael@0: { michael@0: // Make sure we can load the same image immediately out of the cache. michael@0: do_test_pending(); michael@0: var listener2 = new ImageListener(null, function(foo, bar) { do_test_finished(); }); michael@0: var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) michael@0: .createScriptedObserver(listener2); michael@0: requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null)); michael@0: listener2.synchronous = false; michael@0: michael@0: // Now that we've started another load, chain to the callback. michael@0: otherCb(listener, request); michael@0: } michael@0: } michael@0: michael@0: var gCurrentLoader; michael@0: michael@0: function cleanup() michael@0: { michael@0: for (var i = 0; i < requests.length; ++i) { michael@0: requests[i].cancelAndForgetObserver(0); michael@0: } michael@0: } michael@0: michael@0: function run_test() michael@0: { michael@0: do_register_cleanup(cleanup); michael@0: michael@0: gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); michael@0: michael@0: do_test_pending(); michael@0: var listener = new ImageListener(startImageCallback(checkClone), firstLoadDone); michael@0: var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) michael@0: .createScriptedObserver(listener); michael@0: var req = gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null); michael@0: requests.push(req); michael@0: michael@0: // Ensure that we don't cause any mayhem when we lock an image. michael@0: req.lockImage(); michael@0: michael@0: listener.synchronous = false; michael@0: }