Skip to content

Commit 271006c

Browse files
quasi-modchromium-wpt-export-bot
authored andcommitted
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 <[email protected]> Reviewed-by: Yoshisato Yanagisawa <[email protected]> Reviewed-by: Shunya Shishido <[email protected]> Reviewed-by: Kent Tamura <[email protected]> Commit-Queue: Keita Suzuki <[email protected]> Cr-Commit-Position: refs/heads/main@{#1303199}
1 parent 8dd0e0a commit 271006c

File tree

1 file changed

+332
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)