Index: chrome/browser/sync/glue/sync_backend_registrar_unittest.cc |
diff --git a/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc b/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc |
index cd2d29ddf4edfdb88cc9ecefb6feab6cab9e8586..ed8bc39966911c25b11a8b65db06958e8011c68f 100644 |
--- a/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc |
+++ b/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc |
@@ -256,6 +256,92 @@ TEST_F(SyncBackendRegistrarTest, ActivateDeactivateNonUIDataType) { |
TriggerChanges(registrar_.get(), AUTOFILL); |
} |
+class SyncBackendRegistrarShutdownTest : public testing::Test { |
+ public: |
+ void DBThreadBlocker() { |
Nicolas Zea
2014/10/17 00:04:01
nit: I think it would be clearer to call this meth
stanisc
2014/10/17 06:58:02
Done.
|
+ EXPECT_FALSE(ui_thread_lock_.Try()); |
+ |
+ blocked_.Signal(); |
+ base::AutoLock l(ui_thread_lock_); |
+ } |
+ |
+ // Wrap SyncBackendRegistrar so that we can monitor its lifetime. |
+ class TestRegistrar : public SyncBackendRegistrar { |
Nicolas Zea
2014/10/17 00:04:01
nit: The usual style is to avoid nested classes li
stanisc
2014/10/17 06:58:02
Well, nested classes are supposed to be used for s
|
+ 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_; |
+ }; |
+ |
+ protected: |
+ SyncBackendRegistrarShutdownTest() |
+ : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD | |
+ content::TestBrowserThreadBundle::REAL_FILE_THREAD | |
+ content::TestBrowserThreadBundle::REAL_IO_THREAD), |
+ blocked_(false, false), |
+ registrar_destroyed_(false, false) {} |
+ |
+ virtual ~SyncBackendRegistrarShutdownTest() {} |
+ |
+ content::TestBrowserThreadBundle thread_bundle_; |
+ base::WaitableEvent blocked_; |
Nicolas Zea
2014/10/17 00:04:01
nit: perhaps name this db_thread_blocked_
stanisc
2014/10/17 06:58:02
Done.
|
+ base::Lock ui_thread_lock_; |
+ base::WaitableEvent registrar_destroyed_; |
+}; |
+ |
+TEST_F(SyncBackendRegistrarShutdownTest, BlockingShutdown) { |
+ // Lock |ui_thread_lock_| so that the DB thread can't acquire it. |
Nicolas Zea
2014/10/17 00:04:01
nit: because the ui_thread_lock_ is actually being
stanisc
2014/10/17 06:58:02
Agree! Done.
|
+ ui_thread_lock_.Acquire(); |
+ |
+ // Block the DB thread by waiting on |ui_thread_lock_|. |
+ BrowserThread::PostTask( |
+ BrowserThread::DB, |
+ FROM_HERE, |
+ base::Bind(&SyncBackendRegistrarShutdownTest::DBThreadBlocker, |
+ 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. |
+ 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(); |
+ |
+ ui_thread_lock_.Release(); |
+ |
+ // BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::DB)-> |
+ // RunUntilIdle(); |
Nicolas Zea
2014/10/17 00:04:01
did you mean to keep this around?
stanisc
2014/10/17 06:58:02
I ended up not needing this. Removed.
|
+ |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
+ // This verifies that all workers have been removed and the registrar |
+ // destroyed. |
+ registrar_destroyed_.Wait(); |
+} |
+ |
} // namespace |
} // namespace browser_sync |