Bug 1592991 [wpt PR 20018] - Add Web Platform Tests for the Split Cache, a=testonly
authorBlink WPT Bot <blink-w3c-test-autoroller@chromium.org>
Mon, 25 Nov 2019 19:09:18 +0000
changeset 504498 85b0b1f0e7d819f9672392bbe932bfccc489f12f
parent 504497 03831919b6612dc05bf9d28c9050f001504dc952
child 504499 66ea8382f1c22bb7b31ba030df72f95222844d63
push id101897
push userwptsync@mozilla.com
push dateFri, 29 Nov 2019 11:10:32 +0000
treeherderautoland@47be1b3fdda6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1592991, 20018, 981970, 1890952, 714236
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1592991 [wpt PR 20018] - Add Web Platform Tests for the Split Cache, a=testonly Automatic update from web-platform-tests Add Web Platform Tests for the Split Cache (#20018) We add a web platform test for the cache when it is partitioned by top- frame origin. The test caches a resource, then attempts to load it in a popup window. With the split cache, if the popup window is cross-origin, we would expect that request to be a cache miss. We compare the number of requests that hit the server to our expectations. To enable these tests, the existing framework is slightly refactored, including to respond to CORS preflight requests. The virtual test suites virtual/split-http-cache and virtual/not-split-http-cache explicitly test the cases of a split and not-split cache, respectively. The default test is disabled as its result depends on whether the split cache feature is enabled. Bug: 981970 Change-Id: I049fdaec4aebcbdeebdd3c77d13d6ca420d1bd62 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1890952 Reviewed-by: Yutaka Hirano <yhirano@chromium.org> Reviewed-by: Shivani Sharma <shivanisha@chromium.org> Commit-Queue: Alex Turner <alexmt@chromium.org> Cr-Commit-Position: refs/heads/master@{#714236} -- wpt-commits: a1be16d3d955a0dc8f71e259c54b2afd54725355 wpt-pr: 20018
testing/web-platform/tests/fetch/http-cache/http-cache.js
testing/web-platform/tests/fetch/http-cache/resources/http-cache.py
testing/web-platform/tests/fetch/http-cache/resources/split-origin-popup.html
testing/web-platform/tests/fetch/http-cache/split-cache.tentative.html
--- a/testing/web-platform/tests/fetch/http-cache/http-cache.js
+++ b/testing/web-platform/tests/fetch/http-cache/http-cache.js
@@ -37,16 +37,22 @@ const templates = {
 }
 
 const noBodyStatus = new Set([204, 304])
 
 function makeTest (test) {
   return function () {
     var uuid = token()
     var requests = expandTemplates(test)
+    var fetchFunctions = makeFetchFunctions(requests, uuid)
+    return runTest(fetchFunctions, requests, uuid)
+  }
+}
+
+function makeFetchFunctions(requests, uuid) {
     var fetchFunctions = []
     for (let i = 0; i < requests.length; ++i) {
       fetchFunctions.push({
         code: function (idx) {
           var config = requests[idx]
           var url = makeTestUrl(uuid, config)
           var init = fetchInit(requests, config)
           return fetch(url, init)
@@ -57,16 +63,20 @@ function makeTest (test) {
               } else {
                 throw reason
               }
             })
         },
         pauseAfter: 'pause_after' in requests[i]
       })
     }
+    return fetchFunctions
+}
+
+function runTest(fetchFunctions, requests, uuid) {
     var idx = 0
     function runNextStep () {
       if (fetchFunctions.length) {
         var nextFetchFunction = fetchFunctions.shift()
         if (nextFetchFunction.pauseAfter === true) {
           return nextFetchFunction.code(idx++)
             .then(pause)
             .then(runNextStep)
@@ -81,17 +91,16 @@ function makeTest (test) {
 
     return runNextStep()
       .then(function () {
         return getServerState(uuid)
       }).then(function (testState) {
         checkRequests(requests, testState)
         return Promise.resolve()
       })
-  }
 }
 
 function expandTemplates (test) {
   var rawRequests = test.requests
   var requests = []
   for (let i = 0; i < rawRequests.length; i++) {
     var request = rawRequests[i]
     request.name = test.name
@@ -221,20 +230,24 @@ function pause () {
     step_timeout(function () {
       return resolve()
     }, 3000)
   })
 }
 
 function makeTestUrl (uuid, config) {
   var arg = ''
+  var base_url = ''
+  if ('base_url' in config) {
+    base_url = config.base_url
+  }
   if ('query_arg' in config) {
     arg = `&target=${config.query_arg}`
   }
-  return `resources/http-cache.py?dispatch=test&uuid=${uuid}${arg}`
+  return `${base_url}resources/http-cache.py?dispatch=test&uuid=${uuid}${arg}`
 }
 
 function getServerState (uuid) {
   return fetch(`resources/http-cache.py?dispatch=state&uuid=${uuid}`)
     .then(function (response) {
       return response.text()
     }).then(function (text) {
       return JSON.parse(text) || []
--- a/testing/web-platform/tests/fetch/http-cache/resources/http-cache.py
+++ b/testing/web-platform/tests/fetch/http-cache/resources/http-cache.py
@@ -8,28 +8,39 @@ from base64 import b64decode
 NOTEHDRS = set(['content-type', 'access-control-allow-origin', 'last-modified', 'etag'])
 NOBODYSTATUS = set([204, 304])
 LOCATIONHDRS = set(['location', 'content-location'])
 DATEHDRS = set(['date', 'expires', 'last-modified'])
 
 def main(request, response):
     dispatch = request.GET.first("dispatch", None)
     uuid = request.GET.first("uuid", None)
+
+    if request.method == "OPTIONS":
+        return handle_preflight(uuid, request, response)
     if not uuid:
         response.status = (404, "Not Found")
         response.headers.set("Content-Type", "text/plain")
         return "UUID not found"
     if dispatch == 'test':
         return handle_test(uuid, request, response)
     elif dispatch == 'state':
         return handle_state(uuid, request, response)
     response.status = (404, "Not Found")
     response.headers.set("Content-Type", "text/plain")
     return "Fallthrough"
 
+def handle_preflight(uuid, request, response):
+    response.status = (200, "OK")
+    response.headers.set("Access-Control-Allow-Origin", "*")
+    response.headers.set("Access-Control-Allow-Methods", "GET")
+    response.headers.set("Access-Control-Allow-Headers", "*")
+    response.headers.set("Access-Control-Max-Age", "86400")
+    return "Preflight request"
+
 def handle_state(uuid, request, response):
     response.headers.set("Content-Type", "text/plain")
     return json.dumps(request.server.stash.take(uuid))
 
 def handle_test(uuid, request, response):
     server_state = request.server.stash.take(uuid) or []
     try:
         requests = json.loads(b64decode(request.headers.get('Test-Requests', "")))
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/fetch/http-cache/resources/split-origin-popup.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>HTTP Cache - helper</title>
+  <meta name="help" href="https://fetch.spec.whatwg.org/#request">
+  <meta name="timeout" content="normal">
+  <script src="/resources/testharness.js"></script>
+  <script src="../http-cache.js"></script>
+</head>
+<body>
+<script>
+   window.addEventListener("message", function listener(event) {
+      window.removeEventListener("message", listener)
+
+      var fetchFunction = makeFetchFunctions(event.data.requests, event.data.uuid)[event.data.index]
+      fetchFunction.code(event.data.index).then(
+         function(response) {
+            event.source.postMessage("success", event.origin)
+         },
+         function(response) {
+            event.source.postMessage("success", event.origin)
+         }
+      )
+   })
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/fetch/http-cache/split-cache.tentative.html
@@ -0,0 +1,118 @@
+<!doctype html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>HTTP Cache - Partioning by top-level origin</title>
+  <meta name="help" href="https://fetch.spec.whatwg.org/#request">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/utils.js"></script>
+  <script src="/common/get-host-info.sub.js"></script>
+  <script src="http-cache.js"></script>
+</head>
+<body>
+<script>
+const host = get_host_info();
+
+// We run this entire test twice: first with a same-origin then with a cross-origin popup
+function performFullTest(is_same_origin_test) {
+  const POPUP_HTTP_ORIGIN = is_same_origin_test ? host.HTTP_ORIGIN : host.HTTP_REMOTE_ORIGIN
+  const LOCAL_HTTP_ORIGIN = host.HTTP_ORIGIN
+
+  const popupBaseURL = POPUP_HTTP_ORIGIN + window.location.pathname.replace(/\/[^\/]*$/, '/') ;
+  const localBaseURL = LOCAL_HTTP_ORIGIN + window.location.pathname.replace(/\/[^\/]*$/, '/') ;
+
+  var test = {
+    name: "HTTP Cache is partitioned by top-frame origin",
+    requests: [
+      {
+        response_headers: [
+              ["Expires", (30 * 24 * 60 * 60)]
+            ],
+        base_url: localBaseURL
+      },
+      {
+        base_url: localBaseURL
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "no-cache"]
+        ],
+        // If the popup's request was a cache hit, we would only expect 2
+        // requests to the server. If it was a cache miss, we would expect 3.
+        expected_response_headers: [
+          ["server-request-count", is_same_origin_test ? "2" : "3"]
+        ],
+        base_url: localBaseURL
+      }
+    ]
+  }
+
+  var uuid = token()
+  var local_requests = expandTemplates(test)
+  var fetchFns = makeFetchFunctions(local_requests, uuid)
+
+  var popup_requests = expandTemplates(test)
+
+  // Request the resource with a long cache expiry
+  function local_fetch() {
+    return fetchFns[0].code(0)
+  }
+
+  function popup_fetch() {
+    return new Promise(function(resolve, reject) {
+      var win = window.open(popupBaseURL + "resources/split-origin-popup.html")
+
+      // Post a message to intisearchte the popup's request and give the necessary
+      // information. Posted researchtedly to account for dropped messages as the
+      // popup is loading.
+      function postMessage(event) {
+        var payload = {
+          index: 1,
+          requests: popup_requests,
+          uuid: uuid
+        }
+        win.postMessage(payload, POPUP_HTTP_ORIGIN)
+      }
+      var messagePoster = setInterval(postMessage, 100)
+
+      // Listen for the result
+      function messageListener(event) {
+        if (event.origin !== POPUP_HTTP_ORIGIN) {
+          reject("Unknown error")
+        } else if (event.data === "success") {
+          resolve()
+        } else if (event.data === "error") {
+          reject("Error in popup")
+        } else {
+          return; // Ignore testharness.js internal messages
+        }
+        window.removeEventListener("message", messageListener)
+        clearInterval(messagePoster)
+        win.close()
+      }
+      window.addEventListener("message", messageListener)
+    })
+  }
+
+  function local_fetch2() {
+    return fetchFns[2].code(2)
+  }
+
+  // Final checks.
+  function check_server_info() {
+    return getServerState(uuid)
+      .then(function (testState) {
+        checkRequests(local_requests, testState)
+        return Promise.resolve()
+      })
+  }
+
+  promise_test(() => local_fetch().then(popup_fetch).then(local_fetch2).then(check_server_info))
+}
+
+performFullTest(true);
+performFullTest(false);
+</script>
+</body>
+</html>
\ No newline at end of file