Add WPT for Early Hints preload is in-flight when consumed

The test page sends an Early Hints with a resource preload. The response
of the resource is delayed until the final response consumes the
resource.

The purpose of this test is to make sure the resource is added to the
document's map of preloads [1].

[1] https://github.com/whatwg/html/pull/7675

Bug: 1305896
Change-Id: I39371b41860190936991799fb6457f142e7ffef2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3545997
Reviewed-by: Yutaka Hirano <yhirano@chromium.org>
Commit-Queue: Kenichi Ishibashi <bashi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#984778}
diff --git a/loading/early-hints/preload-in-flight-when-consumed.h2.window.js b/loading/early-hints/preload-in-flight-when-consumed.h2.window.js
new file mode 100644
index 0000000..beaa45e
--- /dev/null
+++ b/loading/early-hints/preload-in-flight-when-consumed.h2.window.js
@@ -0,0 +1,11 @@
+// META: script=/common/utils.js
+// META: script=resources/early-hints-helpers.sub.js
+
+test(() => {
+    const params = new URLSearchParams();
+    const id = token();
+    params.set("resource-url", SAME_ORIGIN_RESOURCES_URL + "/delayed-js.h2.py?id=" + id);
+    params.set("resource-id", id);
+    const test_url = "resources/preload-in-flight-when-consumed.h2.py?" + params.toString();
+    window.location.replace(new URL(test_url, window.location));
+});
\ No newline at end of file
diff --git a/loading/early-hints/resources/delayed-js.h2.py b/loading/early-hints/resources/delayed-js.h2.py
new file mode 100644
index 0000000..b3d28e8
--- /dev/null
+++ b/loading/early-hints/resources/delayed-js.h2.py
@@ -0,0 +1,18 @@
+import time
+
+
+def main(request, response):
+    id = request.GET.first(b"id")
+    url_dir = u'/'.join(request.url_parts.path.split(u'/')[:-1]) + u'/'
+    # Wait until the id is set via resume-delayed-js.h2.py.
+    while True:
+        if request.server.stash.take(id, url_dir):
+            break
+        time.sleep(0.1)
+
+    headers = [
+        ("Content-Type", "text/javascript"),
+        ("Cache-Control", "max-age=600"),
+    ]
+    body = "/*empty script*/"
+    return (200, "OK"), headers, body
diff --git a/loading/early-hints/resources/preload-in-flight-when-consumed.h2.py b/loading/early-hints/resources/preload-in-flight-when-consumed.h2.py
new file mode 100644
index 0000000..c3d6616
--- /dev/null
+++ b/loading/early-hints/resources/preload-in-flight-when-consumed.h2.py
@@ -0,0 +1,24 @@
+import os
+
+
+def handle_headers(frame, request, response):
+    resource_url = request.GET.first(b"resource-url").decode()
+    link_header_value = "<{}>; rel=preload; as=script".format(resource_url)
+    early_hints = [
+        (b":status", b"103"),
+        (b"link", link_header_value),
+    ]
+    response.writer.write_raw_header_frame(headers=early_hints,
+                                           end_headers=True)
+
+    response.status = 200
+    response.headers[b"content-type"] = "text/html"
+    response.write_status_headers()
+
+
+def main(request, response):
+    current_dir = os.path.dirname(os.path.realpath(__file__))
+    file_path = os.path.join(current_dir, "preload-in-flight-when-consumed.html")
+    with open(file_path, "r") as f:
+        test_content = f.read()
+    response.writer.write_data(item=test_content, last=True)
diff --git a/loading/early-hints/resources/preload-in-flight-when-consumed.html b/loading/early-hints/resources/preload-in-flight-when-consumed.html
new file mode 100644
index 0000000..5075d92
--- /dev/null
+++ b/loading/early-hints/resources/preload-in-flight-when-consumed.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="early-hints-helpers.sub.js"></script>
+<body>
+<script>
+promise_test(async (t) => {
+    const params = new URLSearchParams(window.location.search);
+    const resource_id = params.get("resource-id");
+    const resource_url = params.get("resource-url");
+
+    const promise = fetchScript(resource_url);
+    await fetch("resume-delayed-js.h2.py?id=" + resource_id);
+    await promise;
+    assert_true(isPreloadedByEarlyHints(resource_url));
+}, "Early hints preload is in-flight when consumed.");
+</script>
+</body>
diff --git a/loading/early-hints/resources/resume-delayed-js.h2.py b/loading/early-hints/resources/resume-delayed-js.h2.py
new file mode 100644
index 0000000..f1d9ab7
--- /dev/null
+++ b/loading/early-hints/resources/resume-delayed-js.h2.py
@@ -0,0 +1,9 @@
+def main(request, response):
+    id = request.GET.first(b"id")
+    url_dir = u'/'.join(request.url_parts.path.split(u'/')[:-1]) + u'/'
+    request.server.stash.put(id, True, url_dir)
+    headers = [
+        ("Content-Type", "text/plain"),
+    ]
+    body = "OK"
+    return (200, "OK"), headers, body