OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/sync/driver/glue/ui_model_worker.h" | 5 #include "components/sync/driver/glue/ui_model_worker.h" |
6 | 6 |
7 #include <memory> | |
8 | |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
9 #include "base/location.h" | 11 #include "base/location.h" |
12 #include "base/memory/ptr_util.h" | |
10 #include "base/memory/ref_counted.h" | 13 #include "base/memory/ref_counted.h" |
11 #include "base/run_loop.h" | 14 #include "base/run_loop.h" |
15 #include "base/test/test_timeouts.h" | |
16 #include "base/threading/platform_thread.h" | |
12 #include "base/threading/thread.h" | 17 #include "base/threading/thread.h" |
13 #include "base/threading/thread_task_runner_handle.h" | 18 #include "base/threading/thread_task_runner_handle.h" |
14 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
15 | 20 |
16 namespace syncer { | 21 namespace syncer { |
17 namespace { | 22 namespace { |
18 | 23 |
19 // Makes a Closure into a WorkCallback. | 24 // Makes a Closure into a WorkCallback. |
20 // Does |work| and checks that we're on the |thread_verifier| thread. | 25 // Does |work| and checks that we're on the |thread_verifier| thread. |
21 SyncerError DoWork( | 26 SyncerError DoWork( |
22 const scoped_refptr<base::SingleThreadTaskRunner>& thread_verifier, | 27 const scoped_refptr<base::SingleThreadTaskRunner>& thread_verifier, |
23 base::Closure work) { | 28 base::Closure work) { |
24 DCHECK(thread_verifier->BelongsToCurrentThread()); | 29 DCHECK(thread_verifier->BelongsToCurrentThread()); |
25 work.Run(); | 30 work.Run(); |
26 return SYNCER_OK; | 31 return SYNCER_OK; |
27 } | 32 } |
28 | 33 |
29 // Converts |work| to a WorkCallback that will verify that it's run on the | 34 // Converts |work| to a WorkCallback that will verify that it's run on the |
30 // thread it was constructed on. | 35 // thread it was constructed on. |
31 WorkCallback ClosureToWorkCallback(base::Closure work) { | 36 WorkCallback ClosureToWorkCallback(base::Closure work) { |
32 return base::Bind(&DoWork, base::ThreadTaskRunnerHandle::Get(), work); | 37 return base::Bind(&DoWork, base::ThreadTaskRunnerHandle::Get(), work); |
33 } | 38 } |
34 | 39 |
40 // Increments |counter|. | |
41 void IncrementCounter(int* counter) { | |
42 ++*counter; | |
43 } | |
44 | |
35 class SyncUIModelWorkerTest : public testing::Test { | 45 class SyncUIModelWorkerTest : public testing::Test { |
36 public: | 46 public: |
37 SyncUIModelWorkerTest() : sync_thread_("SyncThreadForTest") { | 47 SyncUIModelWorkerTest() : sync_thread_("SyncThreadForTest") { |
38 sync_thread_.Start(); | 48 sync_thread_.Start(); |
39 worker_ = new UIModelWorker(base::ThreadTaskRunnerHandle::Get()); | 49 worker_ = new UIModelWorker(base::ThreadTaskRunnerHandle::Get()); |
40 } | 50 } |
41 | 51 |
42 void PostWorkToSyncThread(WorkCallback work) { | 52 void PostWorkToSyncThread(base::Closure work) { |
43 sync_thread_.task_runner()->PostTask( | 53 sync_thread_.task_runner()->PostTask( |
44 FROM_HERE, | 54 FROM_HERE, |
45 base::Bind(base::IgnoreResult(&UIModelWorker::DoWorkAndWaitUntilDone), | 55 base::Bind(base::IgnoreResult(&UIModelWorker::DoWorkAndWaitUntilDone), |
46 worker_, work)); | 56 worker_, ClosureToWorkCallback(work))); |
47 } | 57 } |
48 | 58 |
49 private: | 59 protected: |
50 base::MessageLoop ui_loop_; | 60 std::unique_ptr<base::MessageLoop> ui_loop_ = |
61 base::MakeUnique<base::MessageLoop>(); | |
51 base::Thread sync_thread_; | 62 base::Thread sync_thread_; |
52 scoped_refptr<UIModelWorker> worker_; | 63 scoped_refptr<UIModelWorker> worker_; |
53 }; | 64 }; |
54 | 65 |
66 } // namespace | |
67 | |
55 TEST_F(SyncUIModelWorkerTest, ScheduledWorkRunsOnUILoop) { | 68 TEST_F(SyncUIModelWorkerTest, ScheduledWorkRunsOnUILoop) { |
56 base::RunLoop run_loop; | 69 base::RunLoop run_loop; |
57 PostWorkToSyncThread(ClosureToWorkCallback(run_loop.QuitClosure())); | 70 PostWorkToSyncThread(run_loop.QuitClosure()); |
58 // This won't quit until the QuitClosure is run. | 71 // This won't quit until the QuitClosure is run. |
59 run_loop.Run(); | 72 run_loop.Run(); |
60 } | 73 } |
61 | 74 |
62 } // namespace | 75 TEST_F(SyncUIModelWorkerTest, MultipleDoWork) { |
76 constexpr int kNumWorkCallbacks = 10; | |
77 int counter = 0; | |
78 for (int i = 0; i < kNumWorkCallbacks; ++i) { | |
79 PostWorkToSyncThread( | |
80 base::Bind(&IncrementCounter, base::Unretained(&counter))); | |
81 } | |
82 | |
83 base::RunLoop run_loop; | |
84 PostWorkToSyncThread(run_loop.QuitClosure()); | |
85 run_loop.Run(); | |
86 | |
87 EXPECT_EQ(kNumWorkCallbacks, counter); | |
88 } | |
89 | |
90 TEST_F(SyncUIModelWorkerTest, JoinSyncThreadAfterUIMessageLoopDestruction) { | |
91 PostWorkToSyncThread(base::Bind(&base::DoNothing)); | |
92 | |
93 // Allow the sync thread to post the WorkCallback to the UI MessageLoop. | |
94 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | |
maxbogue
2016/11/18 18:26:51
Ooo, interesting. Didn't know we had anything like
fdoray
2016/11/21 16:57:56
Yes, it's racy. I explained it in the comment.
Jo
| |
95 | |
96 // The sync thread shouldn't wait for the WorkCallback to run on the UI thread | |
97 // after the UI MessageLoop is gone. | |
98 ui_loop_.reset(); | |
99 sync_thread_.Stop(); | |
100 } | |
101 | |
102 TEST_F(SyncUIModelWorkerTest, JoinSyncThreadAfterRequestStop) { | |
103 PostWorkToSyncThread(base::Bind(&base::DoNothing)); | |
104 | |
105 // Allow the sync thread to post the WorkCallback to the UI MessageLoop. | |
106 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | |
107 | |
108 // The sync thread shouldn't wait for the WorkCallback to run on the UI thread | |
109 // after RequestStop() is called. | |
110 worker_->RequestStop(); | |
111 sync_thread_.Stop(); | |
112 } | |
113 | |
63 } // namespace syncer | 114 } // namespace syncer |
OLD | NEW |