[Background Sync] Add unregister().

Add unregister to the idl, update PeriodicSyncManager logic.
Add web_tests to verify unregister works as expected, and update
test expectations to reflect the updated interface.

Bug: 925297
Change-Id: I93795b2355033d244d7e56823df68dc0d3bffe86
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1670209
Commit-Queue: Mugdha Lakhani <nator@chromium.org>
Reviewed-by: Rayan Kanso <rayankans@chromium.org>
Reviewed-by: Peter Beverloo <peter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#672271}
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 3918be4..223f596 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2324,6 +2324,7 @@
   kLazyLoadImageLoadingAttributeLazy = 2935,
   kLazyLoadImageMissingDimensionsForLazy = 2936,
   kPeriodicBackgroundSyncGetTags = 2937,
+  kPeriodicBackgroundSyncUnregister = 2938,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc b/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc
index 71125bf..92344af 100644
--- a/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc
+++ b/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc
@@ -69,6 +69,25 @@
   return promise;
 }
 
+ScriptPromise PeriodicSyncManager::unregister(ScriptState* script_state,
+                                              const String& tag) {
+  if (!registration_->active()) {
+    return ScriptPromise::RejectWithDOMException(
+        script_state, MakeGarbageCollected<DOMException>(
+                          DOMExceptionCode::kInvalidStateError,
+                          "Unregister failed - no active Service Worker"));
+  }
+
+  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  ScriptPromise promise = resolver->Promise();
+
+  GetBackgroundSyncServicePtr()->Unregister(
+      registration_->RegistrationId(), tag,
+      WTF::Bind(&PeriodicSyncManager::UnregisterCallback, WrapPersistent(this),
+                WrapPersistent(resolver)));
+  return promise;
+}
+
 const mojom::blink::PeriodicBackgroundSyncServicePtr&
 PeriodicSyncManager::GetBackgroundSyncServicePtr() {
   if (!background_sync_service_.get()) {
@@ -91,8 +110,7 @@
       break;
     case mojom::blink::BackgroundSyncError::STORAGE:
       resolver->Reject(MakeGarbageCollected<DOMException>(
-          DOMExceptionCode::kUnknownError,
-          "Periodic Background Sync is disabled."));
+          DOMExceptionCode::kUnknownError, "Unknown error."));
       break;
     case mojom::blink::BackgroundSyncError::NOT_ALLOWED:
       resolver->Reject(MakeGarbageCollected<DOMException>(
@@ -132,8 +150,7 @@
       break;
     case mojom::blink::BackgroundSyncError::STORAGE:
       resolver->Reject(MakeGarbageCollected<DOMException>(
-          DOMExceptionCode::kUnknownError,
-          "Periodic Background Sync is disabled."));
+          DOMExceptionCode::kUnknownError, "Unknown error."));
       break;
     case mojom::blink::BackgroundSyncError::NO_SERVICE_WORKER:
       resolver->Reject(MakeGarbageCollected<DOMException>(
@@ -142,6 +159,29 @@
   }
 }
 
+void PeriodicSyncManager::UnregisterCallback(
+    ScriptPromiseResolver* resolver,
+    mojom::blink::BackgroundSyncError error) {
+  switch (error) {
+    case mojom::blink::BackgroundSyncError::NONE:
+      resolver->Resolve();
+      break;
+    case mojom::blink::BackgroundSyncError::NO_SERVICE_WORKER:
+      resolver->Reject(MakeGarbageCollected<DOMException>(
+          DOMExceptionCode::kUnknownError, "No service worker is active."));
+      break;
+    case mojom::blink::BackgroundSyncError::STORAGE:
+      resolver->Reject(MakeGarbageCollected<DOMException>(
+          DOMExceptionCode::kUnknownError, "Unknown error."));
+      break;
+    case mojom::blink::BackgroundSyncError::NOT_FOUND:
+    case mojom::blink::BackgroundSyncError::NOT_ALLOWED:
+    case mojom::BackgroundSyncError::PERMISSION_DENIED:
+      NOTREACHED();
+      break;
+  }
+}
+
 void PeriodicSyncManager::Trace(blink::Visitor* visitor) {
   visitor->Trace(registration_);
   ScriptWrappable::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.h b/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.h
index 4c136af..efafaef 100644
--- a/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.h
+++ b/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.h
@@ -38,6 +38,7 @@
                                      const String& tag,
                                      const BackgroundSyncOptions* options);
   ScriptPromise getTags(ScriptState* script_state);
+  ScriptPromise unregister(ScriptState* script_state, const String& tag);
 
   void Trace(blink::Visitor* visitor) override;
 
@@ -56,6 +57,8 @@
       ScriptPromiseResolver* resolver,
       mojom::blink::BackgroundSyncError error,
       WTF::Vector<mojom::blink::SyncRegistrationOptionsPtr> registrations);
+  void UnregisterCallback(ScriptPromiseResolver* resolver,
+                          mojom::blink::BackgroundSyncError error);
 
   Member<ServiceWorkerRegistration> registration_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
diff --git a/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.idl b/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.idl
index a2fb049..153c4c53 100644
--- a/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.idl
+++ b/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.idl
@@ -11,4 +11,5 @@
 ] interface PeriodicSyncManager {
     [MeasureAs=PeriodicBackgroundSyncRegister,CallWith=ScriptState,ImplementedAs=registerPeriodicSync] Promise<void> register(DOMString tag, optional BackgroundSyncOptions options);
     [MeasureAs=PeriodicBackgroundSyncGetTags, CallWith=ScriptState] Promise<sequence<DOMString>> getTags();
+    [MeasureAs=PeriodicBackgroundSyncUnregister,CallWith=ScriptState] Promise<void> unregister(DOMString tag);
 };
diff --git a/third_party/blink/web_tests/http/tests/background_sync/periodic_sync_tests.html b/third_party/blink/web_tests/http/tests/background_sync/periodic_sync_tests.html
index 0e84b6a..5f9d553f 100644
--- a/third_party/blink/web_tests/http/tests/background_sync/periodic_sync_tests.html
+++ b/third_party/blink/web_tests/http/tests/background_sync/periodic_sync_tests.html
@@ -10,7 +10,6 @@
 <script src="./resources/utils.js"></script>
 
 <script>
-
   periodicSyncTest(async (test, periodicSync) => {
     await periodicSync.register('test');
   }, 'register succeeds when no options are provided');
@@ -33,4 +32,17 @@
     assert_equals(tags[0], 'test');
   }, 'getTags works as expected');
 
+  periodicSyncTest(async (test, periodicSync) => {
+    await periodicSync.unregister('non-existent');
+  }, 'unregister succeeds when a non-existent tag is provided');
+
+  periodicSyncTest(async (test, periodicSync) => {
+    await periodicSync.register('test');
+    let tags = await periodicSync.getTags();
+    assert_equals(tags.length, 1);
+
+    await periodicSync.unregister('test');
+    tags = await periodicSync.getTags();
+    assert_equals(tags.length, 0);
+  }, 'unregister removes the specified registration');
 </script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index e649f51..989716d 100644
--- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1095,6 +1095,7 @@
     method constructor
     method getTags
     method register
+    method unregister
 interface PermissionStatus : EventTarget
     attribute @@toStringTag
     getter onchange
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index d8e7b30..1037fdf 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1029,6 +1029,7 @@
 [Worker]     method constructor
 [Worker]     method getTags
 [Worker]     method register
+[Worker]     method unregister
 [Worker] interface PermissionStatus : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter onchange
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 8d9145d..543c2222 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -5532,6 +5532,7 @@
     method constructor
     method getTags
     method register
+    method unregister
 interface PeriodicWave
     attribute @@toStringTag
     method constructor
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
index c2d279fe..5bc47e4 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -1011,6 +1011,7 @@
 [Worker]     method constructor
 [Worker]     method getTags
 [Worker]     method register
+[Worker]     method unregister
 [Worker] interface PermissionStatus : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter onchange
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 881c9a5..f4495daf 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -23772,6 +23772,7 @@
   <int value="2935" label="LazyLoadImageLoadingAttributeLazy"/>
   <int value="2936" label="LazyLoadImageMissingDimensionsForLazy"/>
   <int value="2937" label="PeriodicBackgroundSyncGetTags"/>
+  <int value="2938" label="PeriodicBackgroundSyncUnregister"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">