OLD | NEW |
| (Empty) |
1 // Copyright 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. | |
4 | |
5 #include "components/sync_driver/glue/sync_backend_registrar.h" | |
6 | |
7 #include "base/location.h" | |
8 #include "base/run_loop.h" | |
9 #include "base/single_thread_task_runner.h" | |
10 #include "components/sync/base/model_type.h" | |
11 #include "components/sync/core/test/test_user_share.h" | |
12 #include "components/sync/engine/passive_model_worker.h" | |
13 #include "components/sync_driver/change_processor_mock.h" | |
14 #include "components/sync_driver/fake_sync_client.h" | |
15 #include "components/sync_driver/glue/browser_thread_model_worker.h" | |
16 #include "components/sync_driver/sync_api_component_factory_mock.h" | |
17 #include "testing/gmock/include/gmock/gmock.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | |
19 | |
20 namespace browser_sync { | |
21 | |
22 namespace { | |
23 | |
24 using ::testing::_; | |
25 using ::testing::InSequence; | |
26 using ::testing::Return; | |
27 using ::testing::StrictMock; | |
28 using syncer::FIRST_REAL_MODEL_TYPE; | |
29 using syncer::AUTOFILL; | |
30 using syncer::BOOKMARKS; | |
31 using syncer::PREFERENCES; | |
32 using syncer::THEMES; | |
33 using syncer::NIGORI; | |
34 using syncer::PASSWORDS; | |
35 using syncer::MODEL_TYPE_COUNT; | |
36 using syncer::ModelTypeSet; | |
37 using syncer::ModelType; | |
38 using syncer::ModelTypeFromInt; | |
39 | |
40 void TriggerChanges(SyncBackendRegistrar* registrar, ModelType type) { | |
41 registrar->OnChangesApplied(type, 0, NULL, | |
42 syncer::ImmutableChangeRecordList()); | |
43 registrar->OnChangesComplete(type); | |
44 } | |
45 | |
46 class RegistrarSyncClient : public sync_driver::FakeSyncClient { | |
47 public: | |
48 RegistrarSyncClient( | |
49 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner, | |
50 const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner, | |
51 const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner) | |
52 : ui_task_runner_(ui_task_runner), | |
53 db_task_runner_(db_task_runner), | |
54 file_task_runner_(file_task_runner) {} | |
55 | |
56 scoped_refptr<syncer::ModelSafeWorker> CreateModelWorkerForGroup( | |
57 syncer::ModelSafeGroup group, | |
58 syncer::WorkerLoopDestructionObserver* observer) override { | |
59 switch (group) { | |
60 case syncer::GROUP_UI: | |
61 return new BrowserThreadModelWorker(ui_task_runner_, group, observer); | |
62 case syncer::GROUP_DB: | |
63 return new BrowserThreadModelWorker(db_task_runner_, group, observer); | |
64 case syncer::GROUP_FILE: | |
65 return new BrowserThreadModelWorker(file_task_runner_, group, observer); | |
66 case syncer::GROUP_PASSIVE: | |
67 return new syncer::PassiveModelWorker(observer); | |
68 default: | |
69 return nullptr; | |
70 } | |
71 } | |
72 | |
73 private: | |
74 const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; | |
75 const scoped_refptr<base::SingleThreadTaskRunner> db_task_runner_; | |
76 const scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; | |
77 }; | |
78 | |
79 // Flaky: https://crbug.com/498238 | |
80 class SyncBackendRegistrarTest : public testing::Test { | |
81 public: | |
82 void TestNonUIDataTypeActivationAsync(sync_driver::ChangeProcessor* processor, | |
83 base::WaitableEvent* done) { | |
84 registrar_->ActivateDataType(AUTOFILL, | |
85 syncer::GROUP_DB, | |
86 processor, | |
87 test_user_share_.user_share()); | |
88 syncer::ModelSafeRoutingInfo expected_routing_info; | |
89 expected_routing_info[AUTOFILL] = syncer::GROUP_DB; | |
90 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
91 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet(AUTOFILL)); | |
92 TriggerChanges(registrar_.get(), AUTOFILL); | |
93 done->Signal(); | |
94 } | |
95 | |
96 protected: | |
97 SyncBackendRegistrarTest() | |
98 : db_thread_("DBThreadForTest"), | |
99 file_thread_("FileThreadForTest"), | |
100 sync_thread_(NULL) {} | |
101 | |
102 ~SyncBackendRegistrarTest() override {} | |
103 | |
104 void SetUp() override { | |
105 db_thread_.StartAndWaitForTesting(); | |
106 file_thread_.StartAndWaitForTesting(); | |
107 test_user_share_.SetUp(); | |
108 sync_client_.reset(new RegistrarSyncClient( | |
109 ui_task_runner(), db_task_runner(), file_task_runner())); | |
110 registrar_.reset(new SyncBackendRegistrar( | |
111 "test", sync_client_.get(), std::unique_ptr<base::Thread>(), | |
112 ui_task_runner(), db_task_runner(), file_task_runner())); | |
113 sync_thread_ = registrar_->sync_thread(); | |
114 } | |
115 | |
116 void TearDown() override { | |
117 registrar_->RequestWorkerStopOnUIThread(); | |
118 test_user_share_.TearDown(); | |
119 sync_thread_->task_runner()->PostTask( | |
120 FROM_HERE, base::Bind(&SyncBackendRegistrar::Shutdown, | |
121 base::Unretained(registrar_.release()))); | |
122 sync_thread_->WaitUntilThreadStarted(); | |
123 base::RunLoop().RunUntilIdle(); | |
124 } | |
125 | |
126 void ExpectRoutingInfo( | |
127 SyncBackendRegistrar* registrar, | |
128 const syncer::ModelSafeRoutingInfo& expected_routing_info) { | |
129 syncer::ModelSafeRoutingInfo routing_info; | |
130 registrar->GetModelSafeRoutingInfo(&routing_info); | |
131 EXPECT_EQ(expected_routing_info, routing_info); | |
132 } | |
133 | |
134 void ExpectHasProcessorsForTypes(const SyncBackendRegistrar& registrar, | |
135 ModelTypeSet types) { | |
136 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { | |
137 ModelType model_type = ModelTypeFromInt(i); | |
138 EXPECT_EQ(types.Has(model_type), | |
139 registrar_->IsTypeActivatedForTest(model_type)); | |
140 } | |
141 } | |
142 | |
143 const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner() { | |
144 return message_loop_.task_runner(); | |
145 } | |
146 | |
147 const scoped_refptr<base::SingleThreadTaskRunner> db_task_runner() { | |
148 return db_thread_.task_runner(); | |
149 } | |
150 | |
151 const scoped_refptr<base::SingleThreadTaskRunner> file_task_runner() { | |
152 return db_thread_.task_runner(); | |
153 } | |
154 | |
155 base::MessageLoop message_loop_; | |
156 base::Thread db_thread_; | |
157 base::Thread file_thread_; | |
158 | |
159 syncer::TestUserShare test_user_share_; | |
160 std::unique_ptr<RegistrarSyncClient> sync_client_; | |
161 std::unique_ptr<SyncBackendRegistrar> registrar_; | |
162 | |
163 base::Thread* sync_thread_; | |
164 }; | |
165 | |
166 TEST_F(SyncBackendRegistrarTest, ConstructorEmpty) { | |
167 registrar_->SetInitialTypes(ModelTypeSet()); | |
168 EXPECT_FALSE(registrar_->IsNigoriEnabled()); | |
169 { | |
170 std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers; | |
171 registrar_->GetWorkers(&workers); | |
172 EXPECT_EQ(4u, workers.size()); | |
173 } | |
174 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); | |
175 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
176 } | |
177 | |
178 TEST_F(SyncBackendRegistrarTest, ConstructorNonEmpty) { | |
179 const ModelTypeSet initial_types(BOOKMARKS, NIGORI, PASSWORDS); | |
180 registrar_->RegisterNonBlockingType(BOOKMARKS); | |
181 registrar_->SetInitialTypes(initial_types); | |
182 EXPECT_TRUE(registrar_->IsNigoriEnabled()); | |
183 { | |
184 std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers; | |
185 registrar_->GetWorkers(&workers); | |
186 EXPECT_EQ(4u, workers.size()); | |
187 } | |
188 { | |
189 syncer::ModelSafeRoutingInfo expected_routing_info; | |
190 expected_routing_info[BOOKMARKS] = syncer::GROUP_NON_BLOCKING; | |
191 expected_routing_info[NIGORI] = syncer::GROUP_PASSIVE; | |
192 // Passwords dropped because of no password store. | |
193 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
194 } | |
195 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
196 } | |
197 | |
198 TEST_F(SyncBackendRegistrarTest, ConfigureDataTypes) { | |
199 registrar_->RegisterNonBlockingType(BOOKMARKS); | |
200 registrar_->SetInitialTypes(ModelTypeSet()); | |
201 | |
202 // Add. | |
203 const ModelTypeSet types1(BOOKMARKS, NIGORI, AUTOFILL); | |
204 EXPECT_EQ(types1, registrar_->ConfigureDataTypes(types1, ModelTypeSet())); | |
205 { | |
206 syncer::ModelSafeRoutingInfo expected_routing_info; | |
207 expected_routing_info[BOOKMARKS] = syncer::GROUP_NON_BLOCKING; | |
208 expected_routing_info[NIGORI] = syncer::GROUP_PASSIVE; | |
209 expected_routing_info[AUTOFILL] = syncer::GROUP_PASSIVE; | |
210 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
211 } | |
212 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
213 EXPECT_EQ(types1, registrar_->GetLastConfiguredTypes()); | |
214 | |
215 // Add and remove. | |
216 const ModelTypeSet types2(PREFERENCES, THEMES); | |
217 EXPECT_EQ(types2, registrar_->ConfigureDataTypes(types2, types1)); | |
218 { | |
219 syncer::ModelSafeRoutingInfo expected_routing_info; | |
220 expected_routing_info[PREFERENCES] = syncer::GROUP_PASSIVE; | |
221 expected_routing_info[THEMES] = syncer::GROUP_PASSIVE; | |
222 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
223 } | |
224 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
225 EXPECT_EQ(types2, registrar_->GetLastConfiguredTypes()); | |
226 | |
227 // Remove. | |
228 EXPECT_TRUE(registrar_->ConfigureDataTypes(ModelTypeSet(), types2).Empty()); | |
229 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); | |
230 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
231 EXPECT_EQ(ModelTypeSet(), registrar_->GetLastConfiguredTypes()); | |
232 } | |
233 | |
234 TEST_F(SyncBackendRegistrarTest, ActivateDeactivateUIDataType) { | |
235 InSequence in_sequence; | |
236 registrar_->SetInitialTypes(ModelTypeSet()); | |
237 | |
238 // Should do nothing. | |
239 TriggerChanges(registrar_.get(), BOOKMARKS); | |
240 | |
241 StrictMock<sync_driver::ChangeProcessorMock> change_processor_mock; | |
242 EXPECT_CALL(change_processor_mock, StartImpl()); | |
243 EXPECT_CALL(change_processor_mock, IsRunning()) | |
244 .WillRepeatedly(Return(true)); | |
245 EXPECT_CALL(change_processor_mock, ApplyChangesFromSyncModel(NULL, _, _)); | |
246 EXPECT_CALL(change_processor_mock, IsRunning()) | |
247 .WillRepeatedly(Return(true)); | |
248 EXPECT_CALL(change_processor_mock, CommitChangesFromSyncModel()); | |
249 EXPECT_CALL(change_processor_mock, IsRunning()) | |
250 .WillRepeatedly(Return(false)); | |
251 | |
252 const ModelTypeSet types(BOOKMARKS); | |
253 EXPECT_EQ(types, registrar_->ConfigureDataTypes(types, ModelTypeSet())); | |
254 registrar_->ActivateDataType(BOOKMARKS, syncer::GROUP_UI, | |
255 &change_processor_mock, | |
256 test_user_share_.user_share()); | |
257 { | |
258 syncer::ModelSafeRoutingInfo expected_routing_info; | |
259 expected_routing_info[BOOKMARKS] = syncer::GROUP_UI; | |
260 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
261 } | |
262 ExpectHasProcessorsForTypes(*registrar_, types); | |
263 | |
264 TriggerChanges(registrar_.get(), BOOKMARKS); | |
265 | |
266 registrar_->DeactivateDataType(BOOKMARKS); | |
267 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); | |
268 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
269 | |
270 // Should do nothing. | |
271 TriggerChanges(registrar_.get(), BOOKMARKS); | |
272 } | |
273 | |
274 TEST_F(SyncBackendRegistrarTest, ActivateDeactivateNonUIDataType) { | |
275 InSequence in_sequence; | |
276 registrar_->SetInitialTypes(ModelTypeSet()); | |
277 | |
278 // Should do nothing. | |
279 TriggerChanges(registrar_.get(), AUTOFILL); | |
280 | |
281 StrictMock<sync_driver::ChangeProcessorMock> change_processor_mock; | |
282 EXPECT_CALL(change_processor_mock, StartImpl()); | |
283 EXPECT_CALL(change_processor_mock, IsRunning()) | |
284 .WillRepeatedly(Return(true)); | |
285 EXPECT_CALL(change_processor_mock, ApplyChangesFromSyncModel(NULL, _, _)); | |
286 EXPECT_CALL(change_processor_mock, IsRunning()) | |
287 .WillRepeatedly(Return(true)); | |
288 EXPECT_CALL(change_processor_mock, CommitChangesFromSyncModel()); | |
289 EXPECT_CALL(change_processor_mock, IsRunning()) | |
290 .WillRepeatedly(Return(false)); | |
291 | |
292 const ModelTypeSet types(AUTOFILL); | |
293 EXPECT_EQ(types, registrar_->ConfigureDataTypes(types, ModelTypeSet())); | |
294 | |
295 base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
296 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
297 db_task_runner()->PostTask( | |
298 FROM_HERE, | |
299 base::Bind(&SyncBackendRegistrarTest::TestNonUIDataTypeActivationAsync, | |
300 base::Unretained(this), &change_processor_mock, &done)); | |
301 done.Wait(); | |
302 | |
303 registrar_->DeactivateDataType(AUTOFILL); | |
304 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); | |
305 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
306 | |
307 // Should do nothing. | |
308 TriggerChanges(registrar_.get(), AUTOFILL); | |
309 } | |
310 | |
311 // Tests that registration and configuration of non-blocking data types is | |
312 // handled correctly in SyncBackendRegistrar. | |
313 TEST_F(SyncBackendRegistrarTest, ConfigureNonBlockingDataType) { | |
314 registrar_->RegisterNonBlockingType(AUTOFILL); | |
315 registrar_->RegisterNonBlockingType(BOOKMARKS); | |
316 | |
317 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); | |
318 // Simulate that initial sync was already done for AUTOFILL. | |
319 registrar_->AddRestoredNonBlockingType(AUTOFILL); | |
320 // It should be added to routing info and set of configured types. | |
321 EXPECT_EQ(ModelTypeSet(AUTOFILL), registrar_->GetLastConfiguredTypes()); | |
322 { | |
323 syncer::ModelSafeRoutingInfo expected_routing_info; | |
324 expected_routing_info[AUTOFILL] = syncer::GROUP_NON_BLOCKING; | |
325 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
326 } | |
327 | |
328 // Configure two non-blocking types. Initial sync wasn't done for BOOKMARKS so | |
329 // it should be included in types to be downloaded. | |
330 ModelTypeSet types_to_add(AUTOFILL, BOOKMARKS); | |
331 ModelTypeSet newly_added_types = | |
332 registrar_->ConfigureDataTypes(types_to_add, ModelTypeSet()); | |
333 EXPECT_EQ(ModelTypeSet(BOOKMARKS), newly_added_types); | |
334 EXPECT_EQ(types_to_add, registrar_->GetLastConfiguredTypes()); | |
335 { | |
336 syncer::ModelSafeRoutingInfo expected_routing_info; | |
337 expected_routing_info[AUTOFILL] = syncer::GROUP_NON_BLOCKING; | |
338 expected_routing_info[BOOKMARKS] = syncer::GROUP_NON_BLOCKING; | |
339 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
340 } | |
341 } | |
342 | |
343 class SyncBackendRegistrarShutdownTest : public testing::Test { | |
344 public: | |
345 void BlockDBThread() { | |
346 EXPECT_FALSE(db_thread_lock_.Try()); | |
347 | |
348 db_thread_blocked_.Signal(); | |
349 base::AutoLock l(db_thread_lock_); | |
350 } | |
351 | |
352 protected: | |
353 friend class TestRegistrar; | |
354 | |
355 SyncBackendRegistrarShutdownTest() | |
356 : db_thread_("DBThreadForTest"), | |
357 file_thread_("FileThreadForTest"), | |
358 db_thread_blocked_(base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
359 base::WaitableEvent::InitialState::NOT_SIGNALED) { | |
360 quit_closure_ = run_loop_.QuitClosure(); | |
361 } | |
362 | |
363 ~SyncBackendRegistrarShutdownTest() override {} | |
364 | |
365 void SetUp() override { | |
366 db_thread_.StartAndWaitForTesting(); | |
367 file_thread_.StartAndWaitForTesting(); | |
368 sync_client_.reset(new RegistrarSyncClient( | |
369 ui_task_runner(), db_task_runner(), file_task_runner())); | |
370 } | |
371 | |
372 void PostQuitOnUIMessageLoop() { | |
373 ui_task_runner()->PostTask(FROM_HERE, quit_closure_); | |
374 } | |
375 | |
376 const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner() { | |
377 return message_loop_.task_runner(); | |
378 } | |
379 | |
380 const scoped_refptr<base::SingleThreadTaskRunner> db_task_runner() { | |
381 return db_thread_.task_runner(); | |
382 } | |
383 | |
384 const scoped_refptr<base::SingleThreadTaskRunner> file_task_runner() { | |
385 return file_thread_.task_runner(); | |
386 } | |
387 | |
388 base::MessageLoop message_loop_; | |
389 base::Thread db_thread_; | |
390 base::Thread file_thread_; | |
391 | |
392 std::unique_ptr<RegistrarSyncClient> sync_client_; | |
393 base::WaitableEvent db_thread_blocked_; | |
394 | |
395 base::Lock db_thread_lock_; | |
396 base::RunLoop run_loop_; | |
397 base::Closure quit_closure_; | |
398 }; | |
399 | |
400 // Wrap SyncBackendRegistrar so that we can monitor its lifetime. | |
401 class TestRegistrar : public SyncBackendRegistrar { | |
402 public: | |
403 explicit TestRegistrar( | |
404 sync_driver::SyncClient* sync_client, | |
405 const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread, | |
406 const scoped_refptr<base::SingleThreadTaskRunner>& db_thread, | |
407 const scoped_refptr<base::SingleThreadTaskRunner>& file_thread, | |
408 SyncBackendRegistrarShutdownTest* test) | |
409 : SyncBackendRegistrar("test", | |
410 sync_client, | |
411 std::unique_ptr<base::Thread>(), | |
412 ui_thread, | |
413 db_thread, | |
414 file_thread), | |
415 test_(test) {} | |
416 | |
417 ~TestRegistrar() override { test_->PostQuitOnUIMessageLoop(); } | |
418 | |
419 private: | |
420 SyncBackendRegistrarShutdownTest* test_; | |
421 }; | |
422 | |
423 TEST_F(SyncBackendRegistrarShutdownTest, BlockingShutdown) { | |
424 // Take ownership of |db_thread_lock_| so that the DB thread can't acquire it. | |
425 db_thread_lock_.Acquire(); | |
426 | |
427 // This will block the DB thread by waiting on |db_thread_lock_|. | |
428 db_task_runner()->PostTask( | |
429 FROM_HERE, base::Bind(&SyncBackendRegistrarShutdownTest::BlockDBThread, | |
430 base::Unretained(this))); | |
431 | |
432 std::unique_ptr<TestRegistrar> registrar( | |
433 new TestRegistrar(sync_client_.get(), ui_task_runner(), db_task_runner(), | |
434 file_task_runner(), this)); | |
435 base::Thread* sync_thread = registrar->sync_thread(); | |
436 | |
437 // Stop here until the DB thread gets a chance to run and block on the lock. | |
438 // Please note that since the task above didn't finish, the task to | |
439 // initialize the worker on the DB thread hasn't had a chance to run yet too. | |
440 // Which means ModelSafeWorker::SetWorkingLoopToCurrent hasn't been called | |
441 // for the DB worker. | |
442 db_thread_blocked_.Wait(); | |
443 | |
444 registrar->SetInitialTypes(ModelTypeSet()); | |
445 | |
446 // Start the shutdown. | |
447 registrar->RequestWorkerStopOnUIThread(); | |
448 | |
449 sync_thread->task_runner()->PostTask( | |
450 FROM_HERE, base::Bind(&SyncBackendRegistrar::Shutdown, | |
451 base::Unretained(registrar.release()))); | |
452 | |
453 // Make sure the thread starts running. | |
454 sync_thread->WaitUntilThreadStarted(); | |
455 | |
456 // The test verifies that the sync thread doesn't block because | |
457 // of the blocked DB thread and can finish the shutdown. | |
458 base::RunLoop().RunUntilIdle(); | |
459 | |
460 db_thread_lock_.Release(); | |
461 | |
462 // Run the main thread loop until all workers have been removed and the | |
463 // registrar destroyed. | |
464 run_loop_.Run(); | |
465 } | |
466 | |
467 } // namespace | |
468 | |
469 } // namespace browser_sync | |
OLD | NEW |