summaryrefslogtreecommitdiffstats
path: root/content/browser/background_sync
diff options
context:
space:
mode:
authorjkarlin <jkarlin@chromium.org>2015-04-03 09:46:44 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-03 16:47:23 +0000
commit9059304cb5c6f7f683ea30259eeacc5a429566c9 (patch)
treed320b71723b483898a4d6e61d4ee8579e47af4d8 /content/browser/background_sync
parentd4c3a502cc21b8e2f7d37b0508278f3445196f5d (diff)
downloadchromium_src-9059304cb5c6f7f683ea30259eeacc5a429566c9.zip
chromium_src-9059304cb5c6f7f683ea30259eeacc5a429566c9.tar.gz
chromium_src-9059304cb5c6f7f683ea30259eeacc5a429566c9.tar.bz2
[BackgroundSync] Handle storage failure
This CL introduces proper failure handling in case the storage backend fails. Changes: 1. If the ServiceWorker is unregistered - Remove the sync registrations from memory 2. If the ServiceWorkerStorage is wiped - Reinit the BackgroundSyncManager 3. If reading or writing from ServiceWorkerStorage fails (SERVICE_WORKER_ERROR_FAILURE) - Delete everything and disable the BackgroundSyncManager until browser restart. Added unittests for above cases. I had to change the unittest to register serviceworkers via the ServiceWorkerContext instead of directly in Storage so that the ServiceWorkerContextObserver receives updates. BUG=449443 Review URL: https://codereview.chromium.org/1048053002 Cr-Commit-Position: refs/heads/master@{#323756}
Diffstat (limited to 'content/browser/background_sync')
-rw-r--r--content/browser/background_sync/background_sync_manager.cc236
-rw-r--r--content/browser/background_sync/background_sync_manager.h45
-rw-r--r--content/browser/background_sync/background_sync_manager_unittest.cc291
3 files changed, 438 insertions, 134 deletions
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index 7ea194f..d67aa7d 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -46,6 +46,7 @@ scoped_ptr<BackgroundSyncManager> BackgroundSyncManager::Create(
}
BackgroundSyncManager::~BackgroundSyncManager() {
+ service_worker_context_->RemoveObserver(this);
}
void BackgroundSyncManager::Register(
@@ -57,13 +58,17 @@ void BackgroundSyncManager::Register(
DCHECK_EQ(BackgroundSyncRegistration::kInvalidRegistrationId,
sync_registration.id);
- StatusAndRegistrationCallback pending_callback =
- base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback,
- weak_ptr_factory_.GetWeakPtr(), callback);
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
op_scheduler_.ScheduleOperation(base::Bind(
&BackgroundSyncManager::RegisterImpl, weak_ptr_factory_.GetWeakPtr(),
- origin, sw_registration_id, sync_registration, pending_callback));
+ origin, sw_registration_id, sync_registration,
+ MakeStatusAndRegistrationCompletion(callback)));
}
void BackgroundSyncManager::Unregister(
@@ -74,14 +79,16 @@ void BackgroundSyncManager::Unregister(
const StatusCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- StatusCallback pending_callback =
- base::Bind(&BackgroundSyncManager::PendingStatusCallback,
- weak_ptr_factory_.GetWeakPtr(), callback);
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
+ return;
+ }
op_scheduler_.ScheduleOperation(base::Bind(
&BackgroundSyncManager::UnregisterImpl, weak_ptr_factory_.GetWeakPtr(),
origin, sw_registration_id, sync_registration_name, sync_registration_id,
- pending_callback));
+ MakeStatusCompletion(callback)));
}
void BackgroundSyncManager::GetRegistration(
@@ -91,43 +98,82 @@ void BackgroundSyncManager::GetRegistration(
const StatusAndRegistrationCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- StatusAndRegistrationCallback pending_callback =
- base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback,
- weak_ptr_factory_.GetWeakPtr(), callback);
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
+ op_scheduler_.ScheduleOperation(base::Bind(
+ &BackgroundSyncManager::GetRegistrationImpl,
+ weak_ptr_factory_.GetWeakPtr(), origin, sw_registration_id,
+ sync_registration_name, MakeStatusAndRegistrationCompletion(callback)));
+}
+
+void BackgroundSyncManager::OnRegistrationDeleted(int64 registration_id,
+ const GURL& pattern) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Operations already in the queue will either fail when they write to storage
+ // or return stale results based on registrations loaded in memory. This is
+ // inconsequential since the service worker is gone.
+ op_scheduler_.ScheduleOperation(base::Bind(
+ &BackgroundSyncManager::OnRegistrationDeletedImpl,
+ weak_ptr_factory_.GetWeakPtr(), registration_id, MakeEmptyCompletion()));
+}
+void BackgroundSyncManager::OnStorageWiped() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // Operations already in the queue will either fail when they write to storage
+ // or return stale results based on registrations loaded in memory. This is
+ // inconsequential since the service workers are gone.
op_scheduler_.ScheduleOperation(
- base::Bind(&BackgroundSyncManager::GetRegistrationImpl,
- weak_ptr_factory_.GetWeakPtr(), origin, sw_registration_id,
- sync_registration_name, pending_callback));
+ base::Bind(&BackgroundSyncManager::OnStorageWipedImpl,
+ weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion()));
}
BackgroundSyncManager::BackgroundSyncManager(
const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
- : service_worker_context_(service_worker_context), weak_ptr_factory_(this) {
+ : service_worker_context_(service_worker_context),
+ disabled_(false),
+ weak_ptr_factory_(this) {
+ service_worker_context_->AddObserver(this);
}
void BackgroundSyncManager::Init() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!op_scheduler_.ScheduledOperations());
+ DCHECK(!disabled_);
op_scheduler_.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr(),
+ MakeEmptyCompletion()));
}
-void BackgroundSyncManager::InitImpl() {
+void BackgroundSyncManager::InitImpl(const base::Closure& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
GetDataFromBackend(
kBackgroundSyncUserDataKey,
base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr(), callback));
}
void BackgroundSyncManager::InitDidGetDataFromBackend(
+ const base::Closure& callback,
const std::vector<std::pair<int64, std::string>>& user_data,
ServiceWorkerStatusCode status) {
- if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND)
- LOG(ERROR) << "Background Sync Failed to load from backend.";
+ if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
+ LOG(ERROR) << "BackgroundSync failed to init due to backend failure.";
+ DisableAndClearManager(base::Bind(callback));
+ return;
+ }
bool corruption_detected = false;
for (const std::pair<int64, std::string>& data : user_data) {
@@ -163,12 +209,13 @@ void BackgroundSyncManager::InitDidGetDataFromBackend(
if (corruption_detected) {
LOG(ERROR) << "Corruption detected in background sync backend";
- sw_to_registrations_map_.clear();
+ DisableAndClearManager(base::Bind(callback));
+ return;
}
// TODO(jkarlin): Call the scheduling algorithm here.
- op_scheduler_.CompleteOperationAndRunNext();
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
}
void BackgroundSyncManager::RegisterImpl(
@@ -176,6 +223,13 @@ void BackgroundSyncManager::RegisterImpl(
int64 sw_registration_id,
const BackgroundSyncRegistration& sync_registration,
const StatusAndRegistrationCallback& callback) {
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
BackgroundSyncRegistration existing_registration;
if (LookupRegistration(sw_registration_id, sync_registration.name,
&existing_registration)) {
@@ -198,7 +252,54 @@ void BackgroundSyncManager::RegisterImpl(
origin, sw_registration_id,
base::Bind(&BackgroundSyncManager::RegisterDidStore,
weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
- new_registration, existing_registration, callback));
+ new_registration, callback));
+}
+
+void BackgroundSyncManager::DisableAndClearManager(
+ const base::Closure& callback) {
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
+ disabled_ = true;
+ sw_to_registrations_map_.clear();
+
+ // Delete all backend entries. The memory representation of registered syncs
+ // may be out of sync with storage (e.g., due to corruption detection on
+ // loading from storage), so reload the registrations from storage again.
+ GetDataFromBackend(
+ kBackgroundSyncUserDataKey,
+ base::Bind(&BackgroundSyncManager::DisableAndClearDidGetRegistrations,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void BackgroundSyncManager::DisableAndClearDidGetRegistrations(
+ const base::Closure& callback,
+ const std::vector<std::pair<int64, std::string>>& user_data,
+ ServiceWorkerStatusCode status) {
+ if (status != SERVICE_WORKER_OK || user_data.empty()) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
+ base::Closure barrier_closure =
+ base::BarrierClosure(user_data.size(), base::Bind(callback));
+
+ for (const auto& sw_id_and_regs : user_data) {
+ service_worker_context_->context()->storage()->ClearUserData(
+ sw_id_and_regs.first, kBackgroundSyncUserDataKey,
+ base::Bind(&BackgroundSyncManager::DisableAndClearManagerClearedOne,
+ weak_ptr_factory_.GetWeakPtr(), barrier_closure));
+ }
+}
+
+void BackgroundSyncManager::DisableAndClearManagerClearedOne(
+ const base::Closure& barrier_closure,
+ ServiceWorkerStatusCode status) {
+ // The status doesn't matter at this point, there is nothing else to be done.
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(barrier_closure));
}
bool BackgroundSyncManager::LookupRegistration(
@@ -255,24 +356,25 @@ void BackgroundSyncManager::StoreRegistrations(
void BackgroundSyncManager::RegisterDidStore(
int64 sw_registration_id,
const BackgroundSyncRegistration& new_registration,
- const BackgroundSyncRegistration& previous_registration,
const StatusAndRegistrationCallback& callback,
ServiceWorkerStatusCode status) {
- if (status != SERVICE_WORKER_OK) {
- // Restore the previous state.
- if (previous_registration.id !=
- BackgroundSyncRegistration::kInvalidRegistrationId) {
- AddRegistrationToMap(sw_registration_id, previous_registration);
- } else {
- RemoveRegistrationFromMap(sw_registration_id, new_registration.name,
- nullptr);
- }
+ if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
+ // The registration is gone.
+ sw_to_registrations_map_.erase(sw_registration_id);
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
return;
}
+ if (status != SERVICE_WORKER_OK) {
+ LOG(ERROR) << "BackgroundSync failed to store registration due to backend "
+ "failure.";
+ DisableAndClearManager(
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
// TODO(jkarlin): Run the registration algorithm.
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, new_registration));
@@ -334,6 +436,12 @@ void BackgroundSyncManager::UnregisterImpl(
const std::string& sync_registration_name,
BackgroundSyncRegistration::RegistrationId sync_registration_id,
const StatusCallback& callback) {
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
+ return;
+ }
+
BackgroundSyncRegistration existing_registration;
if (!LookupRegistration(sw_registration_id, sync_registration_name,
&existing_registration) ||
@@ -359,14 +467,20 @@ void BackgroundSyncManager::UnregisterDidStore(
const BackgroundSyncRegistration& old_sync_registration,
const StatusCallback& callback,
ServiceWorkerStatusCode status) {
- if (status != SERVICE_WORKER_OK) {
- // Restore the previous state.
- AddRegistrationToMap(sw_registration_id, old_sync_registration);
+ if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
+ // ServiceWorker was unregistered.
+ sw_to_registrations_map_.erase(sw_registration_id);
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
return;
}
+ if (status != SERVICE_WORKER_OK) {
+ LOG(ERROR) << "BackgroundSync failed to unregister due to backend failure.";
+ DisableAndClearManager(base::Bind(callback, ERROR_TYPE_STORAGE));
+ return;
+ }
+
// TODO(jkarlin): Run the registration algorithm.
base::MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(callback, ERROR_TYPE_OK));
@@ -377,6 +491,13 @@ void BackgroundSyncManager::GetRegistrationImpl(
int64 sw_registration_id,
const std::string sync_registration_name,
const StatusAndRegistrationCallback& callback) {
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
BackgroundSyncRegistration out_registration;
if (!LookupRegistration(sw_registration_id, sync_registration_name,
&out_registration)) {
@@ -390,6 +511,21 @@ void BackgroundSyncManager::GetRegistrationImpl(
FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, out_registration));
}
+void BackgroundSyncManager::OnRegistrationDeletedImpl(
+ int64 registration_id,
+ const base::Closure& callback) {
+ // The backend (ServiceWorkerStorage) will delete the data, so just delete the
+ // memory representation here.
+ sw_to_registrations_map_.erase(registration_id);
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+}
+
+void BackgroundSyncManager::OnStorageWipedImpl(const base::Closure& callback) {
+ sw_to_registrations_map_.clear();
+ disabled_ = false;
+ InitImpl(callback);
+}
+
void BackgroundSyncManager::PendingStatusAndRegistrationCallback(
const StatusAndRegistrationCallback& callback,
ErrorType error,
@@ -411,4 +547,32 @@ void BackgroundSyncManager::PendingStatusCallback(
op_scheduler_.CompleteOperationAndRunNext();
}
+void BackgroundSyncManager::PendingClosure(const base::Closure& callback) {
+ // The callback might delete this object, so hang onto a weak ptr to find out.
+ base::WeakPtr<BackgroundSyncManager> manager = weak_ptr_factory_.GetWeakPtr();
+ callback.Run();
+ if (manager)
+ op_scheduler_.CompleteOperationAndRunNext();
+}
+
+base::Closure BackgroundSyncManager::MakeEmptyCompletion() {
+ return base::Bind(&BackgroundSyncManager::PendingClosure,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Bind(base::DoNothing));
+}
+
+BackgroundSyncManager::StatusAndRegistrationCallback
+BackgroundSyncManager::MakeStatusAndRegistrationCompletion(
+ const StatusAndRegistrationCallback& callback) {
+ return base::Bind(
+ &BackgroundSyncManager::PendingStatusAndRegistrationCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+}
+
+BackgroundSyncManager::StatusCallback
+BackgroundSyncManager::MakeStatusCompletion(const StatusCallback& callback) {
+ return base::Bind(&BackgroundSyncManager::PendingStatusCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+}
+
} // namespace content
diff --git a/content/browser/background_sync/background_sync_manager.h b/content/browser/background_sync/background_sync_manager.h
index 40bbb55..2ba2da1 100644
--- a/content/browser/background_sync/background_sync_manager.h
+++ b/content/browser/background_sync/background_sync_manager.h
@@ -12,6 +12,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#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/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
@@ -36,9 +37,8 @@ class ServiceWorkerContextWrapper;
// registered events.
// TODO(jkarlin): Keep the browser alive if "Let Google Chrome Run in the
// Background" is true and a sync is registered.
-// TODO(jkarlin): Unregister syncs when storage for an origin is cleared.
-// TODO(jkarlin): Detect and handle a corrupt or broken backend.
-class CONTENT_EXPORT BackgroundSyncManager {
+class CONTENT_EXPORT BackgroundSyncManager
+ : NON_EXPORTED_BASE(public ServiceWorkerContextObserver) {
public:
enum ErrorType {
ERROR_TYPE_OK = 0,
@@ -88,7 +88,7 @@ class CONTENT_EXPORT BackgroundSyncManager {
static scoped_ptr<BackgroundSyncManager> Create(
const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context);
- virtual ~BackgroundSyncManager();
+ ~BackgroundSyncManager() override;
// Stores the given background sync registration and adds it to the scheduling
// queue. Overwrites any existing registration with the same name but
@@ -121,6 +121,11 @@ class CONTENT_EXPORT BackgroundSyncManager {
const std::string sync_registration_name,
const StatusAndRegistrationCallback& callback);
+ // ServiceWorkerContextObserver overrides.
+ void OnRegistrationDeleted(int64 registration_id,
+ const GURL& pattern) override;
+ void OnStorageWiped() override;
+
protected:
explicit BackgroundSyncManager(
const scoped_refptr<ServiceWorkerContextWrapper>& context);
@@ -144,6 +149,19 @@ class CONTENT_EXPORT BackgroundSyncManager {
using PermissionStatusCallback = base::Callback<void(bool)>;
using SWIdToRegistrationsMap = std::map<int64, BackgroundSyncRegistrations>;
+ // Disable the manager. Already queued operations will abort once they start
+ // to run (in their impl methods). Future operations will not queue. Any
+ // registrations are cleared from memory and the backend (if it's still
+ // functioning). The manager will reenable itself once it receives the
+ // OnStorageWiped message or on browser restart.
+ void DisableAndClearManager(const base::Closure& callback);
+ void DisableAndClearDidGetRegistrations(
+ const base::Closure& callback,
+ const std::vector<std::pair<int64, std::string>>& user_data,
+ ServiceWorkerStatusCode status);
+ void DisableAndClearManagerClearedOne(const base::Closure& barrier_closure,
+ ServiceWorkerStatusCode status);
+
// Returns the existing registration in |existing_registration| if it is not
// null.
bool LookupRegistration(int64 sw_registration_id,
@@ -165,8 +183,9 @@ class CONTENT_EXPORT BackgroundSyncManager {
int64 sw_registration_id,
const BackgroundSyncRegistration& sync_registration);
- void InitImpl();
+ void InitImpl(const base::Closure& callback);
void InitDidGetDataFromBackend(
+ const base::Closure& callback,
const std::vector<std::pair<int64, std::string>>& user_data,
ServiceWorkerStatusCode status);
@@ -177,7 +196,6 @@ class CONTENT_EXPORT BackgroundSyncManager {
const StatusAndRegistrationCallback& callback);
void RegisterDidStore(int64 sw_registration_id,
const BackgroundSyncRegistration& sync_registration,
- const BackgroundSyncRegistration& previous_registration,
const StatusAndRegistrationCallback& callback,
ServiceWorkerStatusCode status);
@@ -200,16 +218,31 @@ class CONTENT_EXPORT BackgroundSyncManager {
const std::string sync_registration_name,
const StatusAndRegistrationCallback& callback);
+ // OnRegistrationDeleted callbacks
+ void OnRegistrationDeletedImpl(int64 registration_id,
+ const base::Closure& callback);
+
+ // OnStorageWiped callbacks
+ void OnStorageWipedImpl(const base::Closure& callback);
+
// Operation Scheduling callbacks
void PendingStatusAndRegistrationCallback(
const StatusAndRegistrationCallback& callback,
ErrorType error,
const BackgroundSyncRegistration& sync_registration);
void PendingStatusCallback(const StatusCallback& callback, ErrorType error);
+ void PendingClosure(const base::Closure& closure);
+
+ StatusAndRegistrationCallback MakeStatusAndRegistrationCompletion(
+ const StatusAndRegistrationCallback& callback);
+ BackgroundSyncManager::StatusCallback MakeStatusCompletion(
+ const StatusCallback& callback);
+ base::Closure MakeEmptyCompletion();
SWIdToRegistrationsMap sw_to_registrations_map_;
CacheStorageScheduler op_scheduler_;
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
+ bool disabled_;
base::WeakPtrFactory<BackgroundSyncManager> weak_ptr_factory_;
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc
index c47651a..d2f420a 100644
--- a/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -9,19 +9,41 @@
#include "base/run_loop.h"
#include "base/thread_task_runner_handle.h"
#include "content/browser/browser_thread_impl.h"
+#include "content/browser/service_worker/embedded_worker_test_helper.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace content {
+
namespace {
-const char kOriginUrl[] = "https://example.com";
-const int64 kServiceWorkerVersionId = 0;
-const int64 kServiceWorkerId1 = 1;
-const int64 kServiceWorkerId2 = 2;
+
+const char kOrigin[] = "https://example.com";
+const char kPattern1[] = "https://example.com/a";
+const char kPattern2[] = "https://example.com/b";
+const char kScript1[] = "https://example.com/a/script.js";
+const char kScript2[] = "https://example.com/b/script.js";
+const int kRenderProcessId = 99;
+
+void RegisterServiceWorkerCallback(bool* called,
+ int64* store_registration_id,
+ ServiceWorkerStatusCode status,
+ const std::string& status_message,
+ int64 registration_id) {
+ EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
+ *called = true;
+ *store_registration_id = registration_id;
}
-namespace content {
+void UnregisterServiceWorkerCallback(bool* called,
+ ServiceWorkerStatusCode code) {
+ EXPECT_EQ(SERVICE_WORKER_OK, code);
+ *called = true;
+}
+
+} // namespace
// A BackgroundSyncManager that can simulate delaying and corrupting the
// backend. This class assumes (and verifies) that only one operation runs at a
@@ -115,32 +137,36 @@ class BackgroundSyncManagerTest : public testing::Test {
public:
BackgroundSyncManagerTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
- service_worker_context_(new ServiceWorkerContextWrapper(NULL)),
- origin_(kOriginUrl),
sync_reg_1_(BackgroundSyncManager::BackgroundSyncRegistration("foo")),
sync_reg_2_(BackgroundSyncManager::BackgroundSyncRegistration("bar")),
callback_error_(BackgroundSyncManager::ERROR_TYPE_OK),
callback_sw_status_code_(SERVICE_WORKER_OK) {}
void SetUp() override {
- scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager(
- new MockServiceWorkerDatabaseTaskManager(
- base::ThreadTaskRunnerHandle::Get()));
-
- service_worker_context_->InitInternal(
- base::FilePath(), database_task_manager.Pass(),
- base::ThreadTaskRunnerHandle::Get(), NULL, NULL);
- context_ptr_ = service_worker_context_->context()->AsWeakPtr();
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId));
background_sync_manager_ =
- BackgroundSyncManager::Create(service_worker_context_);
+ BackgroundSyncManager::Create(helper_->context_wrapper());
// Wait for storage to finish initializing before registering service
// workers.
base::RunLoop().RunUntilIdle();
- RegisterServiceWorker(kServiceWorkerId1);
- RegisterServiceWorker(kServiceWorkerId2);
+ bool called_1 = false;
+ bool called_2 = false;
+ helper_->context()->RegisterServiceWorker(
+ GURL(kPattern1), GURL(kScript1), NULL,
+ base::Bind(&RegisterServiceWorkerCallback, &called_1,
+ &sw_registration_id_1_));
+
+ helper_->context()->RegisterServiceWorker(
+ GURL(kPattern2), GURL(kScript2), NULL,
+ base::Bind(&RegisterServiceWorkerCallback, &called_2,
+ &sw_registration_id_2_));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called_1);
+ EXPECT_TRUE(called_2);
}
void StatusAndRegistrationCallback(
@@ -161,7 +187,7 @@ class BackgroundSyncManagerTest : public testing::Test {
protected:
TestBackgroundSyncManager* UseTestBackgroundSyncManager() {
TestBackgroundSyncManager* manager =
- new TestBackgroundSyncManager(service_worker_context_);
+ new TestBackgroundSyncManager(helper_->context_wrapper());
background_sync_manager_.reset(manager);
manager->DoInit();
return manager;
@@ -169,7 +195,8 @@ class BackgroundSyncManagerTest : public testing::Test {
bool Register(const BackgroundSyncManager::BackgroundSyncRegistration&
sync_registration) {
- return RegisterWithServiceWorkerId(kServiceWorkerId1, sync_registration);
+ return RegisterWithServiceWorkerId(sw_registration_id_1_,
+ sync_registration);
}
bool RegisterWithServiceWorkerId(
@@ -178,7 +205,7 @@ class BackgroundSyncManagerTest : public testing::Test {
sync_registration) {
bool was_called = false;
background_sync_manager_->Register(
- origin_, sw_registration_id, sync_registration,
+ GURL(kOrigin), sw_registration_id, sync_registration,
base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
base::Unretained(this), &was_called));
base::RunLoop().RunUntilIdle();
@@ -188,7 +215,8 @@ class BackgroundSyncManagerTest : public testing::Test {
bool Unregister(const BackgroundSyncManager::BackgroundSyncRegistration&
sync_registration) {
- return UnregisterWithServiceWorkerId(kServiceWorkerId1, sync_registration);
+ return UnregisterWithServiceWorkerId(sw_registration_id_1_,
+ sync_registration);
}
bool UnregisterWithServiceWorkerId(
@@ -197,7 +225,7 @@ class BackgroundSyncManagerTest : public testing::Test {
sync_registration) {
bool was_called = false;
background_sync_manager_->Unregister(
- origin_, sw_registration_id, sync_registration.name,
+ GURL(kOrigin), sw_registration_id, sync_registration.name,
sync_registration.id,
base::Bind(&BackgroundSyncManagerTest::StatusCallback,
base::Unretained(this), &was_called));
@@ -207,7 +235,7 @@ class BackgroundSyncManagerTest : public testing::Test {
}
bool GetRegistration(const std::string& sync_registration_name) {
- return GetRegistrationWithServiceWorkerId(kServiceWorkerId1,
+ return GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
sync_registration_name);
}
@@ -216,7 +244,7 @@ class BackgroundSyncManagerTest : public testing::Test {
const std::string& sync_registration_name) {
bool was_called = false;
background_sync_manager_->GetRegistration(
- origin_, sw_registration_id, sync_registration_name,
+ GURL(kOrigin), sw_registration_id, sync_registration_name,
base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
base::Unretained(this), &was_called));
base::RunLoop().RunUntilIdle();
@@ -232,32 +260,28 @@ class BackgroundSyncManagerTest : public testing::Test {
callback_sw_status_code_ = result;
}
- void RegisterServiceWorker(uint64 sw_registration_id) {
- scoped_refptr<ServiceWorkerRegistration> live_registration =
- new ServiceWorkerRegistration(origin_, sw_registration_id,
- context_ptr_);
-
- scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
- live_registration.get(), GURL(std::string(kOriginUrl) + "/script.js"),
- kServiceWorkerVersionId, context_ptr_);
- live_version->SetStatus(ServiceWorkerVersion::INSTALLED);
- live_registration->SetWaitingVersion(live_version.get());
-
- service_worker_context_->context()->storage()->StoreRegistration(
- live_registration.get(), live_version.get(),
- base::Bind(&BackgroundSyncManagerTest::StorageRegistrationCallback,
- base::Unretained(this)));
-
+ void UnregisterServiceWorker(uint64 sw_registration_id) {
+ bool called = false;
+ helper_->context()->UnregisterServiceWorker(
+ PatternForSWId(sw_registration_id),
+ base::Bind(&UnregisterServiceWorkerCallback, &called));
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SERVICE_WORKER_OK, callback_sw_status_code_);
+ EXPECT_TRUE(called);
+ }
+
+ GURL PatternForSWId(int64 sw_id) {
+ EXPECT_TRUE(sw_id == sw_registration_id_1_ ||
+ sw_id == sw_registration_id_2_);
+ return sw_id == sw_registration_id_1_ ? GURL(kPattern1) : GURL(kPattern2);
}
TestBrowserThreadBundle browser_thread_bundle_;
- scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
+ scoped_ptr<EmbeddedWorkerTestHelper> helper_;
scoped_ptr<BackgroundSyncManager> background_sync_manager_;
- base::WeakPtr<ServiceWorkerContextCore> context_ptr_;
- const GURL origin_;
+ int64 sw_registration_id_1_;
+ int64 sw_registration_id_2_;
+
BackgroundSyncManager::BackgroundSyncRegistration sync_reg_1_;
BackgroundSyncManager::BackgroundSyncRegistration sync_reg_2_;
@@ -304,22 +328,8 @@ TEST_F(BackgroundSyncManagerTest, RegisterBadBackend) {
manager->set_corrupt_backend(true);
EXPECT_FALSE(Register(sync_reg_1_));
manager->set_corrupt_backend(false);
- EXPECT_FALSE(GetRegistration(sync_reg_1_.name));
-}
-
-TEST_F(BackgroundSyncManagerTest, RegisterOverwriteBadBackend) {
- TestBackgroundSyncManager* manager = UseTestBackgroundSyncManager();
- EXPECT_TRUE(Register(sync_reg_1_));
- BackgroundSyncManager::BackgroundSyncRegistration first_registration =
- callback_registration_;
-
- sync_reg_1_.min_period = 100;
-
- manager->set_corrupt_backend(true);
EXPECT_FALSE(Register(sync_reg_1_));
- EXPECT_TRUE(GetRegistration(sync_reg_1_.name));
- EXPECT_EQ(callback_registration_.id, first_registration.id);
- EXPECT_TRUE(callback_registration_.Equals(first_registration));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_.name));
}
TEST_F(BackgroundSyncManagerTest, TwoRegistrations) {
@@ -342,10 +352,12 @@ TEST_F(BackgroundSyncManagerTest, GetRegistrationBadBackend) {
EXPECT_TRUE(Register(sync_reg_1_));
manager->set_corrupt_backend(true);
EXPECT_TRUE(GetRegistration(sync_reg_1_.name));
- EXPECT_FALSE(GetRegistration(sync_reg_2_.name));
+ EXPECT_FALSE(Register(sync_reg_2_));
+ // Registration should have discovered the bad backend and disabled the
+ // BackgroundSyncManager.
+ EXPECT_FALSE(GetRegistration(sync_reg_1_.name));
manager->set_corrupt_backend(false);
- EXPECT_TRUE(GetRegistration(sync_reg_1_.name));
- EXPECT_FALSE(GetRegistration(sync_reg_2_.name));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_.name));
}
TEST_F(BackgroundSyncManagerTest, Unregister) {
@@ -383,11 +395,14 @@ TEST_F(BackgroundSyncManagerTest, UnregisterBadBackend) {
TestBackgroundSyncManager* manager = UseTestBackgroundSyncManager();
sync_reg_1_.min_period += 1;
EXPECT_TRUE(Register(sync_reg_1_));
+ EXPECT_TRUE(Register(sync_reg_2_));
manager->set_corrupt_backend(true);
EXPECT_FALSE(Unregister(callback_registration_));
+ // Unregister should have discovered the bad backend and disabled the
+ // BackgroundSyncManager.
manager->set_corrupt_backend(false);
- EXPECT_TRUE(GetRegistration(sync_reg_1_.name));
- EXPECT_TRUE(callback_registration_.Equals(sync_reg_1_));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_.name));
+ EXPECT_FALSE(GetRegistration(sync_reg_2_.name));
}
TEST_F(BackgroundSyncManagerTest, RegistrationIncreasesId) {
@@ -411,40 +426,40 @@ TEST_F(BackgroundSyncManagerTest, RebootRecovery) {
EXPECT_TRUE(Register(sync_reg_1_));
background_sync_manager_ =
- BackgroundSyncManager::Create(service_worker_context_);
+ BackgroundSyncManager::Create(helper_->context_wrapper());
EXPECT_TRUE(GetRegistration(sync_reg_1_.name));
EXPECT_FALSE(GetRegistration(sync_reg_2_.name));
}
TEST_F(BackgroundSyncManagerTest, RebootRecoveryTwoServiceWorkers) {
- EXPECT_TRUE(RegisterWithServiceWorkerId(kServiceWorkerId1, sync_reg_1_));
- EXPECT_TRUE(RegisterWithServiceWorkerId(kServiceWorkerId2, sync_reg_2_));
+ EXPECT_TRUE(RegisterWithServiceWorkerId(sw_registration_id_1_, sync_reg_1_));
+ EXPECT_TRUE(RegisterWithServiceWorkerId(sw_registration_id_2_, sync_reg_2_));
background_sync_manager_ =
- BackgroundSyncManager::Create(service_worker_context_);
-
- EXPECT_TRUE(
- GetRegistrationWithServiceWorkerId(kServiceWorkerId1, sync_reg_1_.name));
- EXPECT_FALSE(
- GetRegistrationWithServiceWorkerId(kServiceWorkerId1, sync_reg_2_.name));
- EXPECT_FALSE(
- GetRegistrationWithServiceWorkerId(kServiceWorkerId2, sync_reg_1_.name));
- EXPECT_TRUE(
- GetRegistrationWithServiceWorkerId(kServiceWorkerId2, sync_reg_2_.name));
-
- EXPECT_TRUE(
- GetRegistrationWithServiceWorkerId(kServiceWorkerId1, sync_reg_1_.name));
- EXPECT_TRUE(
- GetRegistrationWithServiceWorkerId(kServiceWorkerId2, sync_reg_2_.name));
-
- EXPECT_TRUE(RegisterWithServiceWorkerId(kServiceWorkerId1, sync_reg_2_));
- EXPECT_TRUE(RegisterWithServiceWorkerId(kServiceWorkerId2, sync_reg_1_));
+ BackgroundSyncManager::Create(helper_->context_wrapper());
+
+ EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
+ sync_reg_1_.name));
+ EXPECT_FALSE(GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
+ sync_reg_2_.name));
+ EXPECT_FALSE(GetRegistrationWithServiceWorkerId(sw_registration_id_2_,
+ sync_reg_1_.name));
+ EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_2_,
+ sync_reg_2_.name));
+
+ EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
+ sync_reg_1_.name));
+ EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_2_,
+ sync_reg_2_.name));
+
+ EXPECT_TRUE(RegisterWithServiceWorkerId(sw_registration_id_1_, sync_reg_2_));
+ EXPECT_TRUE(RegisterWithServiceWorkerId(sw_registration_id_2_, sync_reg_1_));
}
-TEST_F(BackgroundSyncManagerTest, InitWithCorruptBackend) {
+TEST_F(BackgroundSyncManagerTest, InitWithBadBackend) {
TestBackgroundSyncManager* manager =
- new TestBackgroundSyncManager(service_worker_context_);
+ new TestBackgroundSyncManager(helper_->context_wrapper());
background_sync_manager_.reset(manager);
manager->set_corrupt_backend(true);
manager->DoInit();
@@ -457,7 +472,7 @@ TEST_F(BackgroundSyncManagerTest, SequentialOperations) {
// Schedule Init and all of the operations on a delayed backend. Verify that
// the operations complete sequentially.
TestBackgroundSyncManager* manager =
- new TestBackgroundSyncManager(service_worker_context_);
+ new TestBackgroundSyncManager(helper_->context_wrapper());
background_sync_manager_.reset(manager);
manager->set_delay_backend(true);
manager->DoInit();
@@ -469,15 +484,15 @@ TEST_F(BackgroundSyncManagerTest, SequentialOperations) {
bool unregister_called = false;
bool get_registration_called = false;
manager->Register(
- origin_, kServiceWorkerId1, sync_reg_1_,
+ GURL(kOrigin), sw_registration_id_1_, sync_reg_1_,
base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
base::Unretained(this), &register_called));
- manager->Unregister(origin_, kServiceWorkerId1, sync_reg_1_.name,
+ manager->Unregister(GURL(kOrigin), sw_registration_id_1_, sync_reg_1_.name,
kExpectedInitialId,
base::Bind(&BackgroundSyncManagerTest::StatusCallback,
base::Unretained(this), &unregister_called));
manager->GetRegistration(
- origin_, kServiceWorkerId1, sync_reg_1_.name,
+ GURL(kOrigin), sw_registration_id_1_, sync_reg_1_.name,
base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
base::Unretained(this), &get_registration_called));
@@ -512,4 +527,96 @@ TEST_F(BackgroundSyncManagerTest, SequentialOperations) {
EXPECT_TRUE(get_registration_called);
}
+TEST_F(BackgroundSyncManagerTest, UnregisterServiceWorker) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ UnregisterServiceWorker(sw_registration_id_1_);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_.name));
+}
+
+TEST_F(BackgroundSyncManagerTest,
+ UnregisterServiceWorkerDuringSyncRegistration) {
+ TestBackgroundSyncManager* manager =
+ new TestBackgroundSyncManager(helper_->context_wrapper());
+ background_sync_manager_.reset(manager);
+ manager->DoInit();
+
+ EXPECT_TRUE(Register(sync_reg_1_));
+
+ manager->set_delay_backend(true);
+ bool callback_called = false;
+ manager->Register(
+ GURL(kOrigin), sw_registration_id_1_, sync_reg_2_,
+ base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
+ base::Unretained(this), &callback_called));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(callback_called);
+ UnregisterServiceWorker(sw_registration_id_1_);
+
+ manager->Continue();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(callback_called);
+ EXPECT_EQ(BackgroundSyncManager::ERROR_TYPE_STORAGE, callback_error_);
+
+ manager->set_delay_backend(false);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_.name));
+}
+
+TEST_F(BackgroundSyncManagerTest, DeleteAndStartOverServiceWorkerContext) {
+ EXPECT_TRUE(Register(sync_reg_1_));
+ helper_->context()->ScheduleDeleteAndStartOver();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(GetRegistration(sync_reg_1_.name));
+}
+
+TEST_F(BackgroundSyncManagerTest, DisabledManagerWorksAfterBrowserRestart) {
+ TestBackgroundSyncManager* manager =
+ new TestBackgroundSyncManager(helper_->context_wrapper());
+ background_sync_manager_.reset(manager);
+ manager->DoInit();
+ EXPECT_TRUE(Register(sync_reg_1_));
+ manager->set_corrupt_backend(true);
+ EXPECT_FALSE(Register(sync_reg_2_));
+
+ // The manager is now disabled and not accepting new requests until browser
+ // restart or notification that the storage has been wiped.
+ manager->set_corrupt_backend(false);
+ EXPECT_FALSE(GetRegistration(sync_reg_1_.name));
+ EXPECT_FALSE(Register(sync_reg_2_));
+
+ // Simulate restarting the browser by creating a new BackgroundSyncManager.
+ background_sync_manager_.reset(
+ new TestBackgroundSyncManager(helper_->context_wrapper()));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_.name));
+ EXPECT_TRUE(Register(sync_reg_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, DisabledManagerWorksAfterDeleteAndStartOver) {
+ TestBackgroundSyncManager* manager =
+ new TestBackgroundSyncManager(helper_->context_wrapper());
+ background_sync_manager_.reset(manager);
+ manager->DoInit();
+ EXPECT_TRUE(Register(sync_reg_1_));
+ manager->set_corrupt_backend(true);
+ EXPECT_FALSE(Register(sync_reg_2_));
+
+ // The manager is now disabled and not accepting new requests until browser
+ // restart or notification that the storage has been wiped.
+ manager->set_corrupt_backend(false);
+ helper_->context()->ScheduleDeleteAndStartOver();
+ base::RunLoop().RunUntilIdle();
+
+ bool called = false;
+ helper_->context()->RegisterServiceWorker(
+ GURL(kPattern1), GURL(kScript1), NULL,
+ base::Bind(&RegisterServiceWorkerCallback, &called,
+ &sw_registration_id_1_));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+
+ EXPECT_TRUE(Register(sync_reg_2_));
+ EXPECT_FALSE(GetRegistration(sync_reg_1_.name));
+ EXPECT_TRUE(GetRegistration(sync_reg_2_.name));
+}
+
} // namespace content