Chromium Code Reviews| Index: components/sync/driver/glue/ui_model_worker_unittest.cc |
| diff --git a/components/sync/driver/glue/ui_model_worker_unittest.cc b/components/sync/driver/glue/ui_model_worker_unittest.cc |
| index d091f317a5c60f2896c0a05ec84abbea9095a730..ce401bf1684dbbf5f6bf38c24534b3c51b61573b 100644 |
| --- a/components/sync/driver/glue/ui_model_worker_unittest.cc |
| +++ b/components/sync/driver/glue/ui_model_worker_unittest.cc |
| @@ -32,6 +32,15 @@ WorkCallback ClosureToWorkCallback(base::Closure work) { |
| return base::Bind(&DoWork, base::ThreadTaskRunnerHandle::Get(), work); |
| } |
| +// This function runs on the sync thread. |
| +void SignalAndDoWork(scoped_refptr<UIModelWorker> worker, |
| + WorkCallback work, |
| + base::WaitableEvent* event) { |
| + if (event) |
|
fdoray
2016/11/14 14:24:34
EXPECT_TRUE(event) since we don't expect |event| t
maxbogue
2016/11/14 20:53:21
n/a, event is no longer needed.
|
| + event->Signal(); |
| + worker->DoWorkAndWaitUntilDone(work); |
| +} |
| + |
| class SyncUIModelWorkerTest : public testing::Test { |
| public: |
| SyncUIModelWorkerTest() : sync_thread_("SyncThreadForTest") { |
| @@ -39,25 +48,54 @@ class SyncUIModelWorkerTest : public testing::Test { |
| worker_ = new UIModelWorker(base::ThreadTaskRunnerHandle::Get()); |
| } |
| - void PostWorkToSyncThread(WorkCallback work) { |
| + void PostWorkToSyncThread(base::Closure work, |
| + base::WaitableEvent* task_on_sync_thread_event) { |
| sync_thread_.task_runner()->PostTask( |
| FROM_HERE, |
| - base::Bind(base::IgnoreResult(&UIModelWorker::DoWorkAndWaitUntilDone), |
| - worker_, work)); |
| + base::Bind(&SignalAndDoWork, worker_, ClosureToWorkCallback(work), |
| + task_on_sync_thread_event)); |
| } |
| + void StopSyncThread() { sync_thread_.Stop(); } |
| + |
| + UIModelWorker* worker() { return worker_.get(); } |
| + |
| private: |
| + // Worker must outlive message loop. |
| + scoped_refptr<UIModelWorker> worker_; |
| base::MessageLoop ui_loop_; |
| base::Thread sync_thread_; |
| - scoped_refptr<UIModelWorker> worker_; |
| }; |
| TEST_F(SyncUIModelWorkerTest, ScheduledWorkRunsOnUILoop) { |
| base::RunLoop run_loop; |
| - PostWorkToSyncThread(ClosureToWorkCallback(run_loop.QuitClosure())); |
| + PostWorkToSyncThread(run_loop.QuitClosure(), nullptr); |
| // This won't quit until the QuitClosure is run. |
| run_loop.Run(); |
| } |
| +TEST_F(SyncUIModelWorkerTest, ShutdownNoDeadlock) { |
| + // We need some way to wait until the sync thread has our task. |
| + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| + base::WaitableEvent::InitialState::NOT_SIGNALED); |
| + |
| + PostWorkToSyncThread(base::Bind(&SyncUIModelWorkerTest::StopSyncThread, |
| + base::Unretained(this)), |
| + &event); |
| + |
| + // Wait until the sync thread has started our task. |
| + event.Wait(); |
| + |
| + // This is a little racy. We're banking on this stop signal to occur after the |
| + // sync thread has progressed past the stopped check. However, if it doesn't, |
| + // we just get a false positive (no flakes). |
|
fdoray
2016/11/14 14:24:34
I think the test below avoids false positives (the
maxbogue
2016/11/14 20:53:21
Of course, just do everything inside the work clos
|
| + worker()->RequestStop(); |
| + |
| + // Now we yield control of the UI thread. The stop signal has unblocked the |
| + // sync thread, so the UI thread task can join the sync thread without |
| + // deadlocking. |
| + base::RunLoop().RunUntilIdle(); |
| +} |
| + |
| } // namespace |
| } // namespace syncer |