diff options
author | jkarlin <jkarlin@chromium.org> | 2015-04-03 09:46:44 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-03 16:47:23 +0000 |
commit | 9059304cb5c6f7f683ea30259eeacc5a429566c9 (patch) | |
tree | d320b71723b483898a4d6e61d4ee8579e47af4d8 /content/browser/background_sync | |
parent | d4c3a502cc21b8e2f7d37b0508278f3445196f5d (diff) | |
download | chromium_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')
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), ®ister_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 |