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/engine/ui_model_worker.h" | 5 #include "components/sync/engine/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 // Wait to allow the sync thread to post the WorkCallback to the UI |
| 94 // MessageLoop. This is racy. If the WorkCallback isn't posted fast enough, |
| 95 // this test doesn't verify that UIModelWorker behaves properly when the UI |
| 96 // MessageLoop is destroyed. However, it doesn't fail (no flakes). |
| 97 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| 98 |
| 99 // The sync thread shouldn't wait for the WorkCallback to run on the UI thread |
| 100 // after the UI MessageLoop is gone. |
| 101 ui_loop_.reset(); |
| 102 sync_thread_.Stop(); |
| 103 } |
| 104 |
| 105 TEST_F(SyncUIModelWorkerTest, JoinSyncThreadAfterRequestStop) { |
| 106 PostWorkToSyncThread(base::Bind(&base::DoNothing)); |
| 107 |
| 108 // Wait to allow the sync thread to post the WorkCallback to the UI |
| 109 // MessageLoop. This is racy. If the WorkCallback isn't posted fast enough, |
| 110 // this test doesn't verify that UIModelWorker behaves properly when |
| 111 // RequestStop() is called. However, it doesn't fail (no flakes). |
| 112 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| 113 |
| 114 // The sync thread shouldn't wait for the WorkCallback to run on the UI thread |
| 115 // after RequestStop() is called. |
| 116 worker_->RequestStop(); |
| 117 sync_thread_.Stop(); |
| 118 } |
| 119 |
63 } // namespace syncer | 120 } // namespace syncer |
OLD | NEW |