diff options
Diffstat (limited to 'chrome/browser/sync/glue/sync_backend_registrar_unittest.cc')
-rw-r--r-- | chrome/browser/sync/glue/sync_backend_registrar_unittest.cc | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc b/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc index cd2d29d..0bb25fa 100644 --- a/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc +++ b/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc @@ -256,6 +256,91 @@ TEST_F(SyncBackendRegistrarTest, ActivateDeactivateNonUIDataType) { TriggerChanges(registrar_.get(), AUTOFILL); } +class SyncBackendRegistrarShutdownTest : public testing::Test { + public: + void BlockDBThread() { + EXPECT_FALSE(db_thread_lock_.Try()); + + db_thread_blocked_.Signal(); + base::AutoLock l(db_thread_lock_); + } + + protected: + friend class TestRegistrar; + + SyncBackendRegistrarShutdownTest() + : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD | + content::TestBrowserThreadBundle::REAL_FILE_THREAD | + content::TestBrowserThreadBundle::REAL_IO_THREAD), + db_thread_blocked_(false, false), + registrar_destroyed_(false, false) {} + + virtual ~SyncBackendRegistrarShutdownTest() {} + + content::TestBrowserThreadBundle thread_bundle_; + base::WaitableEvent db_thread_blocked_; + base::Lock db_thread_lock_; + base::WaitableEvent registrar_destroyed_; +}; + +// Wrap SyncBackendRegistrar so that we can monitor its lifetime. +class TestRegistrar : public SyncBackendRegistrar { + public: + explicit TestRegistrar(Profile* profile, + SyncBackendRegistrarShutdownTest* test) + : SyncBackendRegistrar("test", profile, scoped_ptr<base::Thread>()), + test_(test) {} + + virtual ~TestRegistrar() { test_->registrar_destroyed_.Signal(); } + + private: + SyncBackendRegistrarShutdownTest* test_; +}; + +TEST_F(SyncBackendRegistrarShutdownTest, BlockingShutdown) { + // Take ownership of |db_thread_lock_| so that the DB thread can't acquire it. + db_thread_lock_.Acquire(); + + // This will block the DB thread by waiting on |db_thread_lock_|. + BrowserThread::PostTask( + BrowserThread::DB, + FROM_HERE, + base::Bind(&SyncBackendRegistrarShutdownTest::BlockDBThread, + base::Unretained(this))); + + TestingProfile profile; + scoped_ptr<TestRegistrar> registrar(new TestRegistrar(&profile, this)); + base::Thread* sync_thread = registrar->sync_thread(); + + // Stop here until the DB thread gets a chance to run and block on the lock. + // Please note that since the task above didn't finish, the task to + // initialize the worker on the DB thread hasn't had a chance to run yet too. + // Which means ModelSafeWorker::SetWorkingLoopToCurrent hasn't been called + // for the DB worker. + db_thread_blocked_.Wait(); + + registrar->SetInitialTypes(ModelTypeSet()); + + // Start the shutdown. + registrar->RequestWorkerStopOnUIThread(); + sync_thread->message_loop()->PostTask( + FROM_HERE, + base::Bind(&SyncBackendRegistrar::Shutdown, + base::Unretained(registrar.release()))); + + // The test verifies that the sync thread doesn't block because + // of the blocked DB thread and can finish the shutdown. + sync_thread->message_loop()->RunUntilIdle(); + + db_thread_lock_.Release(); + + base::MessageLoop::current()->RunUntilIdle(); + + // This verifies that all workers have been removed and the registrar + // destroyed. + registrar_destroyed_.Wait(); +} + } // namespace } // namespace browser_sync |