tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

async_load_tests.js (7818B)


      1 /*
      2 * Test to ensure that image loading/decoding notifications are always
      3 * delivered async, and in the order we expect.
      4 *
      5 * Must be included from a file that has a uri of the image to test defined in
      6 * var uri.
      7 */
      8 /* import-globals-from image_load_helpers.js */
      9 
     10 const { HttpServer } = ChromeUtils.importESModule(
     11  "resource://testing-common/httpd.sys.mjs"
     12 );
     13 const { NetUtil } = ChromeUtils.importESModule(
     14  "resource://gre/modules/NetUtil.sys.mjs"
     15 );
     16 const ReferrerInfo = Components.Constructor(
     17  "@mozilla.org/referrer-info;1",
     18  "nsIReferrerInfo",
     19  "init"
     20 );
     21 
     22 var server = new HttpServer();
     23 server.registerDirectory("/", do_get_file(""));
     24 server.registerContentType("sjs", "sjs");
     25 server.start(-1);
     26 
     27 load("image_load_helpers.js");
     28 
     29 var requests = [];
     30 /* global uri */
     31 
     32 // Return a closure that holds on to the listener from the original
     33 // imgIRequest, and compares its results to the cloned one.
     34 function getCloneStopCallback(original_listener) {
     35  return function cloneStop(listener) {
     36    Assert.equal(original_listener.state, listener.state);
     37 
     38    // Sanity check to make sure we didn't accidentally use the same listener
     39    // twice.
     40    Assert.notEqual(original_listener, listener);
     41    do_test_finished();
     42  };
     43 }
     44 
     45 // Make sure that cloned requests get all the same callbacks as the original,
     46 // but they aren't synchronous right now.
     47 function checkClone(other_listener, aRequest) {
     48  do_test_pending();
     49 
     50  // For as long as clone notification is synchronous, we can't test the clone state reliably.
     51  var listener = new ImageListener(
     52    null,
     53    function () {
     54      do_test_finished();
     55    } /* getCloneStopCallback(other_listener)*/
     56  );
     57  listener.synchronous = false;
     58  var outer = Cc["@mozilla.org/image/tools;1"]
     59    .getService(Ci.imgITools)
     60    .createScriptedObserver(listener);
     61  var clone = aRequest.clone(outer);
     62  requests.push({ request: clone, locked: false });
     63 }
     64 
     65 // Ensure that all the callbacks were called on aRequest.
     66 function checkSizeAndLoad(listener) {
     67  Assert.notEqual(listener.state & SIZE_AVAILABLE, 0);
     68  Assert.notEqual(listener.state & LOAD_COMPLETE, 0);
     69 
     70  do_test_finished();
     71 }
     72 
     73 function secondLoadDone(oldlistener, aRequest) {
     74  do_test_pending();
     75 
     76  try {
     77    var staticrequest = aRequest.getStaticRequest();
     78 
     79    // For as long as clone notification is synchronous, we can't test the
     80    // clone state reliably.
     81    var listener = new ImageListener(null, checkSizeAndLoad);
     82    listener.synchronous = false;
     83    var outer = Cc["@mozilla.org/image/tools;1"]
     84      .getService(Ci.imgITools)
     85      .createScriptedObserver(listener);
     86    var staticrequestclone = staticrequest.clone(outer);
     87    requests.push({ request: staticrequestclone, locked: false });
     88  } catch (e) {
     89    // We can't create a static request. Most likely the request we started
     90    // with didn't load successfully.
     91    do_test_finished();
     92  }
     93 
     94  run_loadImageWithChannel_tests();
     95 
     96  do_test_finished();
     97 }
     98 
     99 // Load the request a second time. This should come from the image cache, and
    100 // therefore would be at most risk of being served synchronously.
    101 function checkSecondLoad() {
    102  do_test_pending();
    103 
    104  var listener = new ImageListener(checkClone, secondLoadDone);
    105  var outer = Cc["@mozilla.org/image/tools;1"]
    106    .getService(Ci.imgITools)
    107    .createScriptedObserver(listener);
    108  var referrerInfo = new ReferrerInfo(
    109    Ci.nsIReferrerInfo.NO_REFERRER_WHEN_DOWNGRADE,
    110    true,
    111    null
    112  );
    113  requests.push({
    114    request: gCurrentLoader.loadImageXPCOM(
    115      uri,
    116      null,
    117      referrerInfo,
    118      null,
    119      null,
    120      outer,
    121      null,
    122      0,
    123      null
    124    ),
    125    locked: false,
    126  });
    127  listener.synchronous = false;
    128 }
    129 
    130 function firstLoadDone() {
    131  checkSecondLoad(uri);
    132 
    133  do_test_finished();
    134 }
    135 
    136 // Return a closure that allows us to check the stream listener's status when the
    137 // image finishes loading.
    138 function getChannelLoadImageStopCallback(streamlistener, next) {
    139  return function channelLoadStop() {
    140    next();
    141 
    142    do_test_finished();
    143  };
    144 }
    145 
    146 // Load the request a second time. This should come from the image cache, and
    147 // therefore would be at most risk of being served synchronously.
    148 function checkSecondChannelLoad() {
    149  do_test_pending();
    150  var channel = NetUtil.newChannel({ uri, loadUsingSystemPrincipal: true });
    151  var channellistener = new ChannelListener();
    152  channel.asyncOpen(channellistener);
    153 
    154  var listener = new ImageListener(
    155    null,
    156    getChannelLoadImageStopCallback(channellistener, all_done_callback)
    157  );
    158  var outer = Cc["@mozilla.org/image/tools;1"]
    159    .getService(Ci.imgITools)
    160    .createScriptedObserver(listener);
    161  var outlistener = {};
    162  requests.push({
    163    request: gCurrentLoader.loadImageWithChannelXPCOM(
    164      channel,
    165      outer,
    166      null,
    167      outlistener
    168    ),
    169    locked: false,
    170  });
    171  channellistener.outputListener = outlistener.value;
    172 
    173  listener.synchronous = false;
    174 }
    175 
    176 function run_loadImageWithChannel_tests() {
    177  // To ensure we're testing what we expect to, create a new loader and cache.
    178  gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(
    179    Ci.imgILoader
    180  );
    181 
    182  do_test_pending();
    183  var channel = NetUtil.newChannel({ uri, loadUsingSystemPrincipal: true });
    184  var channellistener = new ChannelListener();
    185  channel.asyncOpen(channellistener);
    186 
    187  var listener = new ImageListener(
    188    null,
    189    getChannelLoadImageStopCallback(channellistener, checkSecondChannelLoad)
    190  );
    191  var outer = Cc["@mozilla.org/image/tools;1"]
    192    .getService(Ci.imgITools)
    193    .createScriptedObserver(listener);
    194  var outlistener = {};
    195  requests.push({
    196    request: gCurrentLoader.loadImageWithChannelXPCOM(
    197      channel,
    198      outer,
    199      null,
    200      outlistener
    201    ),
    202    locked: false,
    203  });
    204  channellistener.outputListener = outlistener.value;
    205 
    206  listener.synchronous = false;
    207 }
    208 
    209 function all_done_callback() {
    210  server.stop(function () {
    211    do_test_finished();
    212  });
    213 }
    214 
    215 function startImageCallback(otherCb) {
    216  return function (listener, request) {
    217    // Make sure we can load the same image immediately out of the cache.
    218    do_test_pending();
    219    var listener2 = new ImageListener(null, function () {
    220      do_test_finished();
    221    });
    222    var outer = Cc["@mozilla.org/image/tools;1"]
    223      .getService(Ci.imgITools)
    224      .createScriptedObserver(listener2);
    225    var referrerInfo = new ReferrerInfo(
    226      Ci.nsIReferrerInfo.NO_REFERRER_WHEN_DOWNGRADE,
    227      true,
    228      null
    229    );
    230    requests.push({
    231      request: gCurrentLoader.loadImageXPCOM(
    232        uri,
    233        null,
    234        referrerInfo,
    235        null,
    236        null,
    237        outer,
    238        null,
    239        0,
    240        null
    241      ),
    242      locked: false,
    243    });
    244    listener2.synchronous = false;
    245 
    246    // Now that we've started another load, chain to the callback.
    247    otherCb(listener, request);
    248  };
    249 }
    250 
    251 var gCurrentLoader;
    252 
    253 function cleanup() {
    254  for (let { request, locked } of requests) {
    255    if (locked) {
    256      try {
    257        request.unlockImage();
    258      } catch (e) {}
    259    }
    260    request.cancelAndForgetObserver(0);
    261  }
    262 }
    263 
    264 function run_test() {
    265  registerCleanupFunction(cleanup);
    266 
    267  gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(
    268    Ci.imgILoader
    269  );
    270 
    271  do_test_pending();
    272  var listener = new ImageListener(
    273    startImageCallback(checkClone),
    274    firstLoadDone
    275  );
    276  var outer = Cc["@mozilla.org/image/tools;1"]
    277    .getService(Ci.imgITools)
    278    .createScriptedObserver(listener);
    279  var referrerInfo = new ReferrerInfo(
    280    Ci.nsIReferrerInfo.NO_REFERRER_WHEN_DOWNGRADE,
    281    true,
    282    null
    283  );
    284  var req = gCurrentLoader.loadImageXPCOM(
    285    uri,
    286    null,
    287    referrerInfo,
    288    null,
    289    null,
    290    outer,
    291    null,
    292    0,
    293    null
    294  );
    295 
    296  // Ensure that we don't cause any mayhem when we lock an image.
    297  req.lockImage();
    298 
    299  requests.push({ request: req, locked: true });
    300 
    301  listener.synchronous = false;
    302 }