Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / components / sync_driver / non_blocking_data_type_controller_unittest.cc
1 // Copyright 2014 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 <list>
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/sequenced_task_runner.h"
12 #include "base/test/test_simple_task_runner.h"
13 #include "components/sync_driver/non_blocking_data_type_controller.h"
14 #include "sync/engine/model_type_sync_proxy_impl.h"
15 #include "sync/engine/model_type_sync_worker.h"
16 #include "sync/internal_api/public/base/model_type.h"
17 #include "sync/internal_api/public/sync_context_proxy.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace sync_driver {
21
22 class ModelTypeSyncWorker;
23
24 namespace {
25
26 // A useless instance of ModelTypeSyncWorker.
27 class NullModelTypeSyncWorker : public syncer::ModelTypeSyncWorker {
28  public:
29   NullModelTypeSyncWorker();
30   virtual ~NullModelTypeSyncWorker();
31
32   virtual void EnqueueForCommit(
33       const syncer::CommitRequestDataList& list) OVERRIDE;
34 };
35
36 NullModelTypeSyncWorker::NullModelTypeSyncWorker() {
37 }
38
39 NullModelTypeSyncWorker::~NullModelTypeSyncWorker() {
40 }
41
42 void NullModelTypeSyncWorker::EnqueueForCommit(
43     const syncer::CommitRequestDataList& list) {
44   NOTREACHED() << "Not implemented.";
45 }
46
47 // A class that pretends to be the sync backend.
48 class MockSyncContext {
49  public:
50   void Connect(
51       syncer::ModelType type,
52       const scoped_refptr<base::SingleThreadTaskRunner>& model_task_runner,
53       const base::WeakPtr<syncer::ModelTypeSyncProxyImpl>& type_proxy) {
54     enabled_types_.Put(type);
55     model_task_runner->PostTask(
56         FROM_HERE,
57         base::Bind(&syncer::ModelTypeSyncProxyImpl::OnConnect,
58                    type_proxy,
59                    base::Passed(scoped_ptr<syncer::ModelTypeSyncWorker>(
60                                     new NullModelTypeSyncWorker()).Pass())));
61   }
62
63   void Disconnect(syncer::ModelType type) {
64     DCHECK(enabled_types_.Has(type));
65     enabled_types_.Remove(type);
66   }
67
68  private:
69   std::list<base::Closure> tasks_;
70   syncer::ModelTypeSet enabled_types_;
71 };
72
73 // A proxy to the MockSyncContext that implements SyncContextProxy.
74 class MockSyncContextProxy : public syncer::SyncContextProxy {
75  public:
76   MockSyncContextProxy(
77       MockSyncContext* sync_context,
78       const scoped_refptr<base::TestSimpleTaskRunner>& model_task_runner,
79       const scoped_refptr<base::TestSimpleTaskRunner>& sync_task_runner)
80       : mock_sync_context_(sync_context),
81         model_task_runner_(model_task_runner),
82         sync_task_runner_(sync_task_runner) {}
83   virtual ~MockSyncContextProxy() {}
84
85   virtual void ConnectTypeToSync(
86       syncer::ModelType type,
87       const syncer::DataTypeState& data_type_state,
88       const syncer::UpdateResponseDataList& saved_pending_updates,
89       const base::WeakPtr<syncer::ModelTypeSyncProxyImpl>& type_proxy)
90       OVERRIDE {
91     // Normally we'd use MessageLoopProxy::current() as the TaskRunner argument
92     // to Connect().  That won't work here in this test, so we use the
93     // model_task_runner_ that was injected for this purpose instead.
94     sync_task_runner_->PostTask(FROM_HERE,
95                                 base::Bind(&MockSyncContext::Connect,
96                                            base::Unretained(mock_sync_context_),
97                                            type,
98                                            model_task_runner_,
99                                            type_proxy));
100   }
101
102   virtual void Disconnect(syncer::ModelType type) OVERRIDE {
103     sync_task_runner_->PostTask(FROM_HERE,
104                                 base::Bind(&MockSyncContext::Disconnect,
105                                            base::Unretained(mock_sync_context_),
106                                            type));
107   }
108
109   virtual scoped_ptr<SyncContextProxy> Clone() const OVERRIDE {
110     return scoped_ptr<SyncContextProxy>(new MockSyncContextProxy(
111         mock_sync_context_, model_task_runner_, sync_task_runner_));
112   }
113
114  private:
115   MockSyncContext* mock_sync_context_;
116   scoped_refptr<base::TestSimpleTaskRunner> model_task_runner_;
117   scoped_refptr<base::TestSimpleTaskRunner> sync_task_runner_;
118 };
119
120 }  // namespace
121
122 class NonBlockingDataTypeControllerTest : public testing::Test {
123  public:
124   NonBlockingDataTypeControllerTest()
125       : type_sync_proxy_(syncer::DICTIONARY),
126         model_thread_(new base::TestSimpleTaskRunner()),
127         sync_thread_(new base::TestSimpleTaskRunner()),
128         controller_(syncer::DICTIONARY, true),
129         mock_context_proxy_(&mock_sync_context_, model_thread_, sync_thread_),
130         auto_run_tasks_(true) {}
131
132   virtual ~NonBlockingDataTypeControllerTest() {}
133
134   // Connects the sync type proxy to the NonBlockingDataTypeController.
135   void InitTypeSyncProxy() {
136     controller_.InitializeType(model_thread_,
137                                type_sync_proxy_.AsWeakPtrForUI());
138     if (auto_run_tasks_) {
139       RunAllTasks();
140     }
141   }
142
143   // Connects the sync backend to the NonBlockingDataTypeController.
144   void InitSyncBackend() {
145     controller_.InitializeSyncContext(mock_context_proxy_.Clone());
146     if (auto_run_tasks_) {
147       RunAllTasks();
148     }
149   }
150
151   // Disconnects the sync backend from the NonBlockingDataTypeController.
152   void UninitializeSyncBackend() {
153     controller_.ClearSyncContext();
154     if (auto_run_tasks_) {
155       RunAllTasks();
156     }
157   }
158
159   // Toggles the user's preference for syncing this type.
160   void SetIsPreferred(bool preferred) {
161     controller_.SetIsPreferred(preferred);
162     if (auto_run_tasks_) {
163       RunAllTasks();
164     }
165   }
166
167   // These threads can ping-pong for a bit so we run the model thread twice.
168   void RunAllTasks() {
169     RunQueuedModelThreadTasks();
170     RunQueuedSyncThreadTasks();
171     RunQueuedModelThreadTasks();
172   }
173
174   // The sync type proxy pretends to run tasks on a different thread.
175   // This function runs any posted tasks.
176   void RunQueuedModelThreadTasks() { model_thread_->RunUntilIdle(); }
177
178   // Processes any pending connect or disconnect requests and sends
179   // responses synchronously.
180   void RunQueuedSyncThreadTasks() { sync_thread_->RunUntilIdle(); }
181
182   void SetAutoRunTasks(bool auto_run_tasks) {
183     auto_run_tasks_ = auto_run_tasks;
184   }
185
186  protected:
187   syncer::ModelTypeSyncProxyImpl type_sync_proxy_;
188   scoped_refptr<base::TestSimpleTaskRunner> model_thread_;
189   scoped_refptr<base::TestSimpleTaskRunner> sync_thread_;
190
191   NonBlockingDataTypeController controller_;
192
193   MockSyncContext mock_sync_context_;
194   MockSyncContextProxy mock_context_proxy_;
195
196   bool auto_run_tasks_;
197 };
198
199 // Initialization when the user has disabled syncing for this type.
200 TEST_F(NonBlockingDataTypeControllerTest, UserDisabled) {
201   SetIsPreferred(false);
202   InitTypeSyncProxy();
203   InitSyncBackend();
204
205   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
206   EXPECT_FALSE(type_sync_proxy_.IsConnected());
207
208   UninitializeSyncBackend();
209
210   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
211   EXPECT_FALSE(type_sync_proxy_.IsConnected());
212 }
213
214 // Init the sync backend then the type sync proxy.
215 TEST_F(NonBlockingDataTypeControllerTest, Enabled_SyncFirst) {
216   SetIsPreferred(true);
217   InitSyncBackend();
218   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
219   EXPECT_FALSE(type_sync_proxy_.IsConnected());
220
221   InitTypeSyncProxy();
222   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
223   EXPECT_TRUE(type_sync_proxy_.IsConnected());
224
225   UninitializeSyncBackend();
226   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
227   EXPECT_FALSE(type_sync_proxy_.IsConnected());
228 }
229
230 // Init the type sync proxy then the sync backend.
231 TEST_F(NonBlockingDataTypeControllerTest, Enabled_ProcessorFirst) {
232   SetIsPreferred(true);
233   InitTypeSyncProxy();
234   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
235   EXPECT_FALSE(type_sync_proxy_.IsConnected());
236
237   InitSyncBackend();
238   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
239   EXPECT_TRUE(type_sync_proxy_.IsConnected());
240
241   UninitializeSyncBackend();
242   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
243   EXPECT_FALSE(type_sync_proxy_.IsConnected());
244 }
245
246 // Initialize sync then disable it with a pref change.
247 TEST_F(NonBlockingDataTypeControllerTest, PreferThenNot) {
248   SetIsPreferred(true);
249   InitTypeSyncProxy();
250   InitSyncBackend();
251
252   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
253   EXPECT_TRUE(type_sync_proxy_.IsConnected());
254
255   SetIsPreferred(false);
256   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
257   EXPECT_FALSE(type_sync_proxy_.IsConnected());
258 }
259
260 // Connect type sync proxy and sync backend, then toggle prefs repeatedly.
261 TEST_F(NonBlockingDataTypeControllerTest, RepeatedTogglePreference) {
262   SetIsPreferred(false);
263   InitTypeSyncProxy();
264   InitSyncBackend();
265   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
266   EXPECT_FALSE(type_sync_proxy_.IsConnected());
267
268   SetIsPreferred(true);
269   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
270   EXPECT_TRUE(type_sync_proxy_.IsConnected());
271
272   SetIsPreferred(false);
273   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
274   EXPECT_FALSE(type_sync_proxy_.IsConnected());
275
276   SetIsPreferred(true);
277   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
278   EXPECT_TRUE(type_sync_proxy_.IsConnected());
279
280   SetIsPreferred(false);
281   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
282   EXPECT_FALSE(type_sync_proxy_.IsConnected());
283 }
284
285 // Test sync backend getting restarted while processor is connected.
286 TEST_F(NonBlockingDataTypeControllerTest, RestartSyncBackend) {
287   SetIsPreferred(true);
288   InitTypeSyncProxy();
289   InitSyncBackend();
290   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
291   EXPECT_TRUE(type_sync_proxy_.IsConnected());
292
293   // Shutting down sync backend should disconnect but not disable the type.
294   UninitializeSyncBackend();
295   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
296   EXPECT_FALSE(type_sync_proxy_.IsConnected());
297
298   // Brining the backend back should reconnect the type.
299   InitSyncBackend();
300   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
301   EXPECT_TRUE(type_sync_proxy_.IsConnected());
302 }
303
304 // Test sync backend being restarted before processor connects.
305 TEST_F(NonBlockingDataTypeControllerTest, RestartSyncBackendEarly) {
306   SetIsPreferred(true);
307
308   // Toggle sync off and on before the type sync proxy is available.
309   InitSyncBackend();
310   EXPECT_FALSE(type_sync_proxy_.IsConnected());
311   UninitializeSyncBackend();
312   EXPECT_FALSE(type_sync_proxy_.IsConnected());
313   InitSyncBackend();
314   EXPECT_FALSE(type_sync_proxy_.IsConnected());
315
316   // Introduce the processor.
317   InitTypeSyncProxy();
318   EXPECT_TRUE(type_sync_proxy_.IsConnected());
319 }
320
321 // Test pref toggling before the sync backend has connected.
322 TEST_F(NonBlockingDataTypeControllerTest, TogglePreferenceWithoutBackend) {
323   SetIsPreferred(true);
324   InitTypeSyncProxy();
325
326   // This should emit a disable signal.
327   SetIsPreferred(false);
328   EXPECT_FALSE(type_sync_proxy_.IsConnected());
329   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
330
331   // This won't enable us, since we don't have a sync backend.
332   SetIsPreferred(true);
333   EXPECT_FALSE(type_sync_proxy_.IsConnected());
334   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
335
336   // Only now do we start sending enable signals.
337   InitSyncBackend();
338   EXPECT_TRUE(type_sync_proxy_.IsConnected());
339   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
340 }
341
342 // Turns off auto-task-running to test the effects of delaying a connection
343 // response.
344 //
345 // This is mostly a test of the test framework.  It's not very interesting on
346 // its own, but it provides a useful "control" against some of the more
347 // complicated race tests below.
348 TEST_F(NonBlockingDataTypeControllerTest, DelayedConnect) {
349   SetAutoRunTasks(false);
350
351   SetIsPreferred(true);
352   InitTypeSyncProxy();
353   InitSyncBackend();
354
355   // Allow the model to emit the request.
356   RunQueuedModelThreadTasks();
357
358   // That should result in a request to connect, but it won't be
359   // executed right away.
360   EXPECT_FALSE(type_sync_proxy_.IsConnected());
361   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
362
363   // Let the sync thread process the request and the model thread handle its
364   // response.
365   RunQueuedSyncThreadTasks();
366   RunQueuedModelThreadTasks();
367
368   EXPECT_TRUE(type_sync_proxy_.IsConnected());
369   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
370 }
371
372 // Send Disable signal while a connection request is in progress.
373 TEST_F(NonBlockingDataTypeControllerTest, DisableRacesWithOnConnect) {
374   SetAutoRunTasks(false);
375
376   SetIsPreferred(true);
377   InitTypeSyncProxy();
378   InitSyncBackend();
379
380   // Allow the model to emit the request.
381   RunQueuedModelThreadTasks();
382
383   // That should result in a request to connect, but it won't be
384   // executed right away.
385   EXPECT_FALSE(type_sync_proxy_.IsConnected());
386   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
387
388   // Send and execute a disable signal before the OnConnect callback returns.
389   SetIsPreferred(false);
390
391   // Now we let sync process the initial request and the disable request,
392   // both of which should be sitting in its queue.
393   RunQueuedSyncThreadTasks();
394
395   // Let the model thread process any responses received from the sync thread.
396   // A plausible error would be that the sync thread returns a "connection OK"
397   // message, and this message overrides the request to disable that arrived
398   // from the UI thread earlier.  We need to make sure that doesn't happen.
399   RunQueuedModelThreadTasks();
400
401   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
402   EXPECT_FALSE(type_sync_proxy_.IsConnected());
403 }
404
405 // Send a request to enable, then disable, then re-enable the data type.
406 //
407 // To make it more interesting, we stall the sync thread until all three
408 // requests have been passed to the model thread.
409 TEST_F(NonBlockingDataTypeControllerTest, EnableDisableEnableRace) {
410   SetAutoRunTasks(false);
411
412   SetIsPreferred(true);
413   InitTypeSyncProxy();
414   InitSyncBackend();
415   RunQueuedModelThreadTasks();
416
417   // That was the first enable.
418   EXPECT_FALSE(type_sync_proxy_.IsConnected());
419   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
420
421   // Now disable.
422   SetIsPreferred(false);
423   RunQueuedModelThreadTasks();
424   EXPECT_FALSE(type_sync_proxy_.IsPreferred());
425
426   // And re-enable.
427   SetIsPreferred(true);
428   RunQueuedModelThreadTasks();
429   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
430
431   // The sync thread has three messages related to those enables and
432   // disables sittin in its queue.  Let's allow it to process them.
433   RunQueuedSyncThreadTasks();
434
435   // Let the model thread process any messages from the sync thread.
436   RunQueuedModelThreadTasks();
437   EXPECT_TRUE(type_sync_proxy_.IsPreferred());
438   EXPECT_TRUE(type_sync_proxy_.IsConnected());
439 }
440
441 }  // namespace sync_driver