static-router-resource-timing.https.html (14914B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title> 4 Static Router: timing information should be shown when used. 5 </title> 6 <script src="/common/get-host-info.sub.js"></script> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testharnessreport.js"></script> 9 <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> 10 <script src="/service-workers/service-worker/resources/static-router-helpers.sub.js"></script> 11 <body> 12 <script> 13 const ROUTER_RULE_KEY = 'condition-urlpattern-constructed-source-network'; 14 const ROUTER_RULE_KEY_URLPATTERN_CACHE = 15 'condition-urlpattern-string-source-cache'; 16 const ROUTER_RULE_KEY_REQUEST_CACHE = 'condition-request-navigate-source-cache'; 17 const ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_MATCH_ALL_CACHE = 18 'condition-urlpattern-constructed-match-all-source-cache'; 19 const ROUTER_RULE_KEY_REQUEST_FETCH = 'condition-urlpattern-string-source-fetch-event'; 20 const REGISTERED_ROUTE = '/service-workers/service-worker/resources/direct.txt'; 21 const CACHED_ROUTE = '/service-workers/service-worker/resources/cache.txt'; 22 const NON_REGISTERED_ROUTE = '/service-workers/service-worker/resources/simple.html'; 23 24 const RACE_ROUTER_KEY = 25 'condition-urlpattern-string-source-race-network-and-fetch-handler'; 26 const RACE_SW_SRC = '/service-workers/service-worker/resources/static-router-race-network-and-fetch-handler-sw.js'; 27 const RACE_ROUTE = '/service-workers/service-worker/resources/direct.py'; 28 29 const host_info = get_host_info(); 30 31 function resourceUrl(resource) { 32 return `${host_info['HTTPS_ORIGIN']}${resource}`; 33 } 34 35 // Verify existance of a PerformanceEntry and the order between the timings of 36 // ServiceWorker Static routing API. 37 // 38 // |options| has these properties: 39 // performance: Performance interface to verify existance of the entry. 40 // url: the URL of resource 41 // description: the description passed to each assertion. 42 // matched_source: the expected matched source of router evaluation. 43 // actual_source: the expected actual source used to get the resource. 44 function test_resource_timing(options) { 45 const description = options.description; 46 const entryList = options.performance.getEntriesByName(resourceUrl(options.url)); 47 assert_equals(entryList.length, 1, description); 48 const entry = entryList[0]; 49 50 assert_equals(entry.workerMatchedSourceType, options.matched_source_type, description); 51 assert_equals(entry.workerFinalSourceType, options.final_source_type, description); 52 53 assert_greater_than(entry.workerRouterEvaluationStart, 0, description); 54 switch (entry.matchedSouceType) { 55 case 'network': 56 assert_equals(entry.workerStart, 0, description); 57 assert_equals(entry.workerCacheLookupStart, 0, description); 58 assert_less_than_equal(entry.workerRouterEvaluationStart, entry.fetchStart, description); 59 assert_greater_than(entry.encodedBodySize, 0, description); 60 break; 61 case 'cache': 62 assert_equals(entry.workerStart, 0, description); 63 assert_greater_than_equal(entry.workerCacheLookupStart, entry.workerRouterEvaluationStart, description); 64 assert_greater_than(entry.encodedBodySize, 0, description); 65 if (entry.workerFinalSourceType === 'cache') { 66 assert_equals(entry.fetchStart, entry.responseStart, description); 67 assert_less_than_equal(entry.workerCacheLookupStart, entry.responseStart, description); 68 assert_equals(entry.deliveryType, 'cache-storage', description); 69 } else { 70 assert_less_than_equal(entry.workerCacheLookupStart, entry.fetchStart, description); 71 } 72 break; 73 case 'race-network-and-fetch-handler': 74 assert_equals(entry.workerCacheLookupStart, 0, description); 75 assert_greater_than(entry.encodedBodySize, 0, description); 76 if (entry.workerFinalSourceType === 'network') { 77 assert_equals(entry.workerStart, 0, description); 78 assert_less_than_equal(entry.workerRouterEvaluationStart, entry.fetchStart, description); 79 } else { 80 assert_greater_than_equal(entry.workerStart, entry.workerRouterEvaluationStart, description); 81 assert_greater_than_equal(entry.fetchStart, entry.workerStart, description); 82 } 83 break; 84 case 'fetch-event': 85 assert_greater_than(entry.encodedBodySize, 0, description); 86 break; 87 case '': // i.e. no matching rules 88 assert_equals(entry.workerCacheLookupStart, 0, description); 89 assert_greater_than_equal(entry.workerStart, entry.workerRouterEvaluationStart, description); 90 assert_greater_than_equal(entry.fetchStart, entry.workerStart, description); 91 break; 92 } 93 } 94 95 promise_test(async t => { 96 const worker = await registerAndActivate(t, ROUTER_RULE_KEY_REQUEST_FETCH); 97 const rnd = randomString(); 98 const url = `${NON_REGISTERED_ROUTE}?nonce=${rnd}`; 99 const iframe = await createIframe(t, url); 100 const {errors, requests} = await get_info_from_worker(worker); 101 102 assert_equals(errors.length, 0); 103 assert_equals(requests.length, 1); 104 assert_equals(iframe.contentWindow.document.body.innerText, rnd); 105 106 test_resource_timing({ 107 performance: iframe.contentWindow.performance, 108 url: url, 109 matched_source_type: 'fetch-event', 110 final_source_type: 'fetch-event', 111 description: "fetch-event as source on main resource" 112 }); 113 }, 'Main resource matched the rule with fetch-event source'); 114 115 iframeTest(REGISTERED_ROUTE, ROUTER_RULE_KEY, async (t, iwin, worker) => { 116 const {requests} = await get_info_from_worker(worker); 117 assert_equals(requests.length, 0); 118 assert_equals(iwin.document.body.innerText, "Network\n"); 119 test_resource_timing({ 120 performance: iwin.performance, 121 url: REGISTERED_ROUTE, 122 matched_source_type: 'network', 123 final_source_type: 'network', 124 description: "network as source on main resource" 125 }); 126 }, 'Main resource load matched with the condition and resource timing'); 127 128 iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY, async (t, iwin, worker) => { 129 const {requests} = await get_info_from_worker(worker); 130 assert_equals(requests.length, 1); 131 assert_equals( 132 requests[0].url, 133 resourceUrl(NON_REGISTERED_ROUTE)); 134 assert_equals(requests[0].mode, 'navigate'); 135 test_resource_timing({ 136 performance: iwin.performance, 137 url: NON_REGISTERED_ROUTE, 138 matched_source_type: '', 139 final_source_type: '', 140 description: "no rule matched on main resource" 141 }); 142 }, 'Main resource load not matched with the condition and resource timing'); 143 144 iframeTest(CACHED_ROUTE, ROUTER_RULE_KEY_URLPATTERN_CACHE, async (t, iwin, worker) => { 145 const {requests} = await get_info_from_worker(worker); 146 assert_equals(requests.length, 0); 147 assert_equals(iwin.document.body.innerText, "From cache"); 148 test_resource_timing({ 149 performance: iwin.performance, 150 url: CACHED_ROUTE, 151 matched_source_type: 'cache', 152 final_source_type: 'cache', 153 description: "cache as source on main resource and cache hit" 154 }); 155 }, 'Main resource load matched with the cache source and resource timing'); 156 157 iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY_REQUEST_CACHE, async (t, iwin, worker) => { 158 const {requests} = await get_info_from_worker(worker); 159 // When the request matched to the rule with the "cache" source but failed to 160 // get the cache entry, the fetch handler is not involved and the network 161 // fallback is triggered instead. 162 assert_equals(requests.length, 0); 163 assert_equals(iwin.document.body.innerText, "Here's a simple html file."); 164 test_resource_timing({ 165 performance: iwin.performance, 166 url: NON_REGISTERED_ROUTE, 167 matched_source_type: 'cache', 168 final_source_type: 'network', 169 description: "cache as source on main resource and cache miss, fallback to network" 170 }); 171 }, 'Main resource fallback to the network when there is no cache entry and resource timing'); 172 173 // Subresource 174 iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY_REQUEST_FETCH, async (t, iwin, worker) => { 175 const rnd = randomString(); 176 const subresource = `?nonce=${rnd}`; 177 const response = await iwin.fetch(subresource); 178 179 assert_equals(response.status, 200); 180 assert_equals(await response.text(), rnd); 181 const {requests} = await get_info_from_worker(worker); 182 // Main resource request + subreosurce request = 2. 183 assert_equals(requests.length, 2); 184 185 test_resource_timing({ 186 performance: iwin.performance, 187 url: `${NON_REGISTERED_ROUTE}${subresource}`, 188 matched_source_type: 'fetch-event', 189 final_source_type: 'fetch-event', 190 description: "fetch-event as source on sub resource" 191 }); 192 }, 'Subresource load matched the rule fetch-event source'); 193 194 iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY, async (t, iwin) => { 195 const rnd = randomString(); 196 const subresource = `?nonce=${rnd}`; 197 const response = await iwin.fetch(subresource); 198 assert_equals(await response.text(), rnd); 199 test_resource_timing({ 200 performance: iwin.performance, 201 url: NON_REGISTERED_ROUTE + subresource, 202 matched_source_type: '', 203 final_source_type: '', 204 description: "no source type matched" 205 }); 206 }, 'Subresource load not matched with URLPattern condition'); 207 208 iframeTest(REGISTERED_ROUTE, ROUTER_RULE_KEY, async (t, iwin) => { 209 const rnd = randomString(); 210 const subresource = `?nonce=${rnd}`; 211 const response = await iwin.fetch(subresource); 212 assert_equals(await response.text(), "Network\n"); 213 test_resource_timing({ 214 performance: iwin.performance, 215 url: REGISTERED_ROUTE + subresource, 216 matched_source_type: 'network', 217 final_source_type: 'network', 218 description: "network as source on subresource" 219 }); 220 }, 'Subresource load matched with URLPattern condition'); 221 222 iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY_URLPATTERN_CACHE, async (t, iwin) => { 223 // No need to set `resources/` because the request is dispatched from iframe. 224 const CACHED_FILE = 'cache.txt'; 225 const response = await iwin.fetch(CACHED_FILE); 226 assert_equals(await response.text(), "From cache"); 227 test_resource_timing({ 228 performance: iwin.performance, 229 url: CACHED_ROUTE, // We need a path including `resources/` to get the resource 230 matched_source_type: 'cache', 231 final_source_type: 'cache', 232 description: "cache as source on subresource and cache hits" 233 }); 234 }, 'Subresource load matched with the cache source rule'); 235 236 iframeTest(REGISTERED_ROUTE, ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_MATCH_ALL_CACHE, async (t, iwin, worker) => { 237 // Send a request, which is not stored in the cache, but it exists over the network. 238 const rnd = randomString(); 239 let subresource = `?nonce=${rnd}`; 240 let response = await iwin.fetch(subresource); 241 assert_equals(await response.text(), "Network\n"); 242 assert_equals(response.status, 200); 243 244 // Request is not handled by ServiceWorker. 245 const {requests} = await get_info_from_worker(worker); 246 assert_equals(requests.length, 0); 247 test_resource_timing({ 248 performance: iwin.performance, 249 url: `${REGISTERED_ROUTE}${subresource}`, 250 matched_source_type: 'cache', 251 final_source_type: 'network', 252 description: "cache as source on subresource and cache misses" 253 }); 254 }, 'Subresource load did not match with the cache and fallback to the network'); 255 256 // Race Tests 257 promise_test(async t => { 258 const rnd = randomString(); 259 const url = `${RACE_ROUTE}?nonce=${rnd}&server_slow`; 260 const worker = await registerAndActivate(t, RACE_ROUTER_KEY, RACE_SW_SRC); 261 const iframe = await createIframe(t, url); 262 // Expect the response from the fetch handler. 263 assert_equals(iframe.contentWindow.document.body.innerText, rnd); 264 const {requests} = await get_info_from_worker(worker); 265 assert_equals(requests.length, 1); 266 test_resource_timing({ 267 performance: iframe.contentWindow.performance, 268 url: url, 269 matched_source_type: 'race-network-and-fetch-handler', 270 final_source_type: 'fetch-event', 271 description: "race as source on main resource, and fetch-event wins" 272 }); 273 }, 'Main resource load matched the rule with race-network-and-fetch-handler source, and the fetch handler response is faster than the server response'); 274 275 promise_test(async t => { 276 const rnd = randomString(); 277 const url = `${RACE_ROUTE}?nonce=${rnd}&sw_slow`; 278 const worker = await registerAndActivate(t, RACE_ROUTER_KEY, RACE_SW_SRC); 279 const iframe = await createIframe(t, url); 280 // Expect the response from the netowrk request. 281 assert_equals(iframe.contentWindow.document.body.innerText, "Network with GET request"); 282 // Ensure the fetch handler is also executed. 283 const {requests} = await get_info_from_worker(worker); 284 assert_equals(requests.length, 1); 285 test_resource_timing({ 286 performance: iframe.contentWindow.performance, 287 url: url, 288 matched_source_type: 'race-network-and-fetch-handler', 289 final_source_type: 'network', 290 description: "race as source on main resource, and network wins" 291 }); 292 }, 'Main resource load matched the rule with race-network-and-fetch-handler source, and the server reseponse is faster than the fetch handler'); 293 294 promise_test(async t => { 295 const rnd = randomString(); 296 const worker = await registerAndActivate(t, RACE_ROUTER_KEY, RACE_SW_SRC); 297 const iframe = await createIframe(t, RACE_ROUTE); 298 const subresource = `?nonce=${rnd}&server_slow`; 299 // Expect the response from the fetch handler. 300 const response = await iframe.contentWindow.fetch(subresource); 301 assert_equals(response.status, 200); 302 assert_equals(await response.text(), rnd); 303 const {requests} = await get_info_from_worker(worker); 304 assert_equals(requests.length, 2); 305 306 test_resource_timing({ 307 performance: iframe.contentWindow.performance, 308 url: `${RACE_ROUTE}${subresource}`, 309 matched_source_type: 'race-network-and-fetch-handler', 310 final_source_type: 'fetch-event', 311 description: "race as source on subresource and fetch wins" 312 }); 313 }, 'Subresource load matched the rule with race-network-and-fetch-handler source, and the fetch handler response is faster than the server response'); 314 315 promise_test(async t => { 316 const rnd = randomString(); 317 const worker = await registerAndActivate(t, RACE_ROUTER_KEY, RACE_SW_SRC); 318 const iframe = await createIframe(t, RACE_ROUTE); 319 const subresource = `?nonce=${rnd}&sw_slow`; 320 // Expect the response from the network request. 321 const response = await iframe.contentWindow.fetch(subresource); 322 assert_equals(response.status, 200); 323 assert_equals(await response.text(), "Network with GET request"); 324 // Ensure the fetch handler is also executed. 325 const {requests} = await get_info_from_worker(worker); 326 assert_equals(requests.length, 2); 327 328 test_resource_timing({ 329 performance: iframe.contentWindow.performance, 330 url: `${RACE_ROUTE}${subresource}`, 331 matched_source_type: 'race-network-and-fetch-handler', 332 final_source_type: 'network', 333 description: "race as source on subresource and network wins" 334 }); 335 }, 'Subresource load matched the rule with race-network-and-fetch-handler source, and the server reseponse is faster than the fetch handler'); 336 </script> 337 </body>