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 "chrome/browser/sync/glue/ui_model_worker.h"
8 #include "chrome/test/base/testing_profile.h"
9 #include "components/sync_driver/change_processor_mock.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/test/test_browser_thread_bundle.h"
12 #include "sync/internal_api/public/base/model_type.h"
13 #include "sync/internal_api/public/test/test_user_share.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 namespace browser_sync
{
22 using ::testing::InSequence
;
23 using ::testing::Return
;
24 using ::testing::StrictMock
;
25 using content::BrowserThread
;
26 using syncer::FIRST_REAL_MODEL_TYPE
;
27 using syncer::AUTOFILL
;
28 using syncer::BOOKMARKS
;
29 using syncer::PREFERENCES
;
32 using syncer::PASSWORDS
;
33 using syncer::MODEL_TYPE_COUNT
;
34 using syncer::ModelTypeSet
;
35 using syncer::ModelType
;
36 using syncer::ModelTypeFromInt
;
38 void TriggerChanges(SyncBackendRegistrar
* registrar
, ModelType type
) {
39 registrar
->OnChangesApplied(type
, 0, NULL
,
40 syncer::ImmutableChangeRecordList());
41 registrar
->OnChangesComplete(type
);
44 class SyncBackendRegistrarTest
: public testing::Test
{
46 void TestNonUIDataTypeActivationAsync(sync_driver::ChangeProcessor
* processor
,
47 base::WaitableEvent
* done
) {
48 registrar_
->ActivateDataType(AUTOFILL
,
51 test_user_share_
.user_share());
52 syncer::ModelSafeRoutingInfo expected_routing_info
;
53 expected_routing_info
[AUTOFILL
] = syncer::GROUP_DB
;
54 ExpectRoutingInfo(registrar_
.get(), expected_routing_info
);
55 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet(AUTOFILL
));
56 TriggerChanges(registrar_
.get(), AUTOFILL
);
61 SyncBackendRegistrarTest()
63 thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD
|
64 content::TestBrowserThreadBundle::REAL_FILE_THREAD
|
65 content::TestBrowserThreadBundle::REAL_IO_THREAD
) {}
67 virtual ~SyncBackendRegistrarTest() {}
69 virtual void SetUp() {
70 test_user_share_
.SetUp();
71 registrar_
.reset(new SyncBackendRegistrar("test", &profile_
,
72 scoped_ptr
<base::Thread
>()));
73 sync_thread_
= registrar_
->sync_thread();
76 virtual void TearDown() {
77 registrar_
->RequestWorkerStopOnUIThread();
78 test_user_share_
.TearDown();
79 sync_thread_
->message_loop()->PostTask(
81 base::Bind(&SyncBackendRegistrar::Shutdown
,
82 base::Unretained(registrar_
.release())));
83 sync_thread_
->message_loop()->RunUntilIdle();
86 void ExpectRoutingInfo(
87 SyncBackendRegistrar
* registrar
,
88 const syncer::ModelSafeRoutingInfo
& expected_routing_info
) {
89 syncer::ModelSafeRoutingInfo routing_info
;
90 registrar
->GetModelSafeRoutingInfo(&routing_info
);
91 EXPECT_EQ(expected_routing_info
, routing_info
);
94 void ExpectHasProcessorsForTypes(const SyncBackendRegistrar
& registrar
,
96 for (int i
= FIRST_REAL_MODEL_TYPE
; i
< MODEL_TYPE_COUNT
; ++i
) {
97 ModelType model_type
= ModelTypeFromInt(i
);
98 EXPECT_EQ(types
.Has(model_type
),
99 registrar_
->IsTypeActivatedForTest(model_type
));
103 syncer::TestUserShare test_user_share_
;
104 TestingProfile profile_
;
105 scoped_ptr
<SyncBackendRegistrar
> registrar_
;
107 base::Thread
* sync_thread_
;
108 content::TestBrowserThreadBundle thread_bundle_
;
111 TEST_F(SyncBackendRegistrarTest
, ConstructorEmpty
) {
112 registrar_
->SetInitialTypes(ModelTypeSet());
113 EXPECT_FALSE(registrar_
->IsNigoriEnabled());
115 std::vector
<scoped_refptr
<syncer::ModelSafeWorker
> > workers
;
116 registrar_
->GetWorkers(&workers
);
117 EXPECT_EQ(4u, workers
.size());
119 ExpectRoutingInfo(registrar_
.get(), syncer::ModelSafeRoutingInfo());
120 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
123 TEST_F(SyncBackendRegistrarTest
, ConstructorNonEmpty
) {
124 const ModelTypeSet
initial_types(BOOKMARKS
, NIGORI
, PASSWORDS
);
125 registrar_
->SetInitialTypes(initial_types
);
126 EXPECT_TRUE(registrar_
->IsNigoriEnabled());
128 std::vector
<scoped_refptr
<syncer::ModelSafeWorker
> > workers
;
129 registrar_
->GetWorkers(&workers
);
130 EXPECT_EQ(4u, workers
.size());
133 syncer::ModelSafeRoutingInfo expected_routing_info
;
134 expected_routing_info
[BOOKMARKS
] = syncer::GROUP_PASSIVE
;
135 expected_routing_info
[NIGORI
] = syncer::GROUP_PASSIVE
;
136 // Passwords dropped because of no password store.
137 ExpectRoutingInfo(registrar_
.get(), expected_routing_info
);
139 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
142 TEST_F(SyncBackendRegistrarTest
, ConfigureDataTypes
) {
143 registrar_
->SetInitialTypes(ModelTypeSet());
146 const ModelTypeSet
types1(BOOKMARKS
, NIGORI
, AUTOFILL
);
148 registrar_
->ConfigureDataTypes(types1
, ModelTypeSet()).Equals(types1
));
150 syncer::ModelSafeRoutingInfo expected_routing_info
;
151 expected_routing_info
[BOOKMARKS
] = syncer::GROUP_PASSIVE
;
152 expected_routing_info
[NIGORI
] = syncer::GROUP_PASSIVE
;
153 expected_routing_info
[AUTOFILL
] = syncer::GROUP_PASSIVE
;
154 ExpectRoutingInfo(registrar_
.get(), expected_routing_info
);
156 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
157 EXPECT_TRUE(types1
.Equals(registrar_
->GetLastConfiguredTypes()));
160 const ModelTypeSet
types2(PREFERENCES
, THEMES
);
161 EXPECT_TRUE(registrar_
->ConfigureDataTypes(types2
, types1
).Equals(types2
));
163 syncer::ModelSafeRoutingInfo expected_routing_info
;
164 expected_routing_info
[PREFERENCES
] = syncer::GROUP_PASSIVE
;
165 expected_routing_info
[THEMES
] = syncer::GROUP_PASSIVE
;
166 ExpectRoutingInfo(registrar_
.get(), expected_routing_info
);
168 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
169 EXPECT_TRUE(types2
.Equals(registrar_
->GetLastConfiguredTypes()));
172 EXPECT_TRUE(registrar_
->ConfigureDataTypes(ModelTypeSet(), types2
).Empty());
173 ExpectRoutingInfo(registrar_
.get(), syncer::ModelSafeRoutingInfo());
174 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
175 EXPECT_TRUE(ModelTypeSet().Equals(registrar_
->GetLastConfiguredTypes()));
178 TEST_F(SyncBackendRegistrarTest
, ActivateDeactivateUIDataType
) {
179 InSequence in_sequence
;
180 registrar_
->SetInitialTypes(ModelTypeSet());
182 // Should do nothing.
183 TriggerChanges(registrar_
.get(), BOOKMARKS
);
185 StrictMock
<sync_driver::ChangeProcessorMock
> change_processor_mock
;
186 EXPECT_CALL(change_processor_mock
, StartImpl());
187 EXPECT_CALL(change_processor_mock
, IsRunning())
188 .WillRepeatedly(Return(true));
189 EXPECT_CALL(change_processor_mock
, ApplyChangesFromSyncModel(NULL
, _
, _
));
190 EXPECT_CALL(change_processor_mock
, IsRunning())
191 .WillRepeatedly(Return(true));
192 EXPECT_CALL(change_processor_mock
, CommitChangesFromSyncModel());
193 EXPECT_CALL(change_processor_mock
, IsRunning())
194 .WillRepeatedly(Return(false));
196 const ModelTypeSet
types(BOOKMARKS
);
198 registrar_
->ConfigureDataTypes(types
, ModelTypeSet()).Equals(types
));
199 registrar_
->ActivateDataType(BOOKMARKS
, syncer::GROUP_UI
,
200 &change_processor_mock
,
201 test_user_share_
.user_share());
203 syncer::ModelSafeRoutingInfo expected_routing_info
;
204 expected_routing_info
[BOOKMARKS
] = syncer::GROUP_UI
;
205 ExpectRoutingInfo(registrar_
.get(), expected_routing_info
);
207 ExpectHasProcessorsForTypes(*registrar_
, types
);
209 TriggerChanges(registrar_
.get(), BOOKMARKS
);
211 registrar_
->DeactivateDataType(BOOKMARKS
);
212 ExpectRoutingInfo(registrar_
.get(), syncer::ModelSafeRoutingInfo());
213 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
215 // Should do nothing.
216 TriggerChanges(registrar_
.get(), BOOKMARKS
);
219 TEST_F(SyncBackendRegistrarTest
, ActivateDeactivateNonUIDataType
) {
220 InSequence in_sequence
;
221 registrar_
->SetInitialTypes(ModelTypeSet());
223 // Should do nothing.
224 TriggerChanges(registrar_
.get(), AUTOFILL
);
226 StrictMock
<sync_driver::ChangeProcessorMock
> change_processor_mock
;
227 EXPECT_CALL(change_processor_mock
, StartImpl());
228 EXPECT_CALL(change_processor_mock
, IsRunning())
229 .WillRepeatedly(Return(true));
230 EXPECT_CALL(change_processor_mock
, ApplyChangesFromSyncModel(NULL
, _
, _
));
231 EXPECT_CALL(change_processor_mock
, IsRunning())
232 .WillRepeatedly(Return(true));
233 EXPECT_CALL(change_processor_mock
, CommitChangesFromSyncModel());
234 EXPECT_CALL(change_processor_mock
, IsRunning())
235 .WillRepeatedly(Return(false));
237 const ModelTypeSet
types(AUTOFILL
);
239 registrar_
->ConfigureDataTypes(types
, ModelTypeSet()).Equals(types
));
241 base::WaitableEvent
done(false, false);
242 BrowserThread::PostTask(
245 base::Bind(&SyncBackendRegistrarTest::TestNonUIDataTypeActivationAsync
,
246 base::Unretained(this),
247 &change_processor_mock
,
251 registrar_
->DeactivateDataType(AUTOFILL
);
252 ExpectRoutingInfo(registrar_
.get(), syncer::ModelSafeRoutingInfo());
253 ExpectHasProcessorsForTypes(*registrar_
, ModelTypeSet());
255 // Should do nothing.
256 TriggerChanges(registrar_
.get(), AUTOFILL
);
259 class SyncBackendRegistrarShutdownTest
: public testing::Test
{
261 void BlockDBThread() {
262 EXPECT_FALSE(db_thread_lock_
.Try());
264 db_thread_blocked_
.Signal();
265 base::AutoLock
l(db_thread_lock_
);
269 friend class TestRegistrar
;
271 SyncBackendRegistrarShutdownTest()
272 : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD
|
273 content::TestBrowserThreadBundle::REAL_FILE_THREAD
|
274 content::TestBrowserThreadBundle::REAL_IO_THREAD
),
275 db_thread_blocked_(false, false),
276 registrar_destroyed_(false, false) {}
278 virtual ~SyncBackendRegistrarShutdownTest() {}
280 content::TestBrowserThreadBundle thread_bundle_
;
281 base::WaitableEvent db_thread_blocked_
;
282 base::Lock db_thread_lock_
;
283 base::WaitableEvent registrar_destroyed_
;
286 // Wrap SyncBackendRegistrar so that we can monitor its lifetime.
287 class TestRegistrar
: public SyncBackendRegistrar
{
289 explicit TestRegistrar(Profile
* profile
,
290 SyncBackendRegistrarShutdownTest
* test
)
291 : SyncBackendRegistrar("test", profile
, scoped_ptr
<base::Thread
>()),
294 virtual ~TestRegistrar() { test_
->registrar_destroyed_
.Signal(); }
297 SyncBackendRegistrarShutdownTest
* test_
;
300 TEST_F(SyncBackendRegistrarShutdownTest
, BlockingShutdown
) {
301 // Take ownership of |db_thread_lock_| so that the DB thread can't acquire it.
302 db_thread_lock_
.Acquire();
304 // This will block the DB thread by waiting on |db_thread_lock_|.
305 BrowserThread::PostTask(
308 base::Bind(&SyncBackendRegistrarShutdownTest::BlockDBThread
,
309 base::Unretained(this)));
311 TestingProfile profile
;
312 scoped_ptr
<TestRegistrar
> registrar(new TestRegistrar(&profile
, this));
313 base::Thread
* sync_thread
= registrar
->sync_thread();
315 // Stop here until the DB thread gets a chance to run and block on the lock.
316 // Please note that since the task above didn't finish, the task to
317 // initialize the worker on the DB thread hasn't had a chance to run yet too.
318 // Which means ModelSafeWorker::SetWorkingLoopToCurrent hasn't been called
319 // for the DB worker.
320 db_thread_blocked_
.Wait();
322 registrar
->SetInitialTypes(ModelTypeSet());
324 // Start the shutdown.
325 registrar
->RequestWorkerStopOnUIThread();
326 sync_thread
->message_loop()->PostTask(
328 base::Bind(&SyncBackendRegistrar::Shutdown
,
329 base::Unretained(registrar
.release())));
331 // The test verifies that the sync thread doesn't block because
332 // of the blocked DB thread and can finish the shutdown.
333 sync_thread
->message_loop()->RunUntilIdle();
335 db_thread_lock_
.Release();
337 base::MessageLoop::current()->RunUntilIdle();
339 // This verifies that all workers have been removed and the registrar
341 registrar_destroyed_
.Wait();
346 } // namespace browser_sync