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 <vector>
6
7#include "base/deferred_sequenced_task_runner.h"
8#include "base/message_loop/message_loop.h"
9#include "base/thread_task_runner_handle.h"
10#include "sync/engine/model_type_sync_proxy_impl.h"
11#include "sync/internal_api/public/base/model_type.h"
12#include "sync/sessions/model_type_registry.h"
13#include "sync/test/engine/fake_model_worker.h"
14#include "sync/test/engine/mock_nudge_handler.h"
15#include "sync/test/engine/test_directory_setter_upper.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace syncer {
19
20class ModelTypeRegistryTest : public ::testing::Test {
21 public:
22  ModelTypeRegistryTest();
23  virtual void SetUp() OVERRIDE;
24  virtual void TearDown() OVERRIDE;
25
26  ModelTypeRegistry* registry();
27
28  static DataTypeState MakeInitialDataTypeState(ModelType type) {
29    DataTypeState state;
30    state.progress_marker.set_data_type_id(
31        GetSpecificsFieldNumberFromModelType(type));
32    state.next_client_id = 0;
33    return state;
34  }
35
36 private:
37  syncable::Directory* directory();
38
39  base::MessageLoop message_loop_;
40
41  TestDirectorySetterUpper dir_maker_;
42  std::vector<scoped_refptr<ModelSafeWorker> > workers_;
43  scoped_ptr<ModelTypeRegistry> registry_;
44  MockNudgeHandler mock_nudge_handler_;
45};
46
47ModelTypeRegistryTest::ModelTypeRegistryTest() {}
48
49void ModelTypeRegistryTest::SetUp() {
50  dir_maker_.SetUp();
51  scoped_refptr<ModelSafeWorker> passive_worker(
52      new FakeModelWorker(GROUP_PASSIVE));
53  scoped_refptr<ModelSafeWorker> ui_worker(
54      new FakeModelWorker(GROUP_UI));
55  scoped_refptr<ModelSafeWorker> db_worker(
56      new FakeModelWorker(GROUP_DB));
57  workers_.push_back(passive_worker);
58  workers_.push_back(ui_worker);
59  workers_.push_back(db_worker);
60
61  registry_.reset(
62      new ModelTypeRegistry(workers_, directory(), &mock_nudge_handler_));
63}
64
65void ModelTypeRegistryTest::TearDown() {
66  registry_.reset();
67  workers_.clear();
68  dir_maker_.TearDown();
69}
70
71ModelTypeRegistry* ModelTypeRegistryTest::registry() {
72  return registry_.get();
73}
74
75syncable::Directory* ModelTypeRegistryTest::directory() {
76  return dir_maker_.directory();
77}
78
79// Create some directory update handlers and commit contributors.
80//
81// We don't get to inspect any of the state we're modifying.  This test is
82// useful only for detecting crashes or memory leaks.
83TEST_F(ModelTypeRegistryTest, SetEnabledDirectoryTypes_Once) {
84  ModelSafeRoutingInfo routing_info;
85  routing_info.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
86  routing_info.insert(std::make_pair(BOOKMARKS, GROUP_UI));
87  routing_info.insert(std::make_pair(AUTOFILL, GROUP_DB));
88
89  registry()->SetEnabledDirectoryTypes(routing_info);
90}
91
92// Try two different routing info settings.
93//
94// We don't get to inspect any of the state we're modifying.  This test is
95// useful only for detecting crashes or memory leaks.
96TEST_F(ModelTypeRegistryTest, SetEnabledDirectoryTypes_Repeatedly) {
97  ModelSafeRoutingInfo routing_info1;
98  routing_info1.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
99  routing_info1.insert(std::make_pair(BOOKMARKS, GROUP_PASSIVE));
100  routing_info1.insert(std::make_pair(AUTOFILL, GROUP_PASSIVE));
101
102  registry()->SetEnabledDirectoryTypes(routing_info1);
103
104  ModelSafeRoutingInfo routing_info2;
105  routing_info2.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
106  routing_info2.insert(std::make_pair(BOOKMARKS, GROUP_UI));
107  routing_info2.insert(std::make_pair(AUTOFILL, GROUP_DB));
108
109  registry()->SetEnabledDirectoryTypes(routing_info2);
110}
111
112// Test removing all types from the list.
113//
114// We don't get to inspect any of the state we're modifying.  This test is
115// useful only for detecting crashes or memory leaks.
116TEST_F(ModelTypeRegistryTest, SetEnabledDirectoryTypes_Clear) {
117  ModelSafeRoutingInfo routing_info1;
118  routing_info1.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
119  routing_info1.insert(std::make_pair(BOOKMARKS, GROUP_UI));
120  routing_info1.insert(std::make_pair(AUTOFILL, GROUP_DB));
121
122  registry()->SetEnabledDirectoryTypes(routing_info1);
123
124  ModelSafeRoutingInfo routing_info2;
125  registry()->SetEnabledDirectoryTypes(routing_info2);
126}
127
128// Test disabling then re-enabling some directory types.
129//
130// We don't get to inspect any of the state we're modifying.  This test is
131// useful only for detecting crashes or memory leaks.
132TEST_F(ModelTypeRegistryTest, SetEnabledDirectoryTypes_OffAndOn) {
133  ModelSafeRoutingInfo routing_info1;
134  routing_info1.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
135  routing_info1.insert(std::make_pair(BOOKMARKS, GROUP_UI));
136  routing_info1.insert(std::make_pair(AUTOFILL, GROUP_DB));
137
138  registry()->SetEnabledDirectoryTypes(routing_info1);
139
140  ModelSafeRoutingInfo routing_info2;
141  registry()->SetEnabledDirectoryTypes(routing_info2);
142
143  registry()->SetEnabledDirectoryTypes(routing_info1);
144}
145
146TEST_F(ModelTypeRegistryTest, NonBlockingTypes) {
147  ModelTypeSyncProxyImpl themes_sync_proxy(syncer::THEMES);
148  ModelTypeSyncProxyImpl sessions_sync_proxy(syncer::SESSIONS);
149  scoped_refptr<base::DeferredSequencedTaskRunner> task_runner =
150      new base::DeferredSequencedTaskRunner(
151          base::ThreadTaskRunnerHandle::Get());
152
153  EXPECT_TRUE(registry()->GetEnabledTypes().Empty());
154
155  registry()->ConnectSyncTypeToWorker(syncer::THEMES,
156                                      MakeInitialDataTypeState(THEMES),
157                                      UpdateResponseDataList(),
158                                      task_runner,
159                                      themes_sync_proxy.AsWeakPtrForUI());
160  EXPECT_TRUE(registry()->GetEnabledTypes().Equals(
161      ModelTypeSet(syncer::THEMES)));
162
163  registry()->ConnectSyncTypeToWorker(syncer::SESSIONS,
164                                      MakeInitialDataTypeState(SESSIONS),
165                                      UpdateResponseDataList(),
166                                      task_runner,
167                                      sessions_sync_proxy.AsWeakPtrForUI());
168  EXPECT_TRUE(registry()->GetEnabledTypes().Equals(
169      ModelTypeSet(syncer::THEMES, syncer::SESSIONS)));
170
171  registry()->DisconnectSyncWorker(syncer::THEMES);
172  EXPECT_TRUE(registry()->GetEnabledTypes().Equals(
173      ModelTypeSet(syncer::SESSIONS)));
174
175  // Allow ModelTypeRegistry destruction to delete the
176  // Sessions' ModelTypeSyncWorker.
177}
178
179TEST_F(ModelTypeRegistryTest, NonBlockingTypesWithDirectoryTypes) {
180  ModelTypeSyncProxyImpl themes_sync_proxy(syncer::THEMES);
181  ModelTypeSyncProxyImpl sessions_sync_proxy(syncer::SESSIONS);
182  scoped_refptr<base::DeferredSequencedTaskRunner> task_runner =
183      new base::DeferredSequencedTaskRunner(
184          base::ThreadTaskRunnerHandle::Get());
185
186  ModelSafeRoutingInfo routing_info1;
187  routing_info1.insert(std::make_pair(NIGORI, GROUP_PASSIVE));
188  routing_info1.insert(std::make_pair(BOOKMARKS, GROUP_UI));
189  routing_info1.insert(std::make_pair(AUTOFILL, GROUP_DB));
190
191  ModelTypeSet current_types;
192  EXPECT_TRUE(registry()->GetEnabledTypes().Empty());
193
194  // Add the themes non-blocking type.
195  registry()->ConnectSyncTypeToWorker(syncer::THEMES,
196                                      MakeInitialDataTypeState(THEMES),
197                                      UpdateResponseDataList(),
198                                      task_runner,
199                                      themes_sync_proxy.AsWeakPtrForUI());
200  current_types.Put(syncer::THEMES);
201  EXPECT_TRUE(registry()->GetEnabledTypes().Equals(current_types));
202
203  // Add some directory types.
204  registry()->SetEnabledDirectoryTypes(routing_info1);
205  current_types.PutAll(GetRoutingInfoTypes(routing_info1));
206  EXPECT_TRUE(registry()->GetEnabledTypes().Equals(current_types));
207
208  // Add sessions non-blocking type.
209  registry()->ConnectSyncTypeToWorker(syncer::SESSIONS,
210                                      MakeInitialDataTypeState(SESSIONS),
211                                      UpdateResponseDataList(),
212                                      task_runner,
213                                      sessions_sync_proxy.AsWeakPtrForUI());
214  current_types.Put(syncer::SESSIONS);
215  EXPECT_TRUE(registry()->GetEnabledTypes().Equals(current_types));
216
217  // Remove themes non-blocking type.
218  registry()->DisconnectSyncWorker(syncer::THEMES);
219  current_types.Remove(syncer::THEMES);
220  EXPECT_TRUE(registry()->GetEnabledTypes().Equals(current_types));
221
222  // Clear all directory types.
223  ModelSafeRoutingInfo routing_info2;
224  registry()->SetEnabledDirectoryTypes(routing_info2);
225  current_types.RemoveAll(GetRoutingInfoTypes(routing_info1));
226  EXPECT_TRUE(registry()->GetEnabledTypes().Equals(current_types));
227}
228
229TEST_F(ModelTypeRegistryTest, DeletionOrdering) {
230  scoped_ptr<ModelTypeSyncProxyImpl> themes_sync_proxy(
231      new ModelTypeSyncProxyImpl(syncer::THEMES));
232  scoped_ptr<ModelTypeSyncProxyImpl> sessions_sync_proxy(
233      new ModelTypeSyncProxyImpl(syncer::SESSIONS));
234  scoped_refptr<base::DeferredSequencedTaskRunner> task_runner =
235      new base::DeferredSequencedTaskRunner(
236          base::ThreadTaskRunnerHandle::Get());
237
238  EXPECT_TRUE(registry()->GetEnabledTypes().Empty());
239
240  registry()->ConnectSyncTypeToWorker(syncer::THEMES,
241                                      MakeInitialDataTypeState(THEMES),
242                                      UpdateResponseDataList(),
243                                      task_runner,
244                                      themes_sync_proxy->AsWeakPtrForUI());
245  registry()->ConnectSyncTypeToWorker(syncer::SESSIONS,
246                                      MakeInitialDataTypeState(SESSIONS),
247                                      UpdateResponseDataList(),
248                                      task_runner,
249                                      sessions_sync_proxy->AsWeakPtrForUI());
250  EXPECT_TRUE(registry()->GetEnabledTypes().Equals(
251      ModelTypeSet(syncer::THEMES, syncer::SESSIONS)));
252
253  // Tear down themes processing, starting with the worker.
254  registry()->DisconnectSyncWorker(syncer::THEMES);
255  themes_sync_proxy.reset();
256
257  // Tear down sessions processing, starting with the type sync proxy.
258  sessions_sync_proxy.reset();
259  registry()->DisconnectSyncWorker(syncer::SESSIONS);
260
261  EXPECT_TRUE(registry()->GetEnabledTypes().Empty());
262}
263
264}  // namespace syncer
265