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
3 // found in the LICENSE file.
5 #include "chrome/browser/sync/glue/sync_backend_registrar.h"
7 #include "base/location.h"
8 #include "base/run_loop.h"
9 #include "base/single_thread_task_runner.h"
10 #include "chrome/browser/sync/glue/ui_model_worker.h"
11 #include "chrome/test/base/testing_profile.h"
12 #include "components/sync_driver/change_processor_mock.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/test/test_browser_thread_bundle.h"
15 #include "sync/internal_api/public/base/model_type.h"
16 #include "sync/internal_api/public/test/test_user_share.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace browser_sync
{
25 using ::testing::InSequence
;
26 using ::testing::Return
;
27 using ::testing::StrictMock
;
28 using content::BrowserThread
;
29 using syncer::FIRST_REAL_MODEL_TYPE
;
30 using syncer::AUTOFILL
;
31 using syncer::BOOKMARKS
;
32 using syncer::PREFERENCES
;
35 using syncer::PASSWORDS
;
36 using syncer::MODEL_TYPE_COUNT
;
37 using syncer::ModelTypeSet
;
38 using syncer::ModelType
;
39 using syncer::ModelTypeFromInt
;
41 void TriggerChanges(SyncBackendRegistrar
* registrar
, ModelType type
) {
42 registrar
->OnChangesApplied(type
, 0, NULL
,
43 syncer::ImmutableChangeRecordList());
44 registrar
->OnChangesComplete(type
);
47 // Flaky: https://crbug.com/498238
48 class SyncBackendRegistrarTest
: public testing::Test
{
50 void TestNonUIDataTypeActivationAsync(sync_driver::ChangeProcessor
* processor
,
51 base::WaitableEvent
* done
) {
52 registrar_
->ActivateDataType(AUTOFILL
,
55 test_user_share_
.user_share());
56 syncer::ModelSafeRoutingInfo expected_routing_info
;
57 expected_routing_info
[AUTOFILL
] = syncer::GROUP_DB
;
58 ExpectRoutingInfo(registrar_
.get(), expected_routing_info
);
59 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet(AUTOFILL
));
60 TriggerChanges(registrar_
.get(), AUTOFILL
);
65 SyncBackendRegistrarTest()
66 : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD
|
67 content::TestBrowserThreadBundle::REAL_FILE_THREAD
|
68 content::TestBrowserThreadBundle::REAL_IO_THREAD
),
71 ~SyncBackendRegistrarTest() override
{}
73 void SetUp() override
{
74 test_user_share_
.SetUp();
75 registrar_
.reset(new SyncBackendRegistrar("test", &profile_
,
76 scoped_ptr
<base::Thread
>()));
77 sync_thread_
= registrar_
->sync_thread();
80 void TearDown() override
{
81 registrar_
->RequestWorkerStopOnUIThread();
82 test_user_share_
.TearDown();
83 sync_thread_
->task_runner()->PostTask(
84 FROM_HERE
, base::Bind(&SyncBackendRegistrar::Shutdown
,
85 base::Unretained(registrar_
.release())));
86 sync_thread_
->WaitUntilThreadStarted();
87 sync_thread_
->message_loop()->RunUntilIdle();
90 void ExpectRoutingInfo(
91 SyncBackendRegistrar
* registrar
,
92 const syncer::ModelSafeRoutingInfo
& expected_routing_info
) {
93 syncer::ModelSafeRoutingInfo routing_info
;
94 registrar
->GetModelSafeRoutingInfo(&routing_info
);
95 EXPECT_EQ(expected_routing_info
, routing_info
);
98 void ExpectHasProcessorsForTypes(const SyncBackendRegistrar
& registrar
,
100 for (int i
= FIRST_REAL_MODEL_TYPE
; i
< MODEL_TYPE_COUNT
; ++i
) {
101 ModelType model_type
= ModelTypeFromInt(i
);
102 EXPECT_EQ(types
.Has(model_type
),
103 registrar_
->IsTypeActivatedForTest(model_type
));
107 content::TestBrowserThreadBundle thread_bundle_
;
108 syncer::TestUserShare test_user_share_
;
109 TestingProfile profile_
;
110 scoped_ptr
<SyncBackendRegistrar
> registrar_
;
112 base::Thread
* sync_thread_
;
115 TEST_F(SyncBackendRegistrarTest
, ConstructorEmpty
) {
116 registrar_
->SetInitialTypes(ModelTypeSet());
117 EXPECT_FALSE(registrar_
->IsNigoriEnabled());
119 std::vector
<scoped_refptr
<syncer::ModelSafeWorker
> > workers
;
120 registrar_
->GetWorkers(&workers
);
121 EXPECT_EQ(4u, workers
.size());
123 ExpectRoutingInfo(registrar_
.get(), syncer::ModelSafeRoutingInfo());
124 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
127 TEST_F(SyncBackendRegistrarTest
, ConstructorNonEmpty
) {
128 const ModelTypeSet
initial_types(BOOKMARKS
, NIGORI
, PASSWORDS
);
129 registrar_
->SetInitialTypes(initial_types
);
130 EXPECT_TRUE(registrar_
->IsNigoriEnabled());
132 std::vector
<scoped_refptr
<syncer::ModelSafeWorker
> > workers
;
133 registrar_
->GetWorkers(&workers
);
134 EXPECT_EQ(4u, workers
.size());
137 syncer::ModelSafeRoutingInfo expected_routing_info
;
138 expected_routing_info
[BOOKMARKS
] = syncer::GROUP_PASSIVE
;
139 expected_routing_info
[NIGORI
] = syncer::GROUP_PASSIVE
;
140 // Passwords dropped because of no password store.
141 ExpectRoutingInfo(registrar_
.get(), expected_routing_info
);
143 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
146 TEST_F(SyncBackendRegistrarTest
, ConfigureDataTypes
) {
147 registrar_
->SetInitialTypes(ModelTypeSet());
150 const ModelTypeSet
types1(BOOKMARKS
, NIGORI
, AUTOFILL
);
152 registrar_
->ConfigureDataTypes(types1
, ModelTypeSet()).Equals(types1
));
154 syncer::ModelSafeRoutingInfo expected_routing_info
;
155 expected_routing_info
[BOOKMARKS
] = syncer::GROUP_PASSIVE
;
156 expected_routing_info
[NIGORI
] = syncer::GROUP_PASSIVE
;
157 expected_routing_info
[AUTOFILL
] = syncer::GROUP_PASSIVE
;
158 ExpectRoutingInfo(registrar_
.get(), expected_routing_info
);
160 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
161 EXPECT_TRUE(types1
.Equals(registrar_
->GetLastConfiguredTypes()));
164 const ModelTypeSet
types2(PREFERENCES
, THEMES
);
165 EXPECT_TRUE(registrar_
->ConfigureDataTypes(types2
, types1
).Equals(types2
));
167 syncer::ModelSafeRoutingInfo expected_routing_info
;
168 expected_routing_info
[PREFERENCES
] = syncer::GROUP_PASSIVE
;
169 expected_routing_info
[THEMES
] = syncer::GROUP_PASSIVE
;
170 ExpectRoutingInfo(registrar_
.get(), expected_routing_info
);
172 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
173 EXPECT_TRUE(types2
.Equals(registrar_
->GetLastConfiguredTypes()));
176 EXPECT_TRUE(registrar_
->ConfigureDataTypes(ModelTypeSet(), types2
).Empty());
177 ExpectRoutingInfo(registrar_
.get(), syncer::ModelSafeRoutingInfo());
178 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
179 EXPECT_TRUE(ModelTypeSet().Equals(registrar_
->GetLastConfiguredTypes()));
182 TEST_F(SyncBackendRegistrarTest
, ActivateDeactivateUIDataType
) {
183 InSequence in_sequence
;
184 registrar_
->SetInitialTypes(ModelTypeSet());
186 // Should do nothing.
187 TriggerChanges(registrar_
.get(), BOOKMARKS
);
189 StrictMock
<sync_driver::ChangeProcessorMock
> change_processor_mock
;
190 EXPECT_CALL(change_processor_mock
, StartImpl());
191 EXPECT_CALL(change_processor_mock
, IsRunning())
192 .WillRepeatedly(Return(true));
193 EXPECT_CALL(change_processor_mock
, ApplyChangesFromSyncModel(NULL
, _
, _
));
194 EXPECT_CALL(change_processor_mock
, IsRunning())
195 .WillRepeatedly(Return(true));
196 EXPECT_CALL(change_processor_mock
, CommitChangesFromSyncModel());
197 EXPECT_CALL(change_processor_mock
, IsRunning())
198 .WillRepeatedly(Return(false));
200 const ModelTypeSet
types(BOOKMARKS
);
202 registrar_
->ConfigureDataTypes(types
, ModelTypeSet()).Equals(types
));
203 registrar_
->ActivateDataType(BOOKMARKS
, syncer::GROUP_UI
,
204 &change_processor_mock
,
205 test_user_share_
.user_share());
207 syncer::ModelSafeRoutingInfo expected_routing_info
;
208 expected_routing_info
[BOOKMARKS
] = syncer::GROUP_UI
;
209 ExpectRoutingInfo(registrar_
.get(), expected_routing_info
);
211 ExpectHasProcessorsForTypes(*registrar_
, types
);
213 TriggerChanges(registrar_
.get(), BOOKMARKS
);
215 registrar_
->DeactivateDataType(BOOKMARKS
);
216 ExpectRoutingInfo(registrar_
.get(), syncer::ModelSafeRoutingInfo());
217 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
219 // Should do nothing.
220 TriggerChanges(registrar_
.get(), BOOKMARKS
);
223 TEST_F(SyncBackendRegistrarTest
, ActivateDeactivateNonUIDataType
) {
224 InSequence in_sequence
;
225 registrar_
->SetInitialTypes(ModelTypeSet());
227 // Should do nothing.
228 TriggerChanges(registrar_
.get(), AUTOFILL
);
230 StrictMock
<sync_driver::ChangeProcessorMock
> change_processor_mock
;
231 EXPECT_CALL(change_processor_mock
, StartImpl());
232 EXPECT_CALL(change_processor_mock
, IsRunning())
233 .WillRepeatedly(Return(true));
234 EXPECT_CALL(change_processor_mock
, ApplyChangesFromSyncModel(NULL
, _
, _
));
235 EXPECT_CALL(change_processor_mock
, IsRunning())
236 .WillRepeatedly(Return(true));
237 EXPECT_CALL(change_processor_mock
, CommitChangesFromSyncModel());
238 EXPECT_CALL(change_processor_mock
, IsRunning())
239 .WillRepeatedly(Return(false));
241 const ModelTypeSet
types(AUTOFILL
);
243 registrar_
->ConfigureDataTypes(types
, ModelTypeSet()).Equals(types
));
245 base::WaitableEvent
done(false, false);
246 BrowserThread::PostTask(
249 base::Bind(&SyncBackendRegistrarTest::TestNonUIDataTypeActivationAsync
,
250 base::Unretained(this),
251 &change_processor_mock
,
255 registrar_
->DeactivateDataType(AUTOFILL
);
256 ExpectRoutingInfo(registrar_
.get(), syncer::ModelSafeRoutingInfo());
257 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
259 // Should do nothing.
260 TriggerChanges(registrar_
.get(), AUTOFILL
);
263 class SyncBackendRegistrarShutdownTest
: public testing::Test
{
265 void BlockDBThread() {
266 EXPECT_FALSE(db_thread_lock_
.Try());
268 db_thread_blocked_
.Signal();
269 base::AutoLock
l(db_thread_lock_
);
273 friend class TestRegistrar
;
275 SyncBackendRegistrarShutdownTest()
276 : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD
|
277 content::TestBrowserThreadBundle::REAL_FILE_THREAD
|
278 content::TestBrowserThreadBundle::REAL_IO_THREAD
),
279 db_thread_blocked_(false, false) {
280 quit_closure_
= run_loop_
.QuitClosure();
283 ~SyncBackendRegistrarShutdownTest() override
{}
285 void PostQuitOnUIMessageLoop() {
286 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, quit_closure_
);
289 content::TestBrowserThreadBundle thread_bundle_
;
290 TestingProfile profile_
;
291 base::WaitableEvent db_thread_blocked_
;
292 base::Lock db_thread_lock_
;
293 base::RunLoop run_loop_
;
294 base::Closure quit_closure_
;
297 // Wrap SyncBackendRegistrar so that we can monitor its lifetime.
298 class TestRegistrar
: public SyncBackendRegistrar
{
300 explicit TestRegistrar(Profile
* profile
,
301 SyncBackendRegistrarShutdownTest
* test
)
302 : SyncBackendRegistrar("test", profile
, scoped_ptr
<base::Thread
>()),
305 ~TestRegistrar() override
{ test_
->PostQuitOnUIMessageLoop(); }
308 SyncBackendRegistrarShutdownTest
* test_
;
311 TEST_F(SyncBackendRegistrarShutdownTest
, BlockingShutdown
) {
312 // Take ownership of |db_thread_lock_| so that the DB thread can't acquire it.
313 db_thread_lock_
.Acquire();
315 // This will block the DB thread by waiting on |db_thread_lock_|.
316 BrowserThread::PostTask(
319 base::Bind(&SyncBackendRegistrarShutdownTest::BlockDBThread
,
320 base::Unretained(this)));
322 scoped_ptr
<TestRegistrar
> registrar(new TestRegistrar(&profile_
, this));
323 base::Thread
* sync_thread
= registrar
->sync_thread();
325 // Stop here until the DB thread gets a chance to run and block on the lock.
326 // Please note that since the task above didn't finish, the task to
327 // initialize the worker on the DB thread hasn't had a chance to run yet too.
328 // Which means ModelSafeWorker::SetWorkingLoopToCurrent hasn't been called
329 // for the DB worker.
330 db_thread_blocked_
.Wait();
332 registrar
->SetInitialTypes(ModelTypeSet());
334 // Start the shutdown.
335 registrar
->RequestWorkerStopOnUIThread();
337 sync_thread
->task_runner()->PostTask(
338 FROM_HERE
, base::Bind(&SyncBackendRegistrar::Shutdown
,
339 base::Unretained(registrar
.release())));
341 // Make sure the thread starts running.
342 sync_thread
->WaitUntilThreadStarted();
344 // The test verifies that the sync thread doesn't block because
345 // of the blocked DB thread and can finish the shutdown.
346 sync_thread
->message_loop()->RunUntilIdle();
348 db_thread_lock_
.Release();
350 // Run the main thread loop until all workers have been removed and the
351 // registrar destroyed.
357 } // namespace browser_sync