browser_resources_network_events_cache.js (8136B)
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 ResourceCommand API internal cache / ignoreExistingResources around NETWORK_EVENT 7 8 const ResourceCommand = require("resource://devtools/shared/commands/resource/resource-command.js"); 9 10 const EXAMPLE_DOMAIN = "https://example.com/"; 11 const TEST_URI = `${URL_ROOT_SSL}network_document.html`; 12 13 add_task(async function () { 14 info("Test basic NETWORK_EVENT resources against ResourceCommand cache"); 15 await testNetworkEventResourcesWithExistingResources(); 16 await testNetworkEventResourcesWithoutExistingResources(); 17 }); 18 19 async function testNetworkEventResourcesWithExistingResources() { 20 info(`Tests for network event resources with the existing resources`); 21 await testNetworkEventResourcesWithCachedRequest({ 22 ignoreExistingResources: false, 23 // 1 available event fired, for the existing resource in the cache. 24 // 1 available event fired, when live request is created. 25 expectedResourcesOnAvailable: { 26 [`${EXAMPLE_DOMAIN}cached_post.html`]: { 27 resourceType: ResourceCommand.TYPES.NETWORK_EVENT, 28 method: "POST", 29 isNavigationRequest: false, 30 }, 31 [`${EXAMPLE_DOMAIN}live_get.html`]: { 32 resourceType: ResourceCommand.TYPES.NETWORK_EVENT, 33 method: "GET", 34 isNavigationRequest: false, 35 }, 36 }, 37 // 2 update events fired, when live request is updated. 38 expectedResourcesOnUpdated: { 39 [`${EXAMPLE_DOMAIN}live_get.html`]: { 40 resourceType: ResourceCommand.TYPES.NETWORK_EVENT, 41 method: "GET", 42 }, 43 }, 44 }); 45 } 46 47 async function testNetworkEventResourcesWithoutExistingResources() { 48 info(`Tests for network event resources without the existing resources`); 49 await testNetworkEventResourcesWithCachedRequest({ 50 ignoreExistingResources: true, 51 // 1 available event fired, when live request is created. 52 expectedResourcesOnAvailable: { 53 [`${EXAMPLE_DOMAIN}live_get.html`]: { 54 resourceType: ResourceCommand.TYPES.NETWORK_EVENT, 55 method: "GET", 56 isNavigationRequest: false, 57 }, 58 }, 59 // 2 update events fired, when live request is updated. 60 expectedResourcesOnUpdated: { 61 [`${EXAMPLE_DOMAIN}live_get.html`]: { 62 resourceType: ResourceCommand.TYPES.NETWORK_EVENT, 63 method: "GET", 64 }, 65 }, 66 }); 67 } 68 69 /** 70 * This test helper is slightly complex as we workaround the fact 71 * that the server is not able to record network requests done in the past. 72 * Because of that we have to start observer requests via ResourceCommand.watchResources 73 * before doing a request, and before doing the actual call to watchResources 74 * we want to assert the behavior of. 75 */ 76 async function testNetworkEventResourcesWithCachedRequest(options) { 77 const tab = await addTab(TEST_URI); 78 const commands = await CommandsFactory.forTab(tab); 79 await commands.targetCommand.startListening(); 80 81 const { resourceCommand } = commands; 82 83 info( 84 `Trigger some network requests *before* calling ResourceCommand.watchResources 85 in order to assert the behavior of already existing network events.` 86 ); 87 88 // Register a first empty listener in order to ensure populating ResourceCommand 89 // internal cache of NETWORK_EVENT's. We can't retrieve past network requests 90 // when calling the server's `watchResources`. 91 let resolveCachedRequestAvailable; 92 const onCachedRequestAvailable = new Promise( 93 r => (resolveCachedRequestAvailable = r) 94 ); 95 const onAvailableToPopulateInternalCache = () => {}; 96 97 // We get multiple updates, wait for all the updates 98 const onUpdatedToPopulateInternalCache = resourceUpdates => { 99 if (resourceUpdates[0].update.resourceUpdates.responseEndAvailable) { 100 resolveCachedRequestAvailable(); 101 } 102 }; 103 104 await resourceCommand.watchResources([resourceCommand.TYPES.NETWORK_EVENT], { 105 ignoreExistingResources: true, 106 onAvailable: onAvailableToPopulateInternalCache, 107 onUpdated: onUpdatedToPopulateInternalCache, 108 }); 109 110 // We can only trigger the requests once `watchResources` settles, 111 // otherwise we might miss some events and they won't be present in the cache 112 const cachedRequest = `await fetch("/cached_post.html", { method: "POST" });`; 113 await triggerNetworkRequests(tab.linkedBrowser, [cachedRequest]); 114 115 // We have to ensure that ResourceCommand processed the Resource for this first 116 // cached request before calling watchResource a second time and report it. 117 // Wait for the updated notification to avoid receiving it during the next call 118 // to watchResources. 119 await onCachedRequestAvailable; 120 121 const actualResourcesOnAvailable = {}; 122 const actualResourcesOnUpdated = {}; 123 124 const { 125 expectedResourcesOnAvailable, 126 expectedResourcesOnUpdated, 127 128 ignoreExistingResources, 129 } = options; 130 131 const onAvailable = resources => { 132 for (const resource of resources) { 133 is( 134 resource.resourceType, 135 resourceCommand.TYPES.NETWORK_EVENT, 136 "Received a network event resource" 137 ); 138 actualResourcesOnAvailable[resource.url] = resource; 139 } 140 }; 141 142 const onUpdated = updates => { 143 for (const { resource } of updates) { 144 is( 145 resource.resourceType, 146 resourceCommand.TYPES.NETWORK_EVENT, 147 "Received a network update event resource" 148 ); 149 actualResourcesOnUpdated[resource.url] = resource; 150 } 151 }; 152 153 await resourceCommand.watchResources([resourceCommand.TYPES.NETWORK_EVENT], { 154 onAvailable, 155 onUpdated, 156 ignoreExistingResources, 157 }); 158 159 info( 160 `Trigger the rest of the requests *after* calling ResourceCommand.watchResources 161 in order to assert the behavior of live network events.` 162 ); 163 const liveRequest = `await fetch("/live_get.html", { method: "GET" });`; 164 await triggerNetworkRequests(tab.linkedBrowser, [liveRequest]); 165 166 info("Check the resources on available"); 167 168 await waitUntil( 169 () => 170 Object.keys(actualResourcesOnAvailable).length == 171 Object.keys(expectedResourcesOnAvailable).length 172 ); 173 174 is( 175 Object.keys(actualResourcesOnAvailable).length, 176 Object.keys(expectedResourcesOnAvailable).length, 177 "Got the expected number of network events fired onAvailable" 178 ); 179 180 // assert the resources emitted when the network event is created 181 for (const key in expectedResourcesOnAvailable) { 182 const expected = expectedResourcesOnAvailable[key]; 183 const actual = actualResourcesOnAvailable[key]; 184 assertResources(actual, expected); 185 } 186 187 info("Check the resources on updated"); 188 await waitUntil( 189 () => 190 Object.keys(actualResourcesOnUpdated).length == 191 Object.keys(expectedResourcesOnUpdated).length 192 ); 193 194 is( 195 Object.keys(actualResourcesOnUpdated).length, 196 Object.keys(expectedResourcesOnUpdated).length, 197 "Got the expected number of network events fired onUpdated" 198 ); 199 200 // assert the resources emitted when the network event is updated 201 for (const key in expectedResourcesOnUpdated) { 202 const expected = expectedResourcesOnUpdated[key]; 203 const actual = actualResourcesOnUpdated[key]; 204 assertResources(actual, expected); 205 // assert that the resourceId for the the available and updated events match 206 is( 207 actual.resourceId, 208 actualResourcesOnAvailable[key].resourceId, 209 `Available and update resource ids for ${key} are the same` 210 ); 211 } 212 213 resourceCommand.unwatchResources([resourceCommand.TYPES.NETWORK_EVENT], { 214 onAvailable, 215 onUpdated, 216 ignoreExistingResources, 217 }); 218 219 resourceCommand.unwatchResources([resourceCommand.TYPES.NETWORK_EVENT], { 220 onAvailable: onAvailableToPopulateInternalCache, 221 }); 222 223 await commands.destroy(); 224 225 BrowserTestUtils.removeTab(tab); 226 } 227 228 function assertResources(actual, expected) { 229 is( 230 actual.resourceType, 231 expected.resourceType, 232 "The resource type is correct" 233 ); 234 is(actual.method, expected.method, "The method is correct"); 235 if ("isNavigationRequest" in expected) { 236 is( 237 actual.isNavigationRequest, 238 expected.isNavigationRequest, 239 "The isNavigationRequest attribute is correct" 240 ); 241 } 242 }