summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/fetch/stale-while-revalidate
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/fetch/stale-while-revalidate
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/fetch/stale-while-revalidate')
-rw-r--r--testing/web-platform/tests/fetch/stale-while-revalidate/fetch-sw.https.html65
-rw-r--r--testing/web-platform/tests/fetch/stale-while-revalidate/fetch.any.js32
-rw-r--r--testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-css.py28
-rw-r--r--testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-image.py40
-rw-r--r--testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-script.py32
-rw-r--r--testing/web-platform/tests/fetch/stale-while-revalidate/revalidate-not-blocked-by-csp.html69
-rw-r--r--testing/web-platform/tests/fetch/stale-while-revalidate/stale-css.html51
-rw-r--r--testing/web-platform/tests/fetch/stale-while-revalidate/stale-image.html55
-rw-r--r--testing/web-platform/tests/fetch/stale-while-revalidate/stale-script.html59
-rw-r--r--testing/web-platform/tests/fetch/stale-while-revalidate/sw-intercept.js14
10 files changed, 445 insertions, 0 deletions
diff --git a/testing/web-platform/tests/fetch/stale-while-revalidate/fetch-sw.https.html b/testing/web-platform/tests/fetch/stale-while-revalidate/fetch-sw.https.html
new file mode 100644
index 0000000000..efcebc24a6
--- /dev/null
+++ b/testing/web-platform/tests/fetch/stale-while-revalidate/fetch-sw.https.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Stale Revalidation Requests don't get sent to service worker</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../service-workers/service-worker/resources/test-helpers.sub.js"></script>
+ <script src="/common/utils.js"></script>
+</head>
+<body>
+<script>
+
+ // Duplicating this resource to make service worker scoping simpler.
+ async function setupRegistrationAndWaitToBeControlled(t, scope) {
+ const controlled = new Promise((resolve) => {
+ navigator.serviceWorker.oncontrollerchange = () => { resolve(); };
+ });
+ const reg = await navigator.serviceWorker.register('sw-intercept.js');
+ await wait_for_state(t, reg.installing, 'activated');
+ await controlled;
+ add_completion_callback(_ => reg.unregister());
+ return reg;
+ }
+
+ // Using 250ms polling interval to provide enough 'network calmness' to give
+ // the background low priority revalidation request a chance to kick in.
+ function wait250ms(test) {
+ return new Promise(resolve => {
+ test.step_timeout(() => {
+ resolve();
+ }, 250);
+ });
+ }
+
+ promise_test(async (test) => {
+ var request_token = token();
+ const uri = 'resources/stale-script.py?token=' + request_token;
+
+ await setupRegistrationAndWaitToBeControlled(test, 'resources/stale-script.py');
+
+ var service_worker_count = 0;
+ navigator.serviceWorker.addEventListener('message', function once(event) {
+ if (event.data.endsWith(uri)) {
+ service_worker_count++;
+ }
+ });
+
+ const response = await fetch(uri);
+ const response2 = await fetch(uri);
+ assert_equals(response.headers.get('Unique-Id'), response2.headers.get('Unique-Id'));
+ while(true) {
+ const revalidation_check = await fetch(`resources/stale-script.py?query&token=` + request_token);
+ if (revalidation_check.headers.get('Count') == '2') {
+ // The service worker should not see the revalidation request.
+ assert_equals(service_worker_count, 2);
+ break;
+ }
+ await wait250ms(test);
+ }
+ }, 'Second fetch returns same response');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/fetch/stale-while-revalidate/fetch.any.js b/testing/web-platform/tests/fetch/stale-while-revalidate/fetch.any.js
new file mode 100644
index 0000000000..3682b9d2c3
--- /dev/null
+++ b/testing/web-platform/tests/fetch/stale-while-revalidate/fetch.any.js
@@ -0,0 +1,32 @@
+// META: global=window,worker
+// META: title=Tests Stale While Revalidate is executed for fetch API
+// META: script=/common/utils.js
+
+function wait25ms(test) {
+ return new Promise(resolve => {
+ test.step_timeout(() => {
+ resolve();
+ }, 25);
+ });
+}
+
+promise_test(async (test) => {
+ var request_token = token();
+
+ const response = await fetch(`resources/stale-script.py?token=` + request_token);
+ // Wait until resource is completely fetched to allow caching before next fetch.
+ const body = await response.text();
+ const response2 = await fetch(`resources/stale-script.py?token=` + request_token);
+
+ assert_equals(response.headers.get('Unique-Id'), response2.headers.get('Unique-Id'));
+ const body2 = await response2.text();
+ assert_equals(body, body2);
+
+ while(true) {
+ const revalidation_check = await fetch(`resources/stale-script.py?query&token=` + request_token);
+ if (revalidation_check.headers.get('Count') == '2') {
+ break;
+ }
+ await wait25ms(test);
+ }
+}, 'Second fetch returns same response');
diff --git a/testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-css.py b/testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-css.py
new file mode 100644
index 0000000000..b87668373a
--- /dev/null
+++ b/testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-css.py
@@ -0,0 +1,28 @@
+def main(request, response):
+
+ token = request.GET.first(b"token", None)
+ is_query = request.GET.first(b"query", None) != None
+ with request.server.stash.lock:
+ value = request.server.stash.take(token)
+ count = 0
+ if value != None:
+ count = int(value)
+ if is_query:
+ if count < 2:
+ request.server.stash.put(token, count)
+ else:
+ count = count + 1
+ request.server.stash.put(token, count)
+ if is_query:
+ headers = [(b"Count", count)]
+ content = b""
+ return 200, headers, content
+ else:
+ content = b"body { background: rgb(0, 128, 0); }"
+ if count > 1:
+ content = b"body { background: rgb(255, 0, 0); }"
+
+ headers = [(b"Content-Type", b"text/css"),
+ (b"Cache-Control", b"private, max-age=0, stale-while-revalidate=60")]
+
+ return 200, headers, content
diff --git a/testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-image.py b/testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-image.py
new file mode 100644
index 0000000000..36e6fc0c9b
--- /dev/null
+++ b/testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-image.py
@@ -0,0 +1,40 @@
+import os.path
+
+from wptserve.utils import isomorphic_decode
+
+def main(request, response):
+
+ token = request.GET.first(b"token", None)
+ is_query = request.GET.first(b"query", None) != None
+ with request.server.stash.lock:
+ value = request.server.stash.take(token)
+ count = 0
+ if value != None:
+ count = int(value)
+ if is_query:
+ if count < 2:
+ request.server.stash.put(token, count)
+ else:
+ count = count + 1
+ request.server.stash.put(token, count)
+
+ if is_query:
+ headers = [(b"Count", count)]
+ content = b""
+ return 200, headers, content
+ else:
+ filename = u"green-16x16.png"
+ if count > 1:
+ filename = u"green-256x256.png"
+
+ path = os.path.join(os.path.dirname(isomorphic_decode(__file__)), u"../../../images", filename)
+ body = open(path, "rb").read()
+
+ response.add_required_headers = False
+ response.writer.write_status(200)
+ response.writer.write_header(b"content-length", len(body))
+ response.writer.write_header(b"Cache-Control", b"private, max-age=0, stale-while-revalidate=60")
+ response.writer.write_header(b"content-type", b"image/png")
+ response.writer.end_headers()
+
+ response.writer.write(body)
diff --git a/testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-script.py b/testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-script.py
new file mode 100644
index 0000000000..731cd80565
--- /dev/null
+++ b/testing/web-platform/tests/fetch/stale-while-revalidate/resources/stale-script.py
@@ -0,0 +1,32 @@
+import random, string
+
+def id_token():
+ letters = string.ascii_lowercase
+ return b''.join(random.choice(letters).encode("utf-8") for i in range(20))
+
+def main(request, response):
+ token = request.GET.first(b"token", None)
+ is_query = request.GET.first(b"query", None) != None
+ with request.server.stash.lock:
+ value = request.server.stash.take(token)
+ count = 0
+ if value != None:
+ count = int(value)
+ if is_query:
+ if count < 2:
+ request.server.stash.put(token, count)
+ else:
+ count = count + 1
+ request.server.stash.put(token, count)
+
+ if is_query:
+ headers = [(b"Count", count)]
+ content = u""
+ return 200, headers, content
+ else:
+ unique_id = id_token()
+ headers = [(b"Content-Type", b"text/javascript"),
+ (b"Cache-Control", b"private, max-age=0, stale-while-revalidate=60"),
+ (b"Unique-Id", unique_id)]
+ content = b"report('%s')" % unique_id
+ return 200, headers, content
diff --git a/testing/web-platform/tests/fetch/stale-while-revalidate/revalidate-not-blocked-by-csp.html b/testing/web-platform/tests/fetch/stale-while-revalidate/revalidate-not-blocked-by-csp.html
new file mode 100644
index 0000000000..ea70b9a9c7
--- /dev/null
+++ b/testing/web-platform/tests/fetch/stale-while-revalidate/revalidate-not-blocked-by-csp.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test revalidations requests aren't blocked by CSP.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<body>
+<script>
+
+// Regression test for https://crbug.com/1070117.
+var request_token = token();
+let image_src = "resources/stale-image.py?token=" + request_token;
+
+let loadImage = async () => {
+ let img = document.createElement("img");
+ img.src = image_src;
+ let loaded = new Promise(r => img.onload = r);
+ document.body.appendChild(img);
+ await loaded;
+ return img;
+};
+
+promise_test(async t => {
+ await new Promise(r => window.onload = r);
+
+ // No CSP report must be sent from now.
+ //
+ // TODO(arthursonzogni): Some browser implementations do not support the
+ // ReportingObserver yet. Ideally, another way to access the reports should be
+ // used to test them.
+ const observer = new ReportingObserver(t.unreached_func(
+ "CSP reports aren't sent for revalidation requests"));
+ if (observer)
+ observer.observe();
+
+ let img1 = await loadImage(); // Load initial resource.
+ let img2 = loadImage(); // Request stale resource.
+
+ // Insert a <meta> CSP. This will block any image load starting from now.
+ const metaCSP = document.createElement("meta");
+ metaCSP.httpEquiv = "Content-Security-Policy";
+ metaCSP.content = "img-src 'none'";
+ document.getElementsByTagName("head")[0].appendChild(metaCSP)
+
+ // The images were requested before the <meta> CSP above was added. So they
+ // will load. Nevertheless, the resource will be stale. A revalidation request
+ // is going to be made after that.
+ assert_equals(img1.width, 16, "(initial version loaded)");
+ assert_equals((await img2).width, 16, "(stale version loaded)");
+
+ // At some point, the <img> resource is going to be revalidated. It must not
+ // be blocked nor trigger a CSP violation report.
+
+ // Query the server again and again. At some point it must have received the
+ // revalidation request. We poll, because we don't know when the revalidation
+ // will occur.
+ let query = false;
+ while(true) {
+ await new Promise(r => step_timeout(r, 25));
+ let response = await fetch(`${image_src}${query ? "&query" : ""}`);
+ let count = response.headers.get("Count");
+ if (count == "2")
+ break;
+ query ^= true;
+ }
+}, "Request revalidation aren't blocked by CSP");
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/fetch/stale-while-revalidate/stale-css.html b/testing/web-platform/tests/fetch/stale-while-revalidate/stale-css.html
new file mode 100644
index 0000000000..603a60c8bb
--- /dev/null
+++ b/testing/web-platform/tests/fetch/stale-while-revalidate/stale-css.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tests Stale While Revalidate works for css</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<body>
+<script>
+
+var request_token = token();
+let link_src = "./resources/stale-css.py?token=" + request_token;
+
+let loadLink = async() => {
+ let link = document.createElement("link");
+ link.rel = "stylesheet";
+ link.type = "text/css";
+ link.href = "resources/stale-css.py?token=" + request_token;
+ let loaded = new Promise(r => link.onload = r);
+ document.body.appendChild(link);
+ await loaded;
+ return window
+ .getComputedStyle(document.body)
+ .getPropertyValue('background-color');
+};
+
+promise_test(async t => {
+ await new Promise(r => window.onload = r);
+
+ let bgColor1 = await loadLink();
+ assert_equals(bgColor1, "rgb(0, 128, 0)", "(initial version loaded)");
+
+ let bgColor2 = await loadLink();
+ assert_equals(bgColor2, "rgb(0, 128, 0)", "(stale version loaded)");
+
+ // Query the server again and again. At some point it must have received the
+ // revalidation request. We poll, because we don't know when the revalidation
+ // will occur.
+ while(true) {
+ await new Promise(r => step_timeout(r, 25));
+ let response = await fetch(link_src + "&query");
+ let count = response.headers.get("Count");
+ if (count == '2')
+ break;
+ }
+
+ let bgColor3 = await loadLink();
+ assert_equals(bgColor3, "rgb(255, 0, 0)", "(revalidated version loaded)");
+}, 'Cache returns stale resource');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/fetch/stale-while-revalidate/stale-image.html b/testing/web-platform/tests/fetch/stale-while-revalidate/stale-image.html
new file mode 100644
index 0000000000..d86bdfbde2
--- /dev/null
+++ b/testing/web-platform/tests/fetch/stale-while-revalidate/stale-image.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tests Stale While Revalidate works for images</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<body>
+<!--
+Use a child document to load the second stale image into because
+an image loaded into the same document will skip cache-control headers.
+See: https://html.spec.whatwg.org/#the-list-of-available-images
+-->
+<iframe id="child1" srcdoc=""></iframe>
+<iframe id="child2" srcdoc=""></iframe>
+<script>
+
+var request_token = token();
+let image_src = "resources/stale-image.py?token=" + request_token;
+
+let loadImage = async (document) => {
+ let img = document.createElement("img");
+ img.src = image_src;
+ let loaded = new Promise(r => img.onload = r);
+ document.body.appendChild(img);
+ await loaded;
+ return img;
+};
+
+promise_test(async t => {
+ await new Promise(r => window.onload = r);
+
+ let img1 = await loadImage(document);
+ assert_equals(img1.width, 16, "(initial version loaded)");
+
+ let img2 = await loadImage(child1.contentDocument);
+ assert_equals(img2.width, 16, "(stale version loaded)");
+
+ // Query the server again and again. At some point it must have received the
+ // revalidation request. We poll, because we don't know when the revalidation
+ // will occur.
+ while(true) {
+ await new Promise(r => step_timeout(r, 25));
+ let response = await fetch(image_src + "&query");
+ let count = response.headers.get("Count");
+ if (count == '2')
+ break;
+ }
+
+ let img3 = await loadImage(child2.contentDocument);
+ assert_equals(img3.width, 256, "(revalidated version loaded)");
+
+}, 'Cache returns stale resource');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/fetch/stale-while-revalidate/stale-script.html b/testing/web-platform/tests/fetch/stale-while-revalidate/stale-script.html
new file mode 100644
index 0000000000..f5317482c4
--- /dev/null
+++ b/testing/web-platform/tests/fetch/stale-while-revalidate/stale-script.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tests Stale While Revalidate works for scripts</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<body>
+<script>
+
+const request_token = token();
+const script_src = "./resources/stale-script.py?token=" + request_token;
+
+// The script above will call report() via a uniquely generated ID on the
+// subresource. If it is a cache hit, the ID will be the same and
+// |last_modified_count| won't be incremented.
+let last_modified;
+let last_modified_count = 0;
+function report(mod) {
+ if (last_modified == mod)
+ return;
+ last_modified = mod;
+ last_modified_count++;
+}
+
+let loadScript = async () => {
+ let script = document.createElement("script");
+ let script_loaded = new Promise(r => script.onload = r);
+ script.src = script_src;
+ document.body.appendChild(script);
+ await script_loaded;
+};
+
+promise_test(async t => {
+ await new Promise(r => window.onload = r);
+
+ await loadScript();
+ assert_equals(last_modified_count, 1, '(initial version loaded)');
+
+ await loadScript();
+ assert_equals(last_modified_count, 1, '(stale version loaded)');
+
+ // Query the server again and again. At some point it must have received the
+ // revalidation request. We poll, because we don't know when the revalidation
+ // will occur.
+ while(true) {
+ await new Promise(r => step_timeout(r, 25));
+ let response = await fetch(script_src + "&query");
+ let count = response.headers.get("Count");
+ if (count == '2')
+ break;
+ }
+
+ await loadScript();
+ assert_equals(last_modified_count, 2, '(revalidated version loaded)');
+
+}, 'Cache returns stale resource');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/fetch/stale-while-revalidate/sw-intercept.js b/testing/web-platform/tests/fetch/stale-while-revalidate/sw-intercept.js
new file mode 100644
index 0000000000..dca7de51b0
--- /dev/null
+++ b/testing/web-platform/tests/fetch/stale-while-revalidate/sw-intercept.js
@@ -0,0 +1,14 @@
+async function broadcast(msg) {
+ for (const client of await clients.matchAll()) {
+ client.postMessage(msg);
+ }
+}
+
+self.addEventListener('fetch', event => {
+ event.waitUntil(broadcast(event.request.url));
+ event.respondWith(fetch(event.request));
+});
+
+self.addEventListener('activate', event => {
+ self.clients.claim();
+});