summaryrefslogtreecommitdiffstats
path: root/content/browser
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser')
-rw-r--r--content/browser/background_sync/background_sync_browsertest.cc96
-rw-r--r--content/browser/background_sync/background_sync_manager.cc94
-rw-r--r--content/browser/background_sync/background_sync_manager.h14
-rw-r--r--content/browser/background_sync/background_sync_manager_unittest.cc222
-rw-r--r--content/browser/background_sync/background_sync_registration.cc41
-rw-r--r--content/browser/background_sync/background_sync_registration.h14
-rw-r--r--content/browser/background_sync/background_sync_registration_handle.cc9
-rw-r--r--content/browser/background_sync/background_sync_registration_handle.h12
-rw-r--r--content/browser/background_sync/background_sync_service_impl.cc25
-rw-r--r--content/browser/background_sync/background_sync_service_impl.h5
-rw-r--r--content/browser/background_sync/background_sync_service_impl_unittest.cc61
11 files changed, 584 insertions, 9 deletions
diff --git a/content/browser/background_sync/background_sync_browsertest.cc b/content/browser/background_sync/background_sync_browsertest.cc
index 9fe51e5..47fd6e0 100644
--- a/content/browser/background_sync/background_sync_browsertest.cc
+++ b/content/browser/background_sync/background_sync_browsertest.cc
@@ -163,6 +163,9 @@ class BackgroundSyncBrowserTest : public ContentBrowserTest {
bool GetRegistrationsOneShot(const std::vector<std::string>& expected_tags);
bool CompleteDelayedOneShot();
bool RejectDelayedOneShot();
+ bool NotifyWhenDoneOneShot(const std::string& tag);
+ bool NotifyWhenDoneImmediateOneShot(const std::string& expected_msg);
+ bool StoreRegistrationOneShot(const std::string& tag);
private:
scoped_ptr<net::SpawnedTestServer> https_server_;
@@ -276,6 +279,27 @@ bool BackgroundSyncBrowserTest::RejectDelayedOneShot() {
return script_result == BuildExpectedResult("delay", "rejecting");
}
+bool BackgroundSyncBrowserTest::NotifyWhenDoneOneShot(const std::string& tag) {
+ EXPECT_TRUE(content::ExecuteScript(
+ shell_->web_contents(), BuildScriptString("notifyWhenDoneOneShot", tag)));
+ return PopConsole(BuildExpectedResult(tag, "done"));
+}
+
+bool BackgroundSyncBrowserTest::NotifyWhenDoneImmediateOneShot(
+ const std::string& expected_msg) {
+ std::string script_result;
+ EXPECT_TRUE(RunScript("notifyWhenDoneImmediateOneShot()", &script_result));
+ return script_result == expected_msg;
+}
+
+bool BackgroundSyncBrowserTest::StoreRegistrationOneShot(
+ const std::string& tag) {
+ std::string script_result;
+ EXPECT_TRUE(
+ RunScript(BuildScriptString("storeRegistration", tag), &script_result));
+ return script_result == BuildExpectedResult(tag, "stored");
+}
+
IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, OneShotFires) {
EXPECT_TRUE(RegisterServiceWorker());
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
@@ -421,6 +445,78 @@ IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, UnregisterMidSync) {
EXPECT_TRUE(PopConsole("ok - unregister completed"));
}
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, CallDoneBeforeSyncSucceeds) {
+ EXPECT_TRUE(RegisterServiceWorker());
+ EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
+
+ SetOnline(false);
+ EXPECT_TRUE(RegisterOneShot("foo"));
+ EXPECT_TRUE(NotifyWhenDoneOneShot("foo"));
+
+ SetOnline(true);
+ // The ordering of PopConsole messages tells us that the event fired
+ // before done resolved.
+ EXPECT_TRUE(PopConsole("foo fired"));
+ EXPECT_TRUE(PopConsole("foo done result: true"));
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, CallDoneBeforeSyncFails) {
+ EXPECT_TRUE(RegisterServiceWorker());
+ EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
+
+ SetOnline(true);
+ EXPECT_TRUE(RegisterOneShot("delay"));
+ EXPECT_FALSE(OneShotPending("delay"));
+ EXPECT_TRUE(NotifyWhenDoneOneShot("delay"));
+
+ EXPECT_TRUE(RejectDelayedOneShot());
+ // The ordering of PopConsole messages tells us that the event fired
+ // before done resolved.
+ EXPECT_TRUE(PopConsole("ok - delay rejected"));
+ EXPECT_TRUE(PopConsole("delay done result: false"));
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, CallDoneAfterSyncSuceeds) {
+ EXPECT_TRUE(RegisterServiceWorker());
+ EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
+
+ SetOnline(false);
+ EXPECT_TRUE(RegisterOneShot("foo"));
+ EXPECT_TRUE(StoreRegistrationOneShot("foo"));
+
+ SetOnline(true);
+ EXPECT_TRUE(PopConsole("foo fired"));
+ EXPECT_FALSE(GetRegistrationOneShot("foo"));
+ EXPECT_TRUE(NotifyWhenDoneImmediateOneShot("ok - foo result: true"));
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
+ CallDoneAfterSyncUnregistered) {
+ EXPECT_TRUE(RegisterServiceWorker());
+ EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
+
+ SetOnline(false);
+ EXPECT_TRUE(RegisterOneShot("foo"));
+ EXPECT_TRUE(StoreRegistrationOneShot("foo"));
+ EXPECT_TRUE(UnregisterOneShot("foo"));
+ EXPECT_FALSE(GetRegistrationOneShot("foo"));
+ EXPECT_TRUE(NotifyWhenDoneImmediateOneShot("ok - foo result: false"));
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, CallDoneAfterSyncFails) {
+ EXPECT_TRUE(RegisterServiceWorker());
+ EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
+
+ SetOnline(true);
+ EXPECT_TRUE(RegisterOneShot("delay"));
+ EXPECT_FALSE(OneShotPending("delay"));
+ EXPECT_TRUE(StoreRegistrationOneShot("delay"));
+
+ EXPECT_TRUE(RejectDelayedOneShot());
+ EXPECT_TRUE(PopConsole("ok - delay rejected"));
+ EXPECT_TRUE(NotifyWhenDoneImmediateOneShot("ok - delay result: false"));
+}
+
} // namespace
} // namespace content
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index 938a87b..3e28bf3 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -703,7 +703,7 @@ void BackgroundSyncManager::UnregisterImpl(
return;
}
- const RefCountedRegistration* existing_registration =
+ RefCountedRegistration* existing_registration =
LookupActiveRegistration(sw_registration_id, registration_key);
if (!existing_registration ||
@@ -715,6 +715,24 @@ void BackgroundSyncManager::UnregisterImpl(
return;
}
+ DCHECK(!existing_registration->value()->HasCompleted());
+
+ bool firing = existing_registration->value()->sync_state() ==
+ BACKGROUND_SYNC_STATE_FIRING ||
+ existing_registration->value()->sync_state() ==
+ BACKGROUND_SYNC_STATE_UNREGISTERED_WHILE_FIRING;
+
+ existing_registration->value()->set_sync_state(
+ firing ? BACKGROUND_SYNC_STATE_UNREGISTERED_WHILE_FIRING
+ : BACKGROUND_SYNC_STATE_UNREGISTERED);
+
+ if (!firing) {
+ // If the registration is currently firing then wait to run
+ // RunDoneCallbacks until after it has finished as it might
+ // change state to SUCCESS first.
+ existing_registration->value()->RunDoneCallbacks();
+ }
+
RemoveActiveRegistration(sw_registration_id, registration_key);
StoreRegistrations(sw_registration_id,
@@ -754,6 +772,69 @@ void BackgroundSyncManager::UnregisterDidStore(int64 sw_registration_id,
FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_OK));
}
+void BackgroundSyncManager::NotifyWhenDone(
+ BackgroundSyncRegistrationHandle::HandleId handle_id,
+ const StatusAndStateCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR,
+ BACKGROUND_SYNC_STATE_FAILED));
+ return;
+ }
+
+ scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle =
+ DuplicateRegistrationHandle(handle_id);
+
+ op_scheduler_.ScheduleOperation(
+ base::Bind(&BackgroundSyncManager::NotifyWhenDoneImpl,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(registration_handle.Pass()), callback));
+}
+
+void BackgroundSyncManager::NotifyWhenDoneImpl(
+ scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle,
+ const StatusAndStateCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_EQ(SYNC_ONE_SHOT, registration_handle->options()->periodicity);
+
+ if (disabled_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR,
+ BACKGROUND_SYNC_STATE_FAILED));
+ return;
+ }
+
+ if (!registration_handle->registration()->HasCompleted()) {
+ registration_handle->registration()->AddDoneCallback(
+ base::Bind(&BackgroundSyncManager::NotifyWhenDoneDidFinish,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+ op_scheduler_.CompleteOperationAndRunNext();
+ return;
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_OK,
+ registration_handle->sync_state()));
+ op_scheduler_.CompleteOperationAndRunNext();
+}
+
+void BackgroundSyncManager::NotifyWhenDoneDidFinish(
+ const StatusAndStateCallback& callback,
+ BackgroundSyncState sync_state) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (disabled_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR,
+ BACKGROUND_SYNC_STATE_FAILED));
+ return;
+ }
+
+ callback.Run(BACKGROUND_SYNC_STATUS_OK, sync_state);
+}
+
void BackgroundSyncManager::GetRegistrationImpl(
int64 sw_registration_id,
const RegistrationKey& registration_key,
@@ -1025,10 +1106,19 @@ void BackgroundSyncManager::EventCompleteImpl(
if (registration->options()->periodicity == SYNC_ONE_SHOT) {
if (status_code != SERVICE_WORKER_OK) {
- // TODO(jkarlin) Fire the sync event on the next page load controlled by
+ // TODO(jkarlin): Insert retry logic here. Be sure to check if the state
+ // is UNREGISTERED_WHILE_FIRING first. If so then set the state to failed
+ // if it was already out of retry attempts otherwise keep the state as
+ // unregistered. Then call RunDoneCallbacks(); (crbug.com/501838)
+ // TODO(jkarlin): Fire the sync event on the next page load controlled
+ // by
// this registration. (crbug.com/479665)
registration->set_sync_state(BACKGROUND_SYNC_STATE_FAILED);
+ registration->RunDoneCallbacks();
} else {
+ registration->set_sync_state(BACKGROUND_SYNC_STATE_SUCCESS);
+ registration->RunDoneCallbacks();
+
RegistrationKey key(*registration);
// Remove the registration if it's still active.
RefCountedRegistration* active_registration =
diff --git a/content/browser/background_sync/background_sync_manager.h b/content/browser/background_sync/background_sync_manager.h
index 673f41f..285f68b 100644
--- a/content/browser/background_sync/background_sync_manager.h
+++ b/content/browser/background_sync/background_sync_manager.h
@@ -21,6 +21,7 @@
#include "content/browser/cache_storage/cache_storage_scheduler.h"
#include "content/browser/service_worker/service_worker_context_observer.h"
#include "content/browser/service_worker/service_worker_storage.h"
+#include "content/common/background_sync_service.mojom.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "url/gurl.h"
@@ -53,6 +54,8 @@ class CONTENT_EXPORT BackgroundSyncManager
using StatusAndRegistrationCallback =
base::Callback<void(BackgroundSyncStatus,
scoped_ptr<BackgroundSyncRegistrationHandle>)>;
+ using StatusAndStateCallback =
+ base::Callback<void(BackgroundSyncStatus, BackgroundSyncState)>;
using StatusAndRegistrationsCallback = base::Callback<void(
BackgroundSyncStatus,
scoped_ptr<ScopedVector<BackgroundSyncRegistrationHandle>>)>;
@@ -242,6 +245,17 @@ class CONTENT_EXPORT BackgroundSyncManager
const StatusCallback& callback,
ServiceWorkerStatusCode status);
+ // NotifyWhenDone and its callbacks. See
+ // BackgroundSyncRegistrationHandle::NotifyWhenDone for detailed
+ // documentation.
+ void NotifyWhenDone(BackgroundSyncRegistrationHandle::HandleId handle_id,
+ const StatusAndStateCallback& callback);
+ void NotifyWhenDoneImpl(
+ scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle,
+ const StatusAndStateCallback& callback);
+ void NotifyWhenDoneDidFinish(const StatusAndStateCallback& callback,
+ BackgroundSyncState status);
+
// GetRegistration callbacks
void GetRegistrationImpl(int64 sw_registration_id,
const RegistrationKey& registration_key,
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc
index d073b06..d8cd693 100644
--- a/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -82,6 +82,16 @@ void OneShotDelayedCallback(
*out_callback = callback;
}
+void NotifyWhenDoneCallback(bool* was_called,
+ BackgroundSyncStatus* out_status,
+ BackgroundSyncState* out_state,
+ BackgroundSyncStatus status,
+ BackgroundSyncState state) {
+ *was_called = true;
+ *out_status = status;
+ *out_state = state;
+}
+
class TestPowerSource : public base::PowerMonitorSource {
public:
void GeneratePowerStateEvent(bool on_battery_power) {
@@ -1023,6 +1033,218 @@ TEST_F(BackgroundSyncManagerTest, OneShotFiresOnRegistration) {
EXPECT_FALSE(GetRegistration(sync_options_1_));
}
+TEST_F(BackgroundSyncManagerTest, NotifyWhenDoneAfterEventSuccess) {
+ InitSyncEventTest();
+
+ EXPECT_TRUE(Register(sync_options_1_));
+ EXPECT_EQ(1, sync_events_called_);
+
+ bool notify_done_called = false;
+ BackgroundSyncStatus status = BACKGROUND_SYNC_STATUS_OK;
+ BackgroundSyncState sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
+ callback_registration_handle_->NotifyWhenDone(base::Bind(
+ &NotifyWhenDoneCallback, &notify_done_called, &status, &sync_state));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(notify_done_called);
+ EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, status);
+ EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, sync_state);
+}
+
+TEST_F(BackgroundSyncManagerTest, NotifyWhenDoneBeforeEventSuccess) {
+ InitDelayedSyncEventTest();
+
+ RegisterAndVerifySyncEventDelayed(sync_options_1_);
+
+ bool notify_done_called = false;
+ BackgroundSyncStatus status = BACKGROUND_SYNC_STATUS_OK;
+ BackgroundSyncState sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
+ callback_registration_handle_->NotifyWhenDone(base::Bind(
+ &NotifyWhenDoneCallback, &notify_done_called, &status, &sync_state));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(notify_done_called);
+
+ // Finish firing the event.
+ sync_fired_callback_.Run(SERVICE_WORKER_OK);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_TRUE(notify_done_called);
+ EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, status);
+ EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, sync_state);
+}
+
+TEST_F(BackgroundSyncManagerTest,
+ NotifyWhenDoneBeforeUnregisteredEventSuccess) {
+ InitDelayedSyncEventTest();
+
+ RegisterAndVerifySyncEventDelayed(sync_options_1_);
+
+ bool notify_done_called = false;
+ BackgroundSyncStatus status = BACKGROUND_SYNC_STATUS_OK;
+ BackgroundSyncState sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
+ callback_registration_handle_->NotifyWhenDone(base::Bind(
+ &NotifyWhenDoneCallback, &notify_done_called, &status, &sync_state));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(notify_done_called);
+
+ // Unregistering should set the state to UNREGISTERED but done shouldn't
+ // be called until the event finishes firing, at which point its state should
+ // be SUCCESS.
+ EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
+ EXPECT_FALSE(GetRegistration(sync_options_1_));
+
+ // Finish firing the event.
+ sync_fired_callback_.Run(SERVICE_WORKER_OK);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_TRUE(notify_done_called);
+ EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, status);
+ EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, sync_state);
+}
+
+TEST_F(BackgroundSyncManagerTest,
+ NotifyWhenDoneBeforeUnregisteredEventFailure) {
+ InitDelayedSyncEventTest();
+
+ RegisterAndVerifySyncEventDelayed(sync_options_1_);
+
+ bool notify_done_called = false;
+ BackgroundSyncStatus status = BACKGROUND_SYNC_STATUS_OK;
+ BackgroundSyncState sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
+ callback_registration_handle_->NotifyWhenDone(base::Bind(
+ &NotifyWhenDoneCallback, &notify_done_called, &status, &sync_state));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(notify_done_called);
+
+ // Unregistering should set the state to UNREGISTERED but done shouldn't
+ // be called until the event finishes firing, at which point its state should
+ // be FAILED.
+ EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
+ EXPECT_FALSE(GetRegistration(sync_options_1_));
+
+ // Finish firing the event.
+ sync_fired_callback_.Run(SERVICE_WORKER_ERROR_FAILED);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_TRUE(notify_done_called);
+ EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, status);
+ EXPECT_EQ(BACKGROUND_SYNC_STATE_FAILED, sync_state);
+}
+
+TEST_F(BackgroundSyncManagerTest, NotifyWhenDoneBeforeUnregisteredEventFires) {
+ InitSyncEventTest();
+
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_TRUE(Register(sync_options_1_));
+ EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
+
+ bool notify_done_called = false;
+ BackgroundSyncStatus status = BACKGROUND_SYNC_STATUS_OK;
+ BackgroundSyncState sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
+ callback_registration_handle_->NotifyWhenDone(base::Bind(
+ &NotifyWhenDoneCallback, &notify_done_called, &status, &sync_state));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(notify_done_called);
+ EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, status);
+ EXPECT_EQ(BACKGROUND_SYNC_STATE_UNREGISTERED, sync_state);
+}
+
+TEST_F(BackgroundSyncManagerTest,
+ NotifyWhenDoneBeforeEventSuccessDroppedHandle) {
+ InitDelayedSyncEventTest();
+
+ RegisterAndVerifySyncEventDelayed(sync_options_1_);
+
+ bool notify_done_called = false;
+ BackgroundSyncStatus status = BACKGROUND_SYNC_STATUS_OK;
+ BackgroundSyncState sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
+
+ callback_registration_handle_->NotifyWhenDone(base::Bind(
+ &NotifyWhenDoneCallback, &notify_done_called, &status, &sync_state));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(notify_done_called);
+
+ // Drop the client's handle to the registration before the event fires, ensure
+ // that the done callback is still run.
+ callback_registration_handle_ = nullptr;
+
+ // Finish firing the event.
+ sync_fired_callback_.Run(SERVICE_WORKER_OK);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_TRUE(notify_done_called);
+ EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, status);
+ EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, sync_state);
+}
+
+TEST_F(BackgroundSyncManagerTest, NotifyWhenDoneAfterEventFailure) {
+ InitFailedSyncEventTest();
+
+ EXPECT_TRUE(Register(sync_options_1_));
+ EXPECT_EQ(1, sync_events_called_);
+
+ bool notify_done_called = false;
+ BackgroundSyncStatus status = BACKGROUND_SYNC_STATUS_OK;
+ BackgroundSyncState sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
+ callback_registration_handle_->NotifyWhenDone(base::Bind(
+ &NotifyWhenDoneCallback, &notify_done_called, &status, &sync_state));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(notify_done_called);
+ EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, status);
+ EXPECT_EQ(BACKGROUND_SYNC_STATE_FAILED, sync_state);
+}
+
+TEST_F(BackgroundSyncManagerTest, NotifyWhenDoneBeforeEventFailure) {
+ InitDelayedSyncEventTest();
+
+ RegisterAndVerifySyncEventDelayed(sync_options_1_);
+
+ bool notify_done_called = false;
+ BackgroundSyncStatus status = BACKGROUND_SYNC_STATUS_OK;
+ BackgroundSyncState sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
+ callback_registration_handle_->NotifyWhenDone(base::Bind(
+ &NotifyWhenDoneCallback, &notify_done_called, &status, &sync_state));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(notify_done_called);
+
+ // Finish firing the event.
+ sync_fired_callback_.Run(SERVICE_WORKER_ERROR_FAILED);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(notify_done_called);
+ EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, status);
+ EXPECT_EQ(BACKGROUND_SYNC_STATE_FAILED, sync_state);
+}
+
+TEST_F(BackgroundSyncManagerTest, NotifyWhenDoneAfterUnregistered) {
+ EXPECT_TRUE(Register(sync_options_1_));
+ EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
+
+ bool notify_done_called = false;
+ BackgroundSyncStatus status = BACKGROUND_SYNC_STATUS_OK;
+ BackgroundSyncState sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
+ callback_registration_handle_->NotifyWhenDone(base::Bind(
+ &NotifyWhenDoneCallback, &notify_done_called, &status, &sync_state));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(notify_done_called);
+ EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, status);
+ EXPECT_EQ(BACKGROUND_SYNC_STATE_UNREGISTERED, sync_state);
+}
+
+TEST_F(BackgroundSyncManagerTest, NotifyWhenDoneBeforeUnregistered) {
+ Register(sync_options_1_);
+ bool notify_done_called = false;
+ BackgroundSyncStatus status = BACKGROUND_SYNC_STATUS_OK;
+ BackgroundSyncState sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
+ callback_registration_handle_->NotifyWhenDone(base::Bind(
+ &NotifyWhenDoneCallback, &notify_done_called, &status, &sync_state));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(notify_done_called);
+
+ EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
+ EXPECT_TRUE(notify_done_called);
+ EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, status);
+ EXPECT_EQ(BACKGROUND_SYNC_STATE_UNREGISTERED, sync_state);
+}
+
// TODO(jkarlin): Change this to a periodic test as one-shots can't be power
// dependent according to spec.
TEST_F(BackgroundSyncManagerTest, OneShotFiresOnPowerChange) {
diff --git a/content/browser/background_sync/background_sync_registration.cc b/content/browser/background_sync/background_sync_registration.cc
index d6a122c..30bbf9e 100644
--- a/content/browser/background_sync/background_sync_registration.cc
+++ b/content/browser/background_sync/background_sync_registration.cc
@@ -4,6 +4,12 @@
#include "content/browser/background_sync/background_sync_registration.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+
namespace content {
const BackgroundSyncRegistration::RegistrationId
@@ -12,6 +18,9 @@ const BackgroundSyncRegistration::RegistrationId
const BackgroundSyncRegistration::RegistrationId
BackgroundSyncRegistration::kInitialId = 0;
+BackgroundSyncRegistration::BackgroundSyncRegistration() = default;
+BackgroundSyncRegistration::~BackgroundSyncRegistration() = default;
+
bool BackgroundSyncRegistration::Equals(
const BackgroundSyncRegistration& other) const {
return options_.Equals(other.options_);
@@ -21,4 +30,36 @@ bool BackgroundSyncRegistration::IsValid() const {
return id_ != kInvalidRegistrationId;
}
+void BackgroundSyncRegistration::AddDoneCallback(
+ const StateCallback& callback) {
+ DCHECK(!HasCompleted());
+ notify_done_callbacks_.push_back(callback);
+}
+
+void BackgroundSyncRegistration::RunDoneCallbacks() {
+ DCHECK(HasCompleted());
+
+ for (auto& callback : notify_done_callbacks_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, sync_state_));
+ }
+
+ notify_done_callbacks_.clear();
+}
+
+bool BackgroundSyncRegistration::HasCompleted() const {
+ switch (sync_state_) {
+ case BACKGROUND_SYNC_STATE_PENDING:
+ case BACKGROUND_SYNC_STATE_FIRING:
+ case BACKGROUND_SYNC_STATE_UNREGISTERED_WHILE_FIRING:
+ return false;
+ case BACKGROUND_SYNC_STATE_FAILED:
+ case BACKGROUND_SYNC_STATE_SUCCESS:
+ case BACKGROUND_SYNC_STATE_UNREGISTERED:
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
} // namespace content
diff --git a/content/browser/background_sync/background_sync_registration.h b/content/browser/background_sync/background_sync_registration.h
index 91f5ded..741c888 100644
--- a/content/browser/background_sync/background_sync_registration.h
+++ b/content/browser/background_sync/background_sync_registration.h
@@ -5,6 +5,9 @@
#ifndef CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_REGISTRATION_H_
#define CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_REGISTRATION_H_
+#include <list>
+
+#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "content/browser/background_sync/background_sync.pb.h"
@@ -18,13 +21,18 @@ namespace content {
class CONTENT_EXPORT BackgroundSyncRegistration {
public:
using RegistrationId = int64_t;
+ using StateCallback = base::Callback<void(BackgroundSyncState)>;
+
static const RegistrationId kInitialId;
- BackgroundSyncRegistration() = default;
- ~BackgroundSyncRegistration() = default;
+ BackgroundSyncRegistration();
+ ~BackgroundSyncRegistration();
bool Equals(const BackgroundSyncRegistration& other) const;
bool IsValid() const;
+ void AddDoneCallback(const StateCallback& callback);
+ void RunDoneCallbacks();
+ bool HasCompleted() const;
const BackgroundSyncRegistrationOptions* options() const { return &options_; }
BackgroundSyncRegistrationOptions* options() { return &options_; }
@@ -42,6 +50,8 @@ class CONTENT_EXPORT BackgroundSyncRegistration {
RegistrationId id_ = kInvalidRegistrationId;
BackgroundSyncState sync_state_ = BACKGROUND_SYNC_STATE_PENDING;
+ std::list<StateCallback> notify_done_callbacks_;
+
DISALLOW_COPY_AND_ASSIGN(BackgroundSyncRegistration);
};
diff --git a/content/browser/background_sync/background_sync_registration_handle.cc b/content/browser/background_sync/background_sync_registration_handle.cc
index ff89cca..4e5e8e8 100644
--- a/content/browser/background_sync/background_sync_registration_handle.cc
+++ b/content/browser/background_sync/background_sync_registration_handle.cc
@@ -26,6 +26,15 @@ void BackgroundSyncRegistrationHandle::Unregister(
sw_registration_id, options()->periodicity, handle_id_, callback);
}
+void BackgroundSyncRegistrationHandle::NotifyWhenDone(
+ const StatusAndStateCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(IsValid());
+ DCHECK(background_sync_manager_);
+
+ background_sync_manager_->NotifyWhenDone(handle_id_, callback);
+}
+
bool BackgroundSyncRegistrationHandle::IsValid() const {
return registration_ != nullptr;
}
diff --git a/content/browser/background_sync/background_sync_registration_handle.h b/content/browser/background_sync/background_sync_registration_handle.h
index 564bd58..f2915d1 100644
--- a/content/browser/background_sync/background_sync_registration_handle.h
+++ b/content/browser/background_sync/background_sync_registration_handle.h
@@ -10,6 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "content/browser/background_sync/background_sync_registration.h"
#include "content/browser/background_sync/background_sync_status.h"
+#include "content/common/background_sync_service.mojom.h"
#include "content/common/content_export.h"
namespace content {
@@ -25,6 +26,8 @@ class CONTENT_EXPORT BackgroundSyncRegistrationHandle {
public:
using HandleId = int;
using StatusCallback = base::Callback<void(BackgroundSyncStatus)>;
+ using StatusAndStateCallback =
+ base::Callback<void(BackgroundSyncStatus, BackgroundSyncState)>;
~BackgroundSyncRegistrationHandle();
@@ -42,6 +45,15 @@ class CONTENT_EXPORT BackgroundSyncRegistrationHandle {
// with BACKGROUND_SYNC_STATUS_OK if it succeeds.
void Unregister(int64_t service_worker_id, const StatusCallback& callback);
+ // Runs |callback| when the registration associated with |handle_id|
+ // completes.The provided status is BACKGROUND_SYNC_STATUS_OK if the operation
+ // succeeded. The provided state is BACKGROUND_SYNC_STATE_SUCCESS on success,
+ // BACKGRUOND_SYNC_STATE_FAILED on final failure, and
+ // BACKGROUND_SYNC_STATE_UNREGISTERED if the registration was unregistered
+ // before it could complete. NotifyWhenDone should only be called for
+ // SYNC_ONE_SHOT registrations.
+ void NotifyWhenDone(const StatusAndStateCallback& callback);
+
// Returns true if the handle is backed by a BackgroundSyncRegistration in the
// BackgroundSyncManager.
bool IsValid() const;
diff --git a/content/browser/background_sync/background_sync_service_impl.cc b/content/browser/background_sync/background_sync_service_impl.cc
index 9f51f9a..b8c03df 100644
--- a/content/browser/background_sync/background_sync_service_impl.cc
+++ b/content/browser/background_sync/background_sync_service_impl.cc
@@ -227,6 +227,23 @@ void BackgroundSyncServiceImpl::ReleaseRegistration(
active_handles_.Remove(handle_id);
}
+void BackgroundSyncServiceImpl::NotifyWhenDone(
+ BackgroundSyncRegistrationHandle::HandleId handle_id,
+ const NotifyWhenDoneCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BackgroundSyncRegistrationHandle* registration =
+ active_handles_.Lookup(handle_id);
+ if (!registration) {
+ callback.Run(BACKGROUND_SYNC_ERROR_NOT_ALLOWED,
+ BACKGROUND_SYNC_STATE_FAILED);
+ return;
+ }
+
+ registration->NotifyWhenDone(
+ base::Bind(&BackgroundSyncServiceImpl::OnNotifyWhenDoneResult,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
void BackgroundSyncServiceImpl::OnRegisterResult(
const RegisterCallback& callback,
BackgroundSyncStatus status,
@@ -271,4 +288,12 @@ void BackgroundSyncServiceImpl::OnGetRegistrationsResult(
mojo_registrations.Pass());
}
+void BackgroundSyncServiceImpl::OnNotifyWhenDoneResult(
+ const NotifyWhenDoneCallback& callback,
+ BackgroundSyncStatus status,
+ BackgroundSyncState sync_state) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ callback.Run(static_cast<content::BackgroundSyncError>(status), sync_state);
+}
+
} // namespace content
diff --git a/content/browser/background_sync/background_sync_service_impl.h b/content/browser/background_sync/background_sync_service_impl.h
index 7e17b7f..f00c668 100644
--- a/content/browser/background_sync/background_sync_service_impl.h
+++ b/content/browser/background_sync/background_sync_service_impl.h
@@ -53,6 +53,8 @@ class CONTENT_EXPORT BackgroundSyncServiceImpl
const DuplicateRegistrationHandleCallback& callback) override;
void ReleaseRegistration(
BackgroundSyncRegistrationHandle::HandleId handle_id) override;
+ void NotifyWhenDone(BackgroundSyncRegistrationHandle::HandleId handle_id,
+ const NotifyWhenDoneCallback& callback) override;
void OnRegisterResult(const RegisterCallback& callback,
BackgroundSyncStatus status,
@@ -63,6 +65,9 @@ class CONTENT_EXPORT BackgroundSyncServiceImpl
const GetRegistrationsCallback& callback,
BackgroundSyncStatus status,
scoped_ptr<ScopedVector<BackgroundSyncRegistrationHandle>> result);
+ void OnNotifyWhenDoneResult(const NotifyWhenDoneCallback& callback,
+ BackgroundSyncStatus status,
+ BackgroundSyncState sync_state);
// Called when an error is detected on binding_.
void OnConnectionError();
diff --git a/content/browser/background_sync/background_sync_service_impl_unittest.cc b/content/browser/background_sync/background_sync_service_impl_unittest.cc
index 346bdd1..ca2e45c 100644
--- a/content/browser/background_sync/background_sync_service_impl_unittest.cc
+++ b/content/browser/background_sync/background_sync_service_impl_unittest.cc
@@ -59,6 +59,16 @@ void ErrorAndRegistrationCallback(bool* called,
*out_registration = registration.Clone();
}
+void ErrorAndStateCallback(bool* called,
+ BackgroundSyncError* out_error,
+ BackgroundSyncState* out_state,
+ BackgroundSyncError error,
+ BackgroundSyncState state) {
+ *called = true;
+ *out_error = error;
+ *out_state = state;
+}
+
void ErrorCallback(bool* called,
BackgroundSyncError* out_error,
BackgroundSyncError error) {
@@ -197,11 +207,11 @@ class BackgroundSyncServiceImplTest : public testing::Test {
}
void UnregisterOneShot(
- SyncRegistrationPtr sync,
+ int32 handle_id,
const BackgroundSyncService::UnregisterCallback& callback) {
service_impl_->Unregister(
BackgroundSyncPeriodicity::BACKGROUND_SYNC_PERIODICITY_ONE_SHOT,
- sync->handle_id, sw_registration_id_, callback);
+ handle_id, sw_registration_id_, callback);
base::RunLoop().RunUntilIdle();
}
@@ -222,6 +232,13 @@ class BackgroundSyncServiceImplTest : public testing::Test {
base::RunLoop().RunUntilIdle();
}
+ void NotifyWhenDone(
+ int32 handle_id,
+ const BackgroundSyncService::NotifyWhenDoneCallback& callback) {
+ service_impl_->NotifyWhenDone(handle_id, callback);
+ base::RunLoop().RunUntilIdle();
+ }
+
scoped_ptr<TestBrowserThreadBundle> thread_bundle_;
scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
scoped_ptr<EmbeddedWorkerTestHelper> embedded_worker_helper_;
@@ -292,7 +309,7 @@ TEST_F(BackgroundSyncServiceImplTest, Unregister) {
BackgroundSyncError unregister_error;
SyncRegistrationPtr reg;
UnregisterOneShot(
- default_sync_registration_.Clone(),
+ default_sync_registration_->handle_id,
base::Bind(&ErrorCallback, &unregister_called, &unregister_error));
EXPECT_TRUE(unregister_called);
EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NOT_ALLOWED,
@@ -310,8 +327,9 @@ TEST_F(BackgroundSyncServiceImplTest, UnregisterWithRegisteredSync) {
&register_error, &reg));
EXPECT_TRUE(register_called);
EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NONE, register_error);
- UnregisterOneShot(reg.Pass(), base::Bind(&ErrorCallback, &unregister_called,
- &unregister_error));
+ UnregisterOneShot(
+ reg->handle_id,
+ base::Bind(&ErrorCallback, &unregister_called, &unregister_error));
EXPECT_TRUE(unregister_called);
EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NONE, unregister_error);
}
@@ -379,4 +397,37 @@ TEST_F(BackgroundSyncServiceImplTest, GetRegistrationsWithRegisteredSync) {
EXPECT_EQ(1UL, array_size);
}
+TEST_F(BackgroundSyncServiceImplTest, NotifyWhenDone) {
+ // Register a sync event.
+ bool register_called = false;
+ BackgroundSyncError register_error;
+ SyncRegistrationPtr reg;
+ RegisterOneShot(default_sync_registration_.Clone(),
+ base::Bind(&ErrorAndRegistrationCallback, &register_called,
+ &register_error, &reg));
+ EXPECT_TRUE(register_called);
+ EXPECT_EQ(BACKGROUND_SYNC_ERROR_NONE, register_error);
+
+ // Unregister it.
+ bool unregister_called = false;
+ BackgroundSyncError unregister_error;
+ UnregisterOneShot(
+ reg->handle_id,
+ base::Bind(&ErrorCallback, &unregister_called, &unregister_error));
+ EXPECT_TRUE(unregister_called);
+ EXPECT_EQ(BACKGROUND_SYNC_ERROR_NONE, unregister_error);
+
+ // Call NotifyWhenDone and verify that it calls back with unregistered.
+ bool notify_done_called = false;
+ BackgroundSyncError notify_done_error = BACKGROUND_SYNC_ERROR_NONE;
+ BackgroundSyncState notify_done_sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
+
+ NotifyWhenDone(reg->handle_id,
+ base::Bind(&ErrorAndStateCallback, &notify_done_called,
+ &notify_done_error, &notify_done_sync_state));
+ EXPECT_TRUE(notify_done_called);
+ EXPECT_EQ(BACKGROUND_SYNC_ERROR_NONE, notify_done_error);
+ EXPECT_EQ(BACKGROUND_SYNC_STATE_UNREGISTERED, notify_done_sync_state);
+}
+
} // namespace content