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 }