-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add WPTs for ServiceWorker Static Routing API Resource Timing
This CL adds WPTs for Service Worker Static Routing API Resource Timing. It conducts a set of tests to determine if the resource timing is correctly working on each source type, and on main and sub-resources. Explainer: WICG/service-worker-static-routing-api#25 Bug: 41496865 Change-Id: Ide7d352d4824b9491645964febb6522ffe71aafb Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5521193 Reviewed-by: Minoru Chikamune <chikamune@chromium.org> Reviewed-by: Yoshisato Yanagisawa <yyanagisawa@chromium.org> Reviewed-by: Shunya Shishido <sisidovski@chromium.org> Reviewed-by: Kent Tamura <tkent@chromium.org> Commit-Queue: Keita Suzuki <suzukikeita@chromium.org> Cr-Commit-Position: refs/heads/main@{#1303199}
- Loading branch information
1 parent
8dd0e0a
commit 1b18480
Showing
1 changed file
with
332 additions
and
0 deletions.
There are no files selected for viewing
332 changes: 332 additions & 0 deletions
332
...e-workers/service-worker/tentative/static-router/static-router-resource-timing.https.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,332 @@ | ||
<!DOCTYPE html> | ||
<meta charset="utf-8"> | ||
<title> | ||
Static Router: timing information should be shown when used. | ||
</title> | ||
<script src="/common/get-host-info.sub.js"></script> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="resources/test-helpers.sub.js"></script> | ||
<script src="resources/static-router-helpers.sub.js"></script> | ||
<body> | ||
<script> | ||
const ROUTER_RULE_KEY = 'condition-urlpattern-constructed-source-network'; | ||
const ROUTER_RULE_KEY_URLPATTERN_CACHE = | ||
'condition-urlpattern-string-source-cache'; | ||
const ROUTER_RULE_KEY_REQUEST_CACHE = 'condition-request-navigate-source-cache'; | ||
const ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_MATCH_ALL_CACHE = | ||
'condition-urlpattern-constructed-match-all-source-cache'; | ||
const ROUTER_RULE_KEY_REQUEST_FETCH = 'condition-urlpattern-string-source-fetch-event'; | ||
const REGISTERED_ROUTE = 'resources/direct.txt'; | ||
const CACHED_ROUTE = 'resources/cache.txt'; | ||
const NON_REGISTERED_ROUTE = 'resources/simple.html'; | ||
|
||
const RACE_ROUTER_KEY = | ||
'condition-urlpattern-string-source-race-network-and-fetch-handler'; | ||
const RACE_SW_SRC = 'resources/static-router-race-network-and-fetch-handler-sw.js'; | ||
const RACE_ROUTE = 'resources/direct.py'; | ||
|
||
const host_info = get_host_info(); | ||
const path = new URL(".", window.location).pathname; | ||
|
||
function resourceUrl(resource) { | ||
return `${host_info['HTTPS_ORIGIN']}${path}${resource}`; | ||
} | ||
|
||
// Verify existance of a PerformanceEntry and the order between the timings of | ||
// ServiceWorker Static routing API. | ||
// | ||
// |options| has these properties: | ||
// performance: Performance interface to verify existance of the entry. | ||
// url: the URL of resource | ||
// description: the description passed to each assertion. | ||
// matched_source: the expected matched source of router evaluation. | ||
// actual_source: the expected actual source used to get the resource. | ||
function test_resource_timing(options) { | ||
const description = options.description; | ||
const entryList = options.performance.getEntriesByName(resourceUrl(options.url)); | ||
assert_equals(entryList.length, 1, description); | ||
const entry = entryList[0]; | ||
|
||
assert_equals(entry.matchedSourceType, options.matched_source_type, description); | ||
assert_equals(entry.finalSourceType, options.final_source_type, description); | ||
|
||
assert_greater_than(entry.workerRouterEvaluationStart, 0, description); | ||
switch (entry.matchedSouceType) { | ||
case 'network': | ||
assert_equals(entry.workerStart, 0, description); | ||
assert_equals(entry.workerCacheLookupStart, 0, description); | ||
assert_less_than_equal(entry.workerRouterEvaluationStart, entry.fetchStart, description); | ||
break; | ||
case 'cache': | ||
assert_equals(entry.workerStart, 0, description); | ||
assert_greater_than_equal(entry.workerCacheLookupStart, entry.workerRouterEvaluationStart, description); | ||
if (entry.finalSourceType === 'cache') { | ||
assert_equals(entry.fetchStart, 0, description); | ||
assert_less_than_equal(entry.workerCacheLookupStart, entry.responseStart, description); | ||
} else { | ||
assert_less_than_equal(entry.workerCacheLookupStart, entry.fetchStart, description); | ||
} | ||
break; | ||
case 'race-network-and-fetch': | ||
assert_equals(entry.workerCacheLookupStart, 0, description); | ||
if (entry.finalSourceType === 'network') { | ||
assert_equals(entry.workerStart, 0, description); | ||
assert_less_than_equal(entry.workerRouterEvaluationStart, entry.fetchStart, description); | ||
} else { | ||
assert_greater_than_equal(entry.workerStart, entry.workerRouterEvaluationStart, description); | ||
assert_greater_than_equal(entry.fetchStart, entry.workerStart, description); | ||
} | ||
break; | ||
case 'fetch-event': | ||
case '': // i.e. no matching rules | ||
assert_equals(entry.workerCacheLookupStart, 0, description); | ||
assert_greater_than_equal(entry.workerStart, entry.workerRouterEvaluationStart, description); | ||
assert_greater_than_equal(entry.fetchStart, entry.workerStart, description); | ||
break; | ||
} | ||
} | ||
|
||
promise_test(async t => { | ||
const worker = await registerAndActivate(t, ROUTER_RULE_KEY_REQUEST_FETCH); | ||
const rnd = randomString(); | ||
const url = `${NON_REGISTERED_ROUTE}?nonce=${rnd}`; | ||
const iframe = await createIframe(t, url); | ||
const {errors, requests} = await get_info_from_worker(worker); | ||
|
||
assert_equals(errors.length, 0); | ||
assert_equals(requests.length, 1); | ||
assert_equals(iframe.contentWindow.document.body.innerText, rnd); | ||
|
||
test_resource_timing({ | ||
performance: iframe.contentWindow.performance, | ||
url: url, | ||
matched_source_type: 'fetch-event', | ||
final_source_type: 'fetch-event', | ||
description: "fetch-event as source on main resource" | ||
}); | ||
}, 'Main resource matched the rule with fetch-event source'); | ||
|
||
iframeTest(REGISTERED_ROUTE, ROUTER_RULE_KEY, async (t, iwin, worker) => { | ||
const {requests} = await get_info_from_worker(worker); | ||
assert_equals(requests.length, 0); | ||
assert_equals(iwin.document.body.innerText, "Network\n"); | ||
test_resource_timing({ | ||
performance: iwin.performance, | ||
url: REGISTERED_ROUTE, | ||
matched_source_type: 'network', | ||
final_source_type: 'network', | ||
description: "network as source on main resource" | ||
}); | ||
}, 'Main resource load matched with the condition and resource timing'); | ||
|
||
iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY, async (t, iwin, worker) => { | ||
const {requests} = await get_info_from_worker(worker); | ||
assert_equals(requests.length, 1); | ||
assert_equals( | ||
requests[0].url, | ||
resourceUrl(NON_REGISTERED_ROUTE)); | ||
assert_equals(requests[0].mode, 'navigate'); | ||
test_resource_timing({ | ||
performance: iwin.performance, | ||
url: NON_REGISTERED_ROUTE, | ||
matched_source_type: '', | ||
final_source_type: '', | ||
description: "no rule matched on main resource" | ||
}); | ||
}, 'Main resource load not matched with the condition and resource timing'); | ||
|
||
iframeTest(CACHED_ROUTE, ROUTER_RULE_KEY_URLPATTERN_CACHE, async (t, iwin, worker) => { | ||
const {requests} = await get_info_from_worker(worker); | ||
assert_equals(requests.length, 0); | ||
assert_equals(iwin.document.body.innerText, "From cache"); | ||
test_resource_timing({ | ||
performance: iwin.performance, | ||
url: CACHED_ROUTE, | ||
matched_source_type: 'cache', | ||
final_source_type: 'cache', | ||
description: "cache as source on main resource and cache hit" | ||
}); | ||
}, 'Main resource load matched with the cache source and resource timing'); | ||
|
||
iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY_REQUEST_CACHE, async (t, iwin, worker) => { | ||
const {requests} = await get_info_from_worker(worker); | ||
// When the request matched to the rule with the "cache" source but failed to | ||
// get the cache entry, the fetch handler is not involved and the network | ||
// fallback is triggered instead. | ||
assert_equals(requests.length, 0); | ||
assert_equals(iwin.document.body.innerText, "Here's a simple html file."); | ||
test_resource_timing({ | ||
performance: iwin.performance, | ||
url: NON_REGISTERED_ROUTE, | ||
matched_source_type: 'cache', | ||
final_source_type: 'network', | ||
description: "cache as source on main resource and cache miss, fallback to network" | ||
}); | ||
}, 'Main resource fallback to the network when there is no cache entry and resource timing'); | ||
|
||
// Subresource | ||
iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY_REQUEST_FETCH, async (t, iwin, worker) => { | ||
const rnd = randomString(); | ||
const subresource = `?nonce=${rnd}`; | ||
const response = await iwin.fetch(subresource); | ||
|
||
assert_equals(response.status, 200); | ||
assert_equals(await response.text(), rnd); | ||
const {requests} = await get_info_from_worker(worker); | ||
// Main resource request + subreosurce request = 2. | ||
assert_equals(requests.length, 2); | ||
|
||
test_resource_timing({ | ||
performance: iwin.performance, | ||
url: `${NON_REGISTERED_ROUTE}${subresource}`, | ||
matched_source_type: 'fetch-event', | ||
final_source_type: 'fetch-event', | ||
description: "fetch-event as source on sub resource" | ||
}); | ||
}, 'Subresource load matched the rule fetch-event source'); | ||
|
||
iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY, async (t, iwin) => { | ||
const rnd = randomString(); | ||
const subresource = `?nonce=${rnd}`; | ||
const response = await iwin.fetch(subresource); | ||
assert_equals(await response.text(), rnd); | ||
test_resource_timing({ | ||
performance: iwin.performance, | ||
url: NON_REGISTERED_ROUTE + subresource, | ||
matched_source_type: '', | ||
final_source_type: '', | ||
description: "no source type matched" | ||
}); | ||
}, 'Subresource load not matched with URLPattern condition'); | ||
|
||
iframeTest(REGISTERED_ROUTE, ROUTER_RULE_KEY, async (t, iwin) => { | ||
const rnd = randomString(); | ||
const subresource = `?nonce=${rnd}`; | ||
const response = await iwin.fetch(subresource); | ||
assert_equals(await response.text(), "Network\n"); | ||
test_resource_timing({ | ||
performance: iwin.performance, | ||
url: REGISTERED_ROUTE + subresource, | ||
matched_source_type: 'network', | ||
final_source_type: 'network', | ||
description: "network as source on subresource" | ||
}); | ||
}, 'Subresource load matched with URLPattern condition'); | ||
|
||
iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY_URLPATTERN_CACHE, async (t, iwin) => { | ||
// No need to set `resources/` because the request is dispatched from iframe. | ||
const CACHED_FILE = 'cache.txt'; | ||
const response = await iwin.fetch(CACHED_FILE); | ||
assert_equals(await response.text(), "From cache"); | ||
test_resource_timing({ | ||
performance: iwin.performance, | ||
url: CACHED_ROUTE, // We need a path including `resources/` to get the resource | ||
matched_source_type: 'cache', | ||
final_source_type: 'cache', | ||
description: "cache as source on subresource and cache hits" | ||
}); | ||
}, 'Subresource load matched with the cache source rule'); | ||
|
||
iframeTest(REGISTERED_ROUTE, ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_MATCH_ALL_CACHE, async (t, iwin, worker) => { | ||
// Send a request, which is not stored in the cache, but it exists over the network. | ||
const rnd = randomString(); | ||
let subresource = `?nonce=${rnd}`; | ||
let response = await iwin.fetch(subresource); | ||
assert_equals(await response.text(), "Network\n"); | ||
assert_equals(response.status, 200); | ||
|
||
// Request is not handled by ServiceWorker. | ||
const {requests} = await get_info_from_worker(worker); | ||
assert_equals(requests.length, 0); | ||
test_resource_timing({ | ||
performance: iwin.performance, | ||
url: `${REGISTERED_ROUTE}${subresource}`, | ||
matched_source_type: 'cache', | ||
final_source_type: 'network', | ||
description: "cache as source on subresource and cache misses" | ||
}); | ||
}, 'Subresource load did not match with the cache and fallback to the network'); | ||
|
||
// Race Tests | ||
promise_test(async t => { | ||
const rnd = randomString(); | ||
const url = `${RACE_ROUTE}?nonce=${rnd}&server_slow`; | ||
const worker = await registerAndActivate(t, RACE_ROUTER_KEY, RACE_SW_SRC); | ||
const iframe = await createIframe(t, url); | ||
// Expect the response from the fetch handler. | ||
assert_equals(iframe.contentWindow.document.body.innerText, rnd); | ||
const {requests} = await get_info_from_worker(worker); | ||
assert_equals(requests.length, 1); | ||
test_resource_timing({ | ||
performance: iframe.contentWindow.performance, | ||
url: url, | ||
matched_source_type: 'race-network-and-fetch', | ||
final_source_type: 'fetch-event', | ||
description: "race as source on main resource, and fetch-event wins" | ||
}); | ||
}, 'Main resource load matched the rule with race-network-and-fetch-handler source, and the fetch handler response is faster than the server response'); | ||
|
||
promise_test(async t => { | ||
const rnd = randomString(); | ||
const url = `${RACE_ROUTE}?nonce=${rnd}&sw_slow`; | ||
const worker = await registerAndActivate(t, RACE_ROUTER_KEY, RACE_SW_SRC); | ||
const iframe = await createIframe(t, url); | ||
// Expect the response from the netowrk request. | ||
assert_equals(iframe.contentWindow.document.body.innerText, "Network with GET request"); | ||
// Ensure the fetch handler is also executed. | ||
const {requests} = await get_info_from_worker(worker); | ||
assert_equals(requests.length, 1); | ||
test_resource_timing({ | ||
performance: iframe.contentWindow.performance, | ||
url: url, | ||
matched_source_type: 'race-network-and-fetch', | ||
final_source_type: 'network', | ||
description: "race as source on main resource, and network wins" | ||
}); | ||
}, 'Main resource load matched the rule with race-network-and-fetch-handler source, and the server reseponse is faster than the fetch handler'); | ||
|
||
promise_test(async t => { | ||
const rnd = randomString(); | ||
const worker = await registerAndActivate(t, RACE_ROUTER_KEY, RACE_SW_SRC); | ||
const iframe = await createIframe(t, RACE_ROUTE); | ||
const subresource = `?nonce=${rnd}&server_slow`; | ||
// Expect the response from the fetch handler. | ||
const response = await iframe.contentWindow.fetch(subresource); | ||
assert_equals(response.status, 200); | ||
assert_equals(await response.text(), rnd); | ||
const {requests} = await get_info_from_worker(worker); | ||
assert_equals(requests.length, 2); | ||
|
||
test_resource_timing({ | ||
performance: iframe.contentWindow.performance, | ||
url: `${RACE_ROUTE}${subresource}`, | ||
matched_source_type: 'race-network-and-fetch', | ||
final_source_type: 'fetch-event', | ||
description: "race as source on subresource and fetch wins" | ||
}); | ||
}, 'Subresource load matched the rule with race-network-and-fetch-handler source, and the fetch handler response is faster than the server response'); | ||
|
||
promise_test(async t => { | ||
const rnd = randomString(); | ||
const worker = await registerAndActivate(t, RACE_ROUTER_KEY, RACE_SW_SRC); | ||
const iframe = await createIframe(t, RACE_ROUTE); | ||
const subresource = `?nonce=${rnd}&sw_slow`; | ||
// Expect the response from the network request. | ||
const response = await iframe.contentWindow.fetch(subresource); | ||
assert_equals(response.status, 200); | ||
assert_equals(await response.text(), "Network with GET request"); | ||
// Ensure the fetch handler is also executed. | ||
const {requests} = await get_info_from_worker(worker); | ||
assert_equals(requests.length, 2); | ||
|
||
test_resource_timing({ | ||
performance: iframe.contentWindow.performance, | ||
url: `${RACE_ROUTE}${subresource}`, | ||
matched_source_type: 'race-network-and-fetch', | ||
final_source_type: 'network', | ||
description: "race as source on subresource and network wins" | ||
}); | ||
}, 'Subresource load matched the rule with race-network-and-fetch-handler source, and the server reseponse is faster than the fetch handler'); | ||
</script> | ||
</body> |
1b18480
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
foia
1b18480
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hello # @ @foiabarroso