[ServiceWorker] Propagate change for ServiceWorkerRegistration#updateViaCache

This CL propagates change of registration's `updateViaCache` to
corresponding registration objects in the renderer process to set their
ServiceWorkerRegistration#updateViaCache attribute.

BUG=675540

Change-Id: I6bb80dacbdd6a276f7ba8eb95f9f1e5379fbf03b
Reviewed-on: https://chromium-review.googlesource.com/1002732
Reviewed-by: Makoto Shimazu <shimazu@chromium.org>
Reviewed-by: Matt Falkenhagen <falken@chromium.org>
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Commit-Queue: Matt Falkenhagen <falken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#558157}
diff --git a/service-workers/service-worker/activation.https.html b/service-workers/service-worker/activation.https.html
index 48aefd4..5755758 100644
--- a/service-workers/service-worker/activation.https.html
+++ b/service-workers/service-worker/activation.https.html
@@ -49,7 +49,7 @@
         return wait_for_state(t, registration.installing, 'installed');
       })
     .then(() => {
-        return wait_for_activation_on_dummy_scope(t);
+        return wait_for_activation_on_dummy_scope(t, self);
       })
     .then(() => {
         assert_not_equals(registration.waiting, null);
@@ -69,7 +69,7 @@
           iframe = result.iframe;
           // Finish the in-flight request.
           registration.active.postMessage('go');
-          return wait_for_activation_on_dummy_scope(t);
+          return wait_for_activation_on_dummy_scope(t, self);
         })
       .then(() => {
           // The new worker is still waiting. Remove the frame and it should
diff --git a/service-workers/service-worker/detached-context.https.html b/service-workers/service-worker/detached-context.https.html
index e70de4d..5ae4de8 100644
--- a/service-workers/service-worker/detached-context.https.html
+++ b/service-workers/service-worker/detached-context.https.html
@@ -54,7 +54,7 @@
                               () => {});
           r.update().then(() => resolvedCount += 1,
                           () => {});
-          return wait_for_activation_on_dummy_scope(t);
+          return wait_for_activation_on_dummy_scope(t, window);
         })
       .then(() => {
           assert_equals(resolvedCount, 0,
diff --git a/service-workers/service-worker/registration-updateviacache.https.html b/service-workers/service-worker/registration-updateviacache.https.html
index b1fd902..64c277d 100644
--- a/service-workers/service-worker/registration-updateviacache.https.html
+++ b/service-workers/service-worker/registration-updateviacache.https.html
@@ -100,13 +100,18 @@
         await wait_for_state(t, sw, 'activated');
         const values = await getScriptTimes(sw, testName);
 
+        const frame = await with_iframe(SCOPE);
+        const reg_in_frame = await frame.contentWindow.navigator.serviceWorker.getRegistration(normalizeURL(SCOPE));
+        assert_equals(reg_in_frame.updateViaCache, updateViaCache1 || 'imports', "reg_in_frame.updateViaCache");
+
         opts = {scope: SCOPE};
         if (updateViaCache2) opts.updateViaCache = updateViaCache2;
 
         await navigator.serviceWorker.register(fullScriptUrl, opts);
 
-        assert_equals(reg.updateViaCache, updateViaCache2 || 'imports', "reg.updateViaCache updated");
+        const expected_updateViaCache = updateViaCache2 || 'imports';
 
+        assert_equals(reg.updateViaCache, expected_updateViaCache, "reg.updateViaCache updated");
         // If the update happens via the cache, the scripts will come back byte-identical.
         // We bypass the byte-identical check if the script URL has changed, but not if
         // only the updateViaCache value has changed.
@@ -138,9 +143,44 @@
           }
         }
 
+        // Wait for all registration related tasks on |frame| to complete.
+        await wait_for_activation_on_dummy_scope(t, frame.contentWindow);
+        // The updateViaCache change should have been propagated to all
+        // corresponding JS registration objects.
+        assert_equals(reg_in_frame.updateViaCache, expected_updateViaCache, "reg_in_frame.updateViaCache updated");
+        frame.remove();
+
         await cleanup();
       }, testName);
     }
   }
 
+  // Test accessing updateViaCache of an unregistered registration.
+  for (const updateViaCache of UPDATE_VIA_CACHE_VALUES) {
+    const testName = `access-updateViaCache-after-unregister-${updateViaCache}`;
+
+    promise_test(async t => {
+      await cleanup();
+
+      const opts = {scope: SCOPE};
+
+      if (updateViaCache) opts.updateViaCache = updateViaCache;
+
+      const reg = await navigator.serviceWorker.register(
+        `${SCRIPT_URL}?test=${testName}`,
+        opts
+      );
+
+      const expected_updateViaCache = updateViaCache || 'imports';
+      assert_equals(reg.updateViaCache, expected_updateViaCache, "reg.updateViaCache");
+
+      await reg.unregister();
+
+      // Keep the original value.
+      assert_equals(reg.updateViaCache, expected_updateViaCache, "reg.updateViaCache");
+
+      await cleanup();
+    }, testName);
+  }
+
 </script>
diff --git a/service-workers/service-worker/resources/test-helpers.sub.js b/service-workers/service-worker/resources/test-helpers.sub.js
index b99ed20..8fa3e3b 100644
--- a/service-workers/service-worker/resources/test-helpers.sub.js
+++ b/service-workers/service-worker/resources/test-helpers.sub.js
@@ -264,10 +264,10 @@
 // activate, and then unregister a service worker.  When checking that
 // certain behavior does *NOT* happen, this is preferable to using an
 // arbitrary delay.
-async function wait_for_activation_on_dummy_scope(t) {
-  const script = 'resources/empty-worker.js';
+async function wait_for_activation_on_dummy_scope(t, window_or_workerglobalscope) {
+  const script = '/service-workers/service-worker/resources/empty-worker.js';
   const scope = 'resources/there/is/no/there/there?' + Date.now();
-  let registration = await navigator.serviceWorker.register(script, { scope });
+  let registration = await window_or_workerglobalscope.navigator.serviceWorker.register(script, { scope });
   await wait_for_state(t, registration.installing, 'activated');
   await registration.unregister();
 }