tor-browser

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

browser_resources_client_caching.js (11143B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // Test the cache mechanism of the ResourceCommand.
      7 
      8 const TEST_URI = "data:text/html;charset=utf-8,<!DOCTYPE html>Cache Test";
      9 
     10 add_task(async function () {
     11  info("Test whether multiple listener can get same cached resources");
     12 
     13  const tab = await addTab(TEST_URI);
     14 
     15  const { client, resourceCommand, targetCommand } =
     16    await initResourceCommand(tab);
     17 
     18  info("Add messages as existing resources");
     19  const messages = ["a", "b", "c"];
     20  await logMessages(tab.linkedBrowser, messages);
     21 
     22  info("Register first listener");
     23  const cachedResources1 = [];
     24  await resourceCommand.watchResources(
     25    [resourceCommand.TYPES.CONSOLE_MESSAGE],
     26    {
     27      onAvailable(resources, { areExistingResources }) {
     28        ok(areExistingResources, "All resources are already existing ones");
     29        cachedResources1.push(...resources);
     30      },
     31    }
     32  );
     33 
     34  info("Register second listener");
     35  const cachedResources2 = [];
     36  await resourceCommand.watchResources(
     37    [resourceCommand.TYPES.CONSOLE_MESSAGE],
     38    {
     39      onAvailable(resources, { areExistingResources }) {
     40        ok(areExistingResources, "All resources are already existing ones");
     41        cachedResources2.push(...resources);
     42      },
     43    }
     44  );
     45 
     46  assertContents(cachedResources1, messages);
     47  assertResources(cachedResources2, cachedResources1);
     48 
     49  targetCommand.destroy();
     50  await client.close();
     51 });
     52 
     53 add_task(async function () {
     54  info(
     55    "Test whether the cache is reflecting existing resources and additional resources"
     56  );
     57 
     58  const tab = await addTab(TEST_URI);
     59 
     60  const { client, resourceCommand, targetCommand } =
     61    await initResourceCommand(tab);
     62 
     63  info("Add messages as existing resources");
     64  const existingMessages = ["a", "b", "c"];
     65  await logMessages(tab.linkedBrowser, existingMessages);
     66 
     67  info("Register first listener to get all available resources");
     68  const availableResources = [];
     69  // We first get notified about existing resources
     70  let shouldBeExistingResources = true;
     71  await resourceCommand.watchResources(
     72    [resourceCommand.TYPES.CONSOLE_MESSAGE],
     73    {
     74      onAvailable(resources, { areExistingResources }) {
     75        is(
     76          areExistingResources,
     77          shouldBeExistingResources,
     78          "areExistingResources flag is correct"
     79        );
     80        availableResources.push(...resources);
     81      },
     82    }
     83  );
     84  // Then, we are notified about, new, live ones
     85  shouldBeExistingResources = false;
     86 
     87  info("Add messages as additional resources");
     88  const additionalMessages = ["d", "e"];
     89  await logMessages(tab.linkedBrowser, additionalMessages);
     90 
     91  info("Wait until onAvailable is called expected times");
     92  const allMessages = [...existingMessages, ...additionalMessages];
     93  await waitUntil(() => availableResources.length === allMessages.length);
     94 
     95  info("Register second listener to get the cached resources");
     96  const cachedResources = [];
     97  await resourceCommand.watchResources(
     98    [resourceCommand.TYPES.CONSOLE_MESSAGE],
     99    {
    100      onAvailable(resources, { areExistingResources }) {
    101        ok(areExistingResources, "All resources are already existing ones");
    102        cachedResources.push(...resources);
    103      },
    104    }
    105  );
    106 
    107  assertContents(availableResources, allMessages);
    108  assertResources(cachedResources, availableResources);
    109 
    110  targetCommand.destroy();
    111  await client.close();
    112 });
    113 
    114 add_task(async function () {
    115  info("Test whether the cache is cleared when navigation");
    116 
    117  const tab = await addTab(TEST_URI);
    118 
    119  const { client, resourceCommand, targetCommand } =
    120    await initResourceCommand(tab);
    121 
    122  info("Add messages as existing resources");
    123  const existingMessages = ["a", "b", "c"];
    124  await logMessages(tab.linkedBrowser, existingMessages);
    125 
    126  info("Register first listener");
    127  await resourceCommand.watchResources(
    128    [resourceCommand.TYPES.CONSOLE_MESSAGE],
    129    {
    130      onAvailable: () => {},
    131    }
    132  );
    133 
    134  info("Reload the page");
    135  await BrowserTestUtils.reloadTab(tab);
    136 
    137  info("Register second listener");
    138  const cachedResources = [];
    139  await resourceCommand.watchResources(
    140    [resourceCommand.TYPES.CONSOLE_MESSAGE],
    141    {
    142      onAvailable: resources => cachedResources.push(...resources),
    143    }
    144  );
    145 
    146  is(cachedResources.length, 0, "The cache in ResourceCommand is cleared");
    147 
    148  targetCommand.destroy();
    149  await client.close();
    150 });
    151 
    152 add_task(async function () {
    153  info("Test with multiple resource types");
    154 
    155  const tab = await addTab(TEST_URI);
    156 
    157  const { client, resourceCommand, targetCommand } =
    158    await initResourceCommand(tab);
    159 
    160  info("Register first listener to get all available resources");
    161  const availableResources = [];
    162  await resourceCommand.watchResources(
    163    [
    164      resourceCommand.TYPES.CONSOLE_MESSAGE,
    165      resourceCommand.TYPES.ERROR_MESSAGE,
    166    ],
    167    {
    168      onAvailable: resources => availableResources.push(...resources),
    169    }
    170  );
    171 
    172  info("Add messages as console message");
    173  const consoleMessages1 = ["a", "b", "c"];
    174  await logMessages(tab.linkedBrowser, consoleMessages1);
    175 
    176  info("Add message as error message");
    177  const errorMessages = ["document.doTheImpossible();"];
    178  await triggerErrors(tab.linkedBrowser, errorMessages);
    179 
    180  info("Add messages as console message again");
    181  const consoleMessages2 = ["d", "e"];
    182  await logMessages(tab.linkedBrowser, consoleMessages2);
    183 
    184  info("Wait until the getting all available resources");
    185  const totalResourceCount =
    186    consoleMessages1.length + errorMessages.length + consoleMessages2.length;
    187  await waitUntil(() => {
    188    return availableResources.length === totalResourceCount;
    189  });
    190 
    191  info("Register listener to get the cached resources");
    192  const cachedResources = [];
    193  await resourceCommand.watchResources(
    194    [
    195      resourceCommand.TYPES.CONSOLE_MESSAGE,
    196      resourceCommand.TYPES.ERROR_MESSAGE,
    197    ],
    198    {
    199      onAvailable: resources => cachedResources.push(...resources),
    200    }
    201  );
    202 
    203  assertResources(cachedResources, availableResources);
    204 
    205  targetCommand.destroy();
    206  await client.close();
    207 });
    208 
    209 add_task(async function () {
    210  info("Test multiple listeners with/without ignoreExistingResources");
    211  await testIgnoreExistingResources(true);
    212  await testIgnoreExistingResources(false);
    213 });
    214 
    215 async function testIgnoreExistingResources(isFirstListenerIgnoreExisting) {
    216  const tab = await addTab(TEST_URI);
    217 
    218  const { client, resourceCommand, targetCommand } =
    219    await initResourceCommand(tab);
    220 
    221  info("Add messages as existing resources");
    222  const existingMessages = ["a", "b", "c"];
    223  await logMessages(tab.linkedBrowser, existingMessages);
    224 
    225  info("Register first listener");
    226  const cachedResources1 = [];
    227  await resourceCommand.watchResources(
    228    [resourceCommand.TYPES.CONSOLE_MESSAGE],
    229    {
    230      onAvailable: resources => cachedResources1.push(...resources),
    231      ignoreExistingResources: isFirstListenerIgnoreExisting,
    232    }
    233  );
    234 
    235  info("Register second listener");
    236  const cachedResources2 = [];
    237  await resourceCommand.watchResources(
    238    [resourceCommand.TYPES.CONSOLE_MESSAGE],
    239    {
    240      onAvailable: resources => cachedResources2.push(...resources),
    241      ignoreExistingResources: !isFirstListenerIgnoreExisting,
    242    }
    243  );
    244 
    245  const cachedResourcesWithFlag = isFirstListenerIgnoreExisting
    246    ? cachedResources1
    247    : cachedResources2;
    248  const cachedResourcesWithoutFlag = isFirstListenerIgnoreExisting
    249    ? cachedResources2
    250    : cachedResources1;
    251 
    252  info("Check the existing resources both listeners got");
    253  assertContents(cachedResourcesWithFlag, []);
    254  assertContents(cachedResourcesWithoutFlag, existingMessages);
    255 
    256  info("Add messages as additional resources");
    257  const additionalMessages = ["d", "e"];
    258  await logMessages(tab.linkedBrowser, additionalMessages);
    259 
    260  info("Wait until onAvailable is called expected times");
    261  await waitUntil(
    262    () => cachedResourcesWithFlag.length === additionalMessages.length
    263  );
    264  const allMessages = [...existingMessages, ...additionalMessages];
    265  await waitUntil(
    266    () => cachedResourcesWithoutFlag.length === allMessages.length
    267  );
    268 
    269  info("Check the resources after adding messages");
    270  assertContents(cachedResourcesWithFlag, additionalMessages);
    271  assertContents(cachedResourcesWithoutFlag, allMessages);
    272 
    273  targetCommand.destroy();
    274  await client.close();
    275 }
    276 
    277 add_task(async function () {
    278  info("Test that onAvailable is not called with an empty resources array");
    279 
    280  const tab = await addTab(TEST_URI);
    281 
    282  const { client, resourceCommand, targetCommand } =
    283    await initResourceCommand(tab);
    284 
    285  info("Register first listener to get all available resources");
    286  const availableResources = [];
    287  let onAvailableCallCount = 0;
    288  const onAvailable = resources => {
    289    ok(
    290      !!resources.length,
    291      "onAvailable is called with a non empty resources array"
    292    );
    293    availableResources.push(...resources);
    294    onAvailableCallCount++;
    295  };
    296 
    297  await resourceCommand.watchResources(
    298    [resourceCommand.TYPES.CONSOLE_MESSAGE],
    299    { onAvailable }
    300  );
    301  is(availableResources.length, 0, "availableResources array is empty");
    302  is(onAvailableCallCount, 0, "onAvailable was never called");
    303 
    304  info("Add messages as console message");
    305  await logMessages(tab.linkedBrowser, ["expected message"]);
    306 
    307  await waitUntil(() => availableResources.length === 1);
    308  is(availableResources.length, 1, "availableResources array has one item");
    309  is(onAvailableCallCount, 1, "onAvailable was called only once");
    310  is(
    311    availableResources[0].arguments[0],
    312    "expected message",
    313    "onAvailable was called with the expected resource"
    314  );
    315 
    316  resourceCommand.unwatchResources([resourceCommand.TYPES.CONSOLE_MESSAGE], {
    317    onAvailable,
    318  });
    319  targetCommand.destroy();
    320  await client.close();
    321 });
    322 
    323 function assertContents(resources, expectedMessages) {
    324  is(
    325    resources.length,
    326    expectedMessages.length,
    327    "Number of the resources is correct"
    328  );
    329 
    330  for (let i = 0; i < expectedMessages.length; i++) {
    331    const resource = resources[i];
    332    const message = resource.arguments[0];
    333    const expectedMessage = expectedMessages[i];
    334    is(message, expectedMessage, `The ${i}th content is correct`);
    335  }
    336 }
    337 
    338 function assertResources(resources, expectedResources) {
    339  is(
    340    resources.length,
    341    expectedResources.length,
    342    "Number of the resources is correct"
    343  );
    344 
    345  for (let i = 0; i < resources.length; i++) {
    346    const resource = resources[i];
    347    const expectedResource = expectedResources[i];
    348    Assert.strictEqual(
    349      resource,
    350      expectedResource,
    351      `The ${i}th resource is correct`
    352    );
    353  }
    354 }
    355 
    356 function logMessages(browser, messages) {
    357  return ContentTask.spawn(browser, { messages }, args => {
    358    for (const message of args.messages) {
    359      content.console.log(message);
    360    }
    361  });
    362 }
    363 
    364 async function triggerErrors(browser, errorScripts) {
    365  for (const errorScript of errorScripts) {
    366    await ContentTask.spawn(browser, errorScript, expr => {
    367      const document = content.document;
    368      const container = document.createElement("script");
    369      document.body.appendChild(container);
    370      container.textContent = expr;
    371      container.remove();
    372    });
    373  }
    374 }