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