summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/sync/glue/sync_backend_registrar_unittest.cc')
-rw-r--r--chrome/browser/sync/glue/sync_backend_registrar_unittest.cc85
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