[ResourceTiming] Update resource_connection_reuse{.https}.html

This change updates the named test to conform to the new style we're
introducing to Resource Timing Web Platform Tests.

With this change, we're also expanding the contexts under which the test
will execute. Namely, this test will run under window, shared-worker and
dedicated-worker contexts.

Bug: 1171767
Change-Id: I7877cbb729299f37e253d9bf0c4902d76d963404
GithubIssue: https://github.com/w3c/resource-timing/issues/254
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2881221
Commit-Queue: Tom McKee <tommckee@chromium.org>
Reviewed-by: Yoav Weiss <yoavweiss@chromium.org>
Cr-Commit-Position: refs/heads/master@{#886879}
diff --git a/resource-timing/TAO-match.html b/resource-timing/TAO-match.html
index bd0e8db..a2645a6 100644
--- a/resource-timing/TAO-match.html
+++ b/resource-timing/TAO-match.html
@@ -16,12 +16,12 @@
 const path = REMOTE_ORIGIN + '/resource-timing/resources/TAOResponse.py?tao=';
 
 attribute_test(load.xhr_sync, path + 'match_origin',
-  invariants.assert_tao_pass_no_redirect,
+  invariants.assert_tao_pass_no_redirect_http,
 'The timing allow check algorithm will pass when the Timing-Allow-Origin ' +
 'header value list contains a case-sensitive match.');
 
 attribute_test(load.xhr_sync, path + 'match_wildcard',
-  invariants.assert_tao_pass_no_redirect,
+  invariants.assert_tao_pass_no_redirect_http,
 'The timing allow check algorithm will pass when the Timing-Allow-Origin ' +
 'header value list contains a wildcard.');
 
@@ -31,17 +31,17 @@
 'header value list contains a null origin.');
 
 attribute_test(load.xhr_sync, path + 'multi',
-  invariants.assert_tao_pass_no_redirect,
+  invariants.assert_tao_pass_no_redirect_http,
 'The timing allow check algorithm will pass when the Timing-Allow-Origin ' +
 'header value list contains the origin and a wildcard.');
 
 attribute_test(load.xhr_sync, path + 'multi_wildcard',
-  invariants.assert_tao_pass_no_redirect,
+  invariants.assert_tao_pass_no_redirect_http,
 'The timing allow check algorithm will pass when the Timing-Allow-Origin ' +
 'header value list contains multiple wildcards.');
 
 attribute_test(load.xhr_sync, path + 'origin',
-  invariants.assert_tao_pass_no_redirect,
+  invariants.assert_tao_pass_no_redirect_http,
 'The timing allow check algorithm will pass when the Timing-Allow-Origin ' +
 'header value contains only the origin.');
 
@@ -56,7 +56,7 @@
 'header value contains only a space.');
 
 attribute_test(load.xhr_sync, path + 'wildcard',
-  invariants.assert_tao_pass_no_redirect,
+  invariants.assert_tao_pass_no_redirect_http,
 'The timing allow check algorithm will fail when the Timing-Allow-Origin ' +
 'header value contains only a wildcard.');
 
diff --git a/resource-timing/TAO-port-mismatch-means-crossorigin.html b/resource-timing/TAO-port-mismatch-means-crossorigin.html
index 1d8b69c..f1218d1 100644
--- a/resource-timing/TAO-port-mismatch-means-crossorigin.html
+++ b/resource-timing/TAO-port-mismatch-means-crossorigin.html
@@ -32,7 +32,7 @@
                        `/resource-timing/resources/TAOResponse.py?` +
                        `tao=origin_port_${PORT}`;
 attribute_test(
-  fetch, port_match_url, invariants.assert_tao_pass_no_redirect,
+  fetch, port_match_url, invariants.assert_tao_pass_no_redirect_http,
   "An identical port must pass the TAO check");
 
 </script>
diff --git a/resource-timing/connection-reuse.html b/resource-timing/connection-reuse.html
new file mode 100644
index 0000000..e82b7bc
--- /dev/null
+++ b/resource-timing/connection-reuse.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing connection reuse</title>
+<link rel="author" title="Google" href="http://www.google.com/" />
+<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#sec-performanceresourcetiming"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/entry-invariants.js"></script>
+<script src="resources/connection-reuse-test.js"></script>
+</head>
+<body>
+<h1>Description</h1>
+<p>See <a href="resources/connection-reuse-test.js">the included test
+  script</a></p>
+</body>
+</html>
diff --git a/resource-timing/connection-reuse.https.html b/resource-timing/connection-reuse.https.html
new file mode 100644
index 0000000..e82b7bc
--- /dev/null
+++ b/resource-timing/connection-reuse.https.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing connection reuse</title>
+<link rel="author" title="Google" href="http://www.google.com/" />
+<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#sec-performanceresourcetiming"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/entry-invariants.js"></script>
+<script src="resources/connection-reuse-test.js"></script>
+</head>
+<body>
+<h1>Description</h1>
+<p>See <a href="resources/connection-reuse-test.js">the included test
+  script</a></p>
+</body>
+</html>
diff --git a/resource-timing/entry-attributes.html b/resource-timing/entry-attributes.html
index 2e95b21..689b4e7 100644
--- a/resource-timing/entry-attributes.html
+++ b/resource-timing/entry-attributes.html
@@ -14,13 +14,13 @@
   entry => {
     assert_true(entry.name.includes('#hash=1'),
       "There should be a hash in the resource name");
-    invariants.assert_tao_pass_no_redirect(entry);
+    invariants.assert_tao_pass_no_redirect_http(entry);
   },
   "Image resources should generate conformant entries");
 
 attribute_test(
   load.font, "/fonts/Ahem.ttf",
-  invariants.assert_tao_pass_no_redirect,
+  invariants.assert_tao_pass_no_redirect_http,
   "Font resources should generate conformant entries");
 
 attribute_test(
diff --git a/resource-timing/resource_connection_reuse.html b/resource-timing/resource_connection_reuse.html
deleted file mode 100644
index f347a0b..0000000
--- a/resource-timing/resource_connection_reuse.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8" />
-<title>Resource Timing connection reuse</title>
-<link rel="author" title="Google" href="http://www.google.com/" />
-<link rel="help" href="https://www.w3.org/TR/resource-timing/#dom-performanceresourcetiming-initiatortype"/>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/webperftestharness.js"></script>
-<script src="resources/webperftestharnessextension.js"></script>
-<script>
-setup({explicit_done: true});
-let iframe;
-let d;
-let body;
-
-// Explicitly test the namespace before we start testing.
-test_namespace('getEntriesByType');
-
-function setup_iframe() {
-    iframe = document.getElementById('frameContext');
-    d = iframe.contentWindow.document;
-    iframe.addEventListener('load', onload_test, false);
-}
-
-function onload_test() {
-    if (window.performance.getEntriesByType === undefined) {
-      done();
-      return;
-    }
-    const context = new PerformanceContext(iframe.contentWindow.performance);
-    const entries = context.getEntriesByType('resource');
-
-    // When a persistent connection is used, follow-on resources should be included as PerformanceResourceTiming objects.
-    test_equals(entries.length, 2, 'There should be 2 PerformanceEntries');
-
-    if (entries.length >= 2) {
-        // When a persistent connection is used, for the resource that reuses the socket, connectStart and connectEnd should have the same value as fetchStart.
-        const entry = entries[1];
-        test_equals(entry.fetchStart, entry.connectStart, 'connectStart and fetchStart should be the same');
-        test_equals(entry.fetchStart, entry.connectEnd, 'connectEnd and fetchStart should be the same');
-        if(!window.isSecureConnection) {
-            test_equals(entry.secureConnectionStart, 0, 'secureConnectionStart should be zero');
-        }
-        test_equals(entry.fetchStart, entry.domainLookupStart, 'domainLookupStart and fetchStart should be the same')
-        test_equals(entry.fetchStart, entry.domainLookupEnd, 'domainLookupEnd and fetchStart should be the same')
-    }
-
-    done();
-}
-
-window.setup_iframe = setup_iframe;
-</script>
-</head>
-<body>
-<h1>Description</h1>
-<p>This test validates that connectStart and connectEnd are the same when a connection is reused (e.g. when a persistent connection is used).</p>
-<div id="log"></div>
-<iframe id="frameContext" src="resources/fake_responses.html"></iframe>
-</body>
-</html>
diff --git a/resource-timing/resource_connection_reuse.https.html b/resource-timing/resource_connection_reuse.https.html
deleted file mode 100644
index 8686409..0000000
--- a/resource-timing/resource_connection_reuse.https.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8" />
-<title>Resource Timing connection reuse</title>
-<link rel="author" title="Google" href="http://www.google.com/" />
-<link rel="help" href="https://www.w3.org/TR/resource-timing/#dom-performanceresourcetiming-initiatortype"/>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/webperftestharness.js"></script>
-<script src="resources/webperftestharnessextension.js"></script>
-<script>
-setup({explicit_done: true});
-let iframe;
-let d;
-let body;
-
-// Explicitly test the namespace before we start testing.
-test_namespace('getEntriesByType');
-
-function setup_iframe() {
-    iframe = document.getElementById('frameContext');
-    d = iframe.contentWindow.document;
-    iframe.addEventListener('load', onload_test, false);
-}
-
-function onload_test() {
-    if (window.performance.getEntriesByType === undefined) {
-      done();
-      return;
-    }
-    const context = new PerformanceContext(iframe.contentWindow.performance);
-    const entries = context.getEntriesByType('resource');
-
-    // When a persistent connection is used, follow-on resources should be included as PerformanceResourceTiming objects.
-    test_equals(entries.length, 2, 'There should be 2 PerformanceEntries');
-
-    if (entries.length >= 2) {
-        // When a persistent connection is used, for the resource that reuses the socket, connectStart and connectEnd should have the same value as fetchStart.
-        const entry = entries[1];
-        test_equals(entry.fetchStart, entry.connectStart, 'connectStart and fetchStart should be the same');
-        test_equals(entry.fetchStart, entry.connectEnd, 'connectEnd and fetchStart should be the same');
-        test_equals(entry.fetchStart, entry.secureConnectionStart, 'secureConnectionStart and fetchStart should be the same');
-        test_equals(entry.fetchStart, entry.domainLookupStart, 'domainLookupStart and fetchStart should be the same')
-        test_equals(entry.fetchStart, entry.domainLookupEnd, 'domainLookupEnd and fetchStart should be the same')
-    }
-
-    done();
-}
-
-window.setup_iframe = setup_iframe;
-</script>
-</head>
-<body>
-<h1>Description</h1>
-<p>This test validates that connectStart and connectEnd are the same when a connection is reused (e.g. when a persistent connection is used).</p>
-<div id="log"></div>
-<iframe id="frameContext" src="resources/fake_responses.html"></iframe>
-</body>
-</html>
diff --git a/resource-timing/resources/connection-reuse-test.js b/resource-timing/resources/connection-reuse-test.js
new file mode 100644
index 0000000..4def16c
--- /dev/null
+++ b/resource-timing/resources/connection-reuse-test.js
@@ -0,0 +1,70 @@
+// This script is loaded in HTTP and HTTPS contexts to validate
+// PerformanceResourceTiming entries' attributes when reusing connections.
+
+// Make the first request before calling 'attribute_test' so that only the
+// second request's PerformanceResourceTiming entry will be interrogated.
+// We don't check the first request's PerformanceResourceTiming entry because
+// that's not what this test is trying to validate.
+//
+// Note: to ensure that we reuse the connection to fetch multiple resources,
+// we use the same XMLHttpRequest object for each request. Although it doesn't
+// seem to be specified, each browser tested by WPT will reuse the underlying
+// TCP connection with this approach. Pre-establishing the XHR's connection
+// helps us to test connection reuse also in browsers that may key their
+// connections on the related request's credentials mode.
+const client = new XMLHttpRequest();
+const identifier = Math.random();
+const path = `resources/fake_responses.py?tag=${identifier}`;
+client.open("GET", path, false);
+client.send();
+
+attribute_test(
+  async () => {
+    client.open("GET", path + "&same_resource=false", false);
+    client.send();
+
+    // We expect to get a 200 Ok response because we've requested a different
+    // resource than previous requests.
+    if (client.status != 200) {
+      throw new Error(`Got something other than a 200 response. ` +
+                      `client.status: ${client.status}`);
+    }
+  }, path, entry => {
+    invariants.assert_connection_reused(entry);
+
+    // The entry must also follow the specification for any entry corresponding
+    // to a 'typical' 200 Ok response.
+    if (self.location.protocol == 'https:') {
+      invariants.assert_tao_pass_no_redirect_https(entry);
+    } else {
+      invariants.assert_tao_pass_no_redirect_http(entry);
+    }
+  },
+  "PerformanceResrouceTiming entries need to conform to the spec when a " +
+  "distinct resource is fetched over a persistent connection");
+
+attribute_test(
+  async () => {
+    client.open("GET", path, false);
+    client.setRequestHeader("If-None-Match", identifier);
+    client.send();
+
+    // We expect to get a 304 Not Modified response because we've used a
+    // matching 'identifier' for the If-None-Match header.
+    if (client.status != 304) {
+      throw new Error(`Got something other than a 304 response. ` +
+                      `client.status: ${client.status}`);
+    }
+  }, path, entry => {
+    invariants.assert_connection_reused(entry);
+
+    // The entry must also follow the specification for any entry corresponding
+    // to a 'typical' 304 Not Modified response.
+    if (self.location.protocol == 'https:') {
+      invariants.assert_tao_pass_304_not_modified_https(entry);
+    } else {
+      invariants.assert_tao_pass_304_not_modified_http(entry);
+    }
+  },
+  "PerformanceResrouceTiming entries need to conform to the spec when the " +
+  "resource is cache-revalidated over a persistent connection");
diff --git a/resource-timing/resources/document-domain-no-impact.html b/resource-timing/resources/document-domain-no-impact.html
index bacae10..64cdd8a 100644
--- a/resource-timing/resources/document-domain-no-impact.html
+++ b/resource-timing/resources/document-domain-no-impact.html
@@ -12,15 +12,15 @@
 attribute_test_with_validator(load.iframe, path,
   el => {
     try {
-        el.contentWindow.document;
-        throw new Error("iframe document.domain was not set");
+      el.contentWindow.document;
+      throw new Error("iframe document.domain was not set");
     } catch(error) {
-        if (error.name != "SecurityError") {
-          throw(error);
-        }
+      if (error.name != "SecurityError") {
+        throw(error);
+      }
     }
   },
-  invariants.assert_tao_pass_no_redirect,
+  invariants.assert_tao_pass_no_redirect_http,
   "test that document.domain being set doesn't have an impact on the " +
   "resource timing entry."
 );
diff --git a/resource-timing/resources/entry-invariants.js b/resource-timing/resources/entry-invariants.js
index 3dc873a..88014ef 100644
--- a/resource-timing/resources/entry-invariants.js
+++ b/resource-timing/resources/entry-invariants.js
@@ -1,3 +1,13 @@
+// Asserts that the given attributes are present in 'entry' and hold equal
+// values.
+const assert_all_equal_ = (entry, attributes) => {
+  let first = attributes[0];
+  attributes.slice(1).forEach(other => {
+    assert_equals(entry[first], entry[other],
+      `${first} should be equal to ${other}`);
+  });
+}
+
 // Asserts that the given attributes are present in 'entry' and hold values
 // that are sorted in the same order as given in 'attributes'.
 const assert_ordered_ = (entry, attributes) => {
@@ -37,9 +47,9 @@
 
 const invariants = {
   // Asserts that attributes of the given PerformanceResourceTiming entry match
-  // what the spec dictates for any resource fetched without redirects but
-  // passing the Timing-Allow-Origin checks.
-  assert_tao_pass_no_redirect: entry => {
+  // what the spec dictates for any resource fetched over HTTP without
+  // redirects but passing the Timing-Allow-Origin checks.
+  assert_tao_pass_no_redirect_http: entry => {
     assert_ordered_(entry, [
       "fetchStart",
       "domainLookupStart",
@@ -70,6 +80,118 @@
     ]);
   },
 
+  // Like assert_tao_pass_no_redirect_http but for resources fetched over HTTPS
+  assert_tao_pass_no_redirect_https: entry => {
+    assert_ordered_(entry, [
+      "fetchStart",
+      "domainLookupStart",
+      "domainLookupEnd",
+      "secureConnectionStart",
+      "connectStart",
+      "connectEnd",
+      "requestStart",
+      "responseStart",
+      "responseEnd",
+    ]);
+
+    assert_zeroed_(entry, [
+      "workerStart",
+      "redirectStart",
+      "redirectEnd",
+    ]);
+
+    assert_not_negative_(entry, [
+      "duration",
+    ]);
+
+    assert_positive_(entry, [
+      "fetchStart",
+      "transferSize",
+      "encodedBodySize",
+      "decodedBodySize",
+    ]);
+  },
+
+  // Like assert_tao_pass_no_redirect_http but, since the resource's bytes
+  // won't be retransmitted, the encoded and decoded sizes must be zero.
+  assert_tao_pass_304_not_modified_http: entry => {
+    assert_ordered_(entry, [
+      "fetchStart",
+      "domainLookupStart",
+      "domainLookupEnd",
+      "connectStart",
+      "connectEnd",
+      "requestStart",
+      "responseStart",
+      "responseEnd",
+    ]);
+
+    assert_zeroed_(entry, [
+      "workerStart",
+      "secureConnectionStart",
+      "redirectStart",
+      "redirectEnd",
+      "encodedBodySize",
+      "decodedBodySize",
+    ]);
+
+    assert_not_negative_(entry, [
+      "duration",
+    ]);
+
+    assert_positive_(entry, [
+      "fetchStart",
+      "transferSize",
+    ]);
+  },
+
+  // Like assert_tao_pass_304_not_modified_http but for resources fetched over
+  // HTTPS.
+  assert_tao_pass_304_not_modified_https: entry => {
+    assert_ordered_(entry, [
+      "fetchStart",
+      "domainLookupStart",
+      "domainLookupEnd",
+      "secureConnectionStart",
+      "connectStart",
+      "connectEnd",
+      "requestStart",
+      "responseStart",
+      "responseEnd",
+    ]);
+
+    assert_zeroed_(entry, [
+      "workerStart",
+      "redirectStart",
+      "redirectEnd",
+      "encodedBodySize",
+      "decodedBodySize",
+    ]);
+
+    assert_not_negative_(entry, [
+      "duration",
+    ]);
+
+    assert_positive_(entry, [
+      "fetchStart",
+      "transferSize",
+    ]);
+  },
+
+  // Asserts that attributes of the given PerformanceResourceTiming entry match
+  // what the spec dictates for any resource subsequently fetched over a
+  // persistent connection. When this happens, we expect that certain
+  // attributes describing transport layer behaviour will be equal.
+  assert_connection_reused: entry => {
+    assert_all_equal_(entry, [
+      "fetchStart",
+      "connectStart",
+      "connectEnd",
+      "domainLookupStart",
+      "domainLookupEnd",
+    ]);
+  },
+
   // Asserts that attributes of the given PerformanceResourceTiming entry match
   // what the spec dictates for any resource fetched over HTTP through an HTTP
   // redirect.
@@ -94,7 +216,7 @@
   // Asserts that attributes of the given PerformanceResourceTiming entry match
   // what the spec dictates for any resource fetched over HTTPS through a
   // cross-origin redirect.
-  // (e.g. GET http://remote.com/foo => 304 Location: https://remote.com/foo)
+  // (e.g. GET http://remote.com/foo => 302 Location: https://remote.com/foo)
   assert_cross_origin_redirected_resource: entry => {
     assert_zeroed_(entry, [
       "redirectStart",