OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 // TODO(akalin): Rename this file to migration_test.cc. | |
6 | |
7 #include "chrome/browser/prefs/scoped_user_pref_update.h" | |
8 #include "chrome/browser/profiles/profile.h" | |
9 #include "chrome/browser/sync/profile_sync_service_harness.h" | |
10 #include "chrome/browser/translate/translate_prefs.h" | |
11 #include "chrome/common/pref_names.h" | |
12 #include "chrome/test/base/ui_test_utils.h" | |
13 #include "chrome/test/live_sync/bookmarks_helper.h" | |
14 #include "chrome/test/live_sync/live_sync_test.h" | |
15 #include "chrome/test/live_sync/preferences_helper.h" | |
16 | |
17 using bookmarks_helper::AddURL; | |
18 using bookmarks_helper::IndexedURL; | |
19 using bookmarks_helper::IndexedURLTitle; | |
20 | |
21 using preferences_helper::BooleanPrefMatches; | |
22 using preferences_helper::ChangeBooleanPref; | |
23 | |
24 namespace { | |
25 | |
26 // Utility functions to make a model type set out of a small number of | |
27 // model types. | |
28 | |
29 syncable::ModelTypeSet MakeSet(syncable::ModelType type) { | |
30 syncable::ModelTypeSet model_types; | |
31 model_types.insert(type); | |
32 return model_types; | |
33 } | |
34 | |
35 syncable::ModelTypeSet MakeSet(syncable::ModelType type1, | |
36 syncable::ModelType type2) { | |
37 syncable::ModelTypeSet model_types; | |
38 model_types.insert(type1); | |
39 model_types.insert(type2); | |
40 return model_types; | |
41 } | |
42 | |
43 // An ordered list of model types sets to migrate. Used by | |
44 // RunMigrationTest(). | |
45 typedef std::deque<syncable::ModelTypeSet> MigrationList; | |
46 | |
47 // Utility functions to make a MigrationList out of a small number of | |
48 // model types / model type sets. | |
49 | |
50 MigrationList MakeList(const syncable::ModelTypeSet& model_types) { | |
51 return MigrationList(1, model_types); | |
52 } | |
53 | |
54 MigrationList MakeList(const syncable::ModelTypeSet& model_types1, | |
55 const syncable::ModelTypeSet& model_types2) { | |
56 MigrationList migration_list; | |
57 migration_list.push_back(model_types1); | |
58 migration_list.push_back(model_types2); | |
59 return migration_list; | |
60 } | |
61 | |
62 MigrationList MakeList(syncable::ModelType type) { | |
63 return MakeList(MakeSet(type)); | |
64 } | |
65 | |
66 MigrationList MakeList(syncable::ModelType type1, | |
67 syncable::ModelType type2) { | |
68 return MakeList(MakeSet(type1), MakeSet(type2)); | |
69 } | |
70 | |
71 class MigrationTest : public LiveSyncTest { | |
72 public: | |
73 explicit MigrationTest(TestType test_type) : LiveSyncTest(test_type) {} | |
74 virtual ~MigrationTest() {} | |
75 | |
76 // TODO(akalin): Add more MODIFY_(data type) trigger methods, as | |
77 // well as a poll-based trigger method. | |
78 enum TriggerMethod { MODIFY_PREF, MODIFY_BOOKMARK, TRIGGER_NOTIFICATION }; | |
79 | |
80 syncable::ModelTypeSet GetPreferredDataTypes() { | |
81 syncable::ModelTypeSet preferred_data_types; | |
82 GetClient(0)->service()->GetPreferredDataTypes(&preferred_data_types); | |
83 // Make sure all clients have the same preferred data types. | |
84 for (int i = 1; i < num_clients(); ++i) { | |
85 syncable::ModelTypeSet other_preferred_data_types; | |
86 GetClient(i)->service()->GetPreferredDataTypes( | |
87 &other_preferred_data_types); | |
88 EXPECT_EQ(preferred_data_types, other_preferred_data_types); | |
89 } | |
90 return preferred_data_types; | |
91 } | |
92 | |
93 // Returns a MigrationList with every enabled data type in its own | |
94 // set. | |
95 MigrationList GetPreferredDataTypesList() { | |
96 MigrationList migration_list; | |
97 const syncable::ModelTypeSet& preferred_data_types = | |
98 GetPreferredDataTypes(); | |
99 for (syncable::ModelTypeSet::const_iterator it = | |
100 preferred_data_types.begin(); | |
101 it != preferred_data_types.end(); ++it) { | |
102 migration_list.push_back(MakeSet(*it)); | |
103 } | |
104 return migration_list; | |
105 } | |
106 | |
107 // Trigger a migration for the given types with the given method. | |
108 void TriggerMigration(const syncable::ModelTypeSet& model_types, | |
109 TriggerMethod trigger_method) { | |
110 switch (trigger_method) { | |
111 case MODIFY_PREF: | |
112 // Unlike MODIFY_BOOKMARK, MODIFY_PREF doesn't cause a | |
113 // notification to happen (since model association on a | |
114 // boolean pref clobbers the local value), so it doesn't work | |
115 // for anything but single-client tests. | |
116 ASSERT_EQ(1, num_clients()); | |
117 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); | |
118 ChangeBooleanPref(0, prefs::kShowHomeButton); | |
119 break; | |
120 case MODIFY_BOOKMARK: | |
121 ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0)))); | |
122 break; | |
123 case TRIGGER_NOTIFICATION: | |
124 TriggerNotification(model_types); | |
125 break; | |
126 default: | |
127 ADD_FAILURE(); | |
128 } | |
129 } | |
130 | |
131 // Block until all clients have completed migration for the given | |
132 // types. | |
133 void AwaitMigration(const syncable::ModelTypeSet& migrate_types) { | |
134 for (int i = 0; i < num_clients(); ++i) { | |
135 ASSERT_TRUE(GetClient(i)->AwaitMigration(migrate_types)); | |
136 } | |
137 } | |
138 | |
139 bool ShouldRunMigrationTest() const { | |
140 if (!ServerSupportsNotificationControl() || | |
141 !ServerSupportsErrorTriggering()) { | |
142 LOG(WARNING) << "Test skipped in this server environment."; | |
143 return false; | |
144 } | |
145 return true; | |
146 } | |
147 | |
148 // Makes sure migration works with the given migration list and | |
149 // trigger method. | |
150 void RunMigrationTest(const MigrationList& migration_list, | |
151 TriggerMethod trigger_method) { | |
152 ASSERT_TRUE(ShouldRunMigrationTest()); | |
153 | |
154 // If we have only one client, turn off notifications to avoid the | |
155 // possibility of spurious sync cycles. | |
156 bool do_test_without_notifications = | |
157 (trigger_method != TRIGGER_NOTIFICATION && num_clients() == 1); | |
158 | |
159 if (do_test_without_notifications) { | |
160 DisableNotifications(); | |
161 } | |
162 | |
163 // Phase 1: Trigger the migrations on the server. | |
164 for (MigrationList::const_iterator it = migration_list.begin(); | |
165 it != migration_list.end(); ++it) { | |
166 TriggerMigrationDoneError(*it); | |
167 } | |
168 | |
169 // Phase 2: Trigger each migration individually and wait for it to | |
170 // complete. (Multiple migrations may be handled by each | |
171 // migration cycle, but there's no guarantee of that, so we have | |
172 // to trigger each migration individually.) | |
173 for (MigrationList::const_iterator it = migration_list.begin(); | |
174 it != migration_list.end(); ++it) { | |
175 TriggerMigration(*it, trigger_method); | |
176 AwaitMigration(*it); | |
177 } | |
178 | |
179 // Phase 3: Wait for all clients to catch up. | |
180 AwaitQuiescence(); | |
181 | |
182 // Re-enable notifications if we disabled it. | |
183 if (do_test_without_notifications) { | |
184 EnableNotifications(); | |
185 } | |
186 } | |
187 | |
188 private: | |
189 DISALLOW_COPY_AND_ASSIGN(MigrationTest); | |
190 }; | |
191 | |
192 class MigrationSingleClientTest : public MigrationTest { | |
193 public: | |
194 MigrationSingleClientTest() : MigrationTest(SINGLE_CLIENT) {} | |
195 virtual ~MigrationSingleClientTest() {} | |
196 | |
197 void RunSingleClientMigrationTest(const MigrationList& migration_list, | |
198 TriggerMethod trigger_method) { | |
199 if (!ShouldRunMigrationTest()) { | |
200 return; | |
201 } | |
202 ASSERT_TRUE(SetupSync()); | |
203 RunMigrationTest(migration_list, trigger_method); | |
204 } | |
205 | |
206 private: | |
207 DISALLOW_COPY_AND_ASSIGN(MigrationSingleClientTest); | |
208 }; | |
209 | |
210 // The simplest possible migration tests -- a single data type. | |
211 | |
212 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyPref) { | |
213 RunSingleClientMigrationTest(MakeList(syncable::PREFERENCES), MODIFY_PREF); | |
214 } | |
215 | |
216 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyBookmark) { | |
217 RunSingleClientMigrationTest(MakeList(syncable::PREFERENCES), | |
218 MODIFY_BOOKMARK); | |
219 } | |
220 | |
221 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, | |
222 PrefsOnlyTriggerNotification) { | |
223 RunSingleClientMigrationTest(MakeList(syncable::PREFERENCES), | |
224 TRIGGER_NOTIFICATION); | |
225 } | |
226 | |
227 // Nigori is handled specially, so we test that separately. | |
228 | |
229 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, NigoriOnly) { | |
230 RunSingleClientMigrationTest(MakeList(syncable::PREFERENCES), | |
231 TRIGGER_NOTIFICATION); | |
232 } | |
233 | |
234 // A little more complicated -- two data types. | |
235 | |
236 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, | |
237 BookmarksPrefsIndividually) { | |
238 RunSingleClientMigrationTest( | |
239 MakeList(syncable::BOOKMARKS, syncable::PREFERENCES), | |
240 MODIFY_PREF); | |
241 } | |
242 | |
243 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsBoth) { | |
244 RunSingleClientMigrationTest( | |
245 MakeList(MakeSet(syncable::BOOKMARKS, syncable::PREFERENCES)), | |
246 MODIFY_BOOKMARK); | |
247 } | |
248 | |
249 // Two data types with one being nigori. | |
250 | |
251 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriIndividiaully) { | |
252 RunSingleClientMigrationTest( | |
253 MakeList(syncable::PREFERENCES, syncable::NIGORI), | |
254 TRIGGER_NOTIFICATION); | |
255 } | |
256 | |
257 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriBoth) { | |
258 RunSingleClientMigrationTest( | |
259 MakeList(MakeSet(syncable::PREFERENCES, syncable::NIGORI)), | |
260 MODIFY_PREF); | |
261 } | |
262 | |
263 // The whole shebang -- all data types. | |
264 | |
265 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesIndividually) { | |
266 ASSERT_TRUE(SetupClients()); | |
267 RunSingleClientMigrationTest(GetPreferredDataTypesList(), MODIFY_BOOKMARK); | |
268 } | |
269 | |
270 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, | |
271 AllTypesIndividuallyTriggerNotification) { | |
272 ASSERT_TRUE(SetupClients()); | |
273 RunSingleClientMigrationTest(GetPreferredDataTypesList(), | |
274 TRIGGER_NOTIFICATION); | |
275 } | |
276 | |
277 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesAtOnce) { | |
278 ASSERT_TRUE(SetupClients()); | |
279 RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()), | |
280 MODIFY_PREF); | |
281 } | |
282 | |
283 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, | |
284 AllTypesAtOnceTriggerNotification) { | |
285 ASSERT_TRUE(SetupClients()); | |
286 RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()), | |
287 TRIGGER_NOTIFICATION); | |
288 } | |
289 | |
290 // All data types plus nigori. | |
291 | |
292 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, | |
293 AllTypesWithNigoriIndividually) { | |
294 ASSERT_TRUE(SetupClients()); | |
295 MigrationList migration_list = GetPreferredDataTypesList(); | |
296 migration_list.push_front(MakeSet(syncable::NIGORI)); | |
297 RunSingleClientMigrationTest(migration_list, MODIFY_BOOKMARK); | |
298 } | |
299 | |
300 IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesWithNigoriAtOnce) { | |
301 ASSERT_TRUE(SetupClients()); | |
302 syncable::ModelTypeSet all_types = GetPreferredDataTypes(); | |
303 all_types.insert(syncable::NIGORI); | |
304 RunSingleClientMigrationTest(MakeList(all_types), MODIFY_PREF); | |
305 } | |
306 | |
307 class MigrationTwoClientTest : public MigrationTest { | |
308 public: | |
309 MigrationTwoClientTest() : MigrationTest(TWO_CLIENT) {} | |
310 virtual ~MigrationTwoClientTest() {} | |
311 | |
312 // Helper function that verifies that preferences sync still works. | |
313 void VerifyPrefSync() { | |
314 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); | |
315 ChangeBooleanPref(0, prefs::kShowHomeButton); | |
316 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); | |
317 ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); | |
318 } | |
319 | |
320 void RunTwoClientMigrationTest(const MigrationList& migration_list, | |
321 TriggerMethod trigger_method) { | |
322 if (!ShouldRunMigrationTest()) { | |
323 return; | |
324 } | |
325 ASSERT_TRUE(SetupSync()); | |
326 | |
327 // Make sure pref sync works before running the migration test. | |
328 VerifyPrefSync(); | |
329 | |
330 RunMigrationTest(migration_list, trigger_method); | |
331 | |
332 // Make sure pref sync still works after running the migration | |
333 // test. | |
334 VerifyPrefSync(); | |
335 } | |
336 | |
337 private: | |
338 DISALLOW_COPY_AND_ASSIGN(MigrationTwoClientTest); | |
339 }; | |
340 | |
341 // Easiest possible test of migration errors: triggers a server | |
342 // migration on one datatype, then modifies some other datatype. | |
343 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, | |
344 MigratePrefsThenModifyBookmark) { | |
345 RunTwoClientMigrationTest(MakeList(syncable::PREFERENCES), | |
346 MODIFY_BOOKMARK); | |
347 } | |
348 | |
349 // Triggers a server migration on two datatypes, then makes a local | |
350 // modification to one of them. | |
351 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, | |
352 MigratePrefsAndBookmarksThenModifyBookmark) { | |
353 RunTwoClientMigrationTest( | |
354 MakeList(syncable::PREFERENCES, syncable::BOOKMARKS), | |
355 MODIFY_BOOKMARK); | |
356 } | |
357 | |
358 // Migrate every datatype in sequence; the catch being that the server | |
359 // will only tell the client about the migrations one at a time. | |
360 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigrationHellWithoutNigori) { | |
361 ASSERT_TRUE(SetupClients()); | |
362 MigrationList migration_list = GetPreferredDataTypesList(); | |
363 // Let the first nudge be a datatype that's neither prefs nor | |
364 // bookmarks. | |
365 migration_list.push_front(MakeSet(syncable::THEMES)); | |
366 RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK); | |
367 } | |
368 | |
369 IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigrationHellWithNigori) { | |
370 ASSERT_TRUE(SetupClients()); | |
371 MigrationList migration_list = GetPreferredDataTypesList(); | |
372 // Let the first nudge be a datatype that's neither prefs nor | |
373 // bookmarks. | |
374 migration_list.push_front(MakeSet(syncable::THEMES)); | |
375 // Pop off one so that we don't migrate all data types; the syncer | |
376 // freaks out if we do that (see http://crbug.com/94882). | |
377 ASSERT_GE(migration_list.size(), 2u); | |
378 ASSERT_NE(migration_list.back(), MakeSet(syncable::NIGORI)); | |
379 migration_list.back() = MakeSet(syncable::NIGORI); | |
380 RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK); | |
381 } | |
382 | |
383 class MigrationReconfigureTest : public MigrationTwoClientTest { | |
384 public: | |
385 MigrationReconfigureTest() {} | |
386 | |
387 virtual void SetUpCommandLine(CommandLine* cl) OVERRIDE { | |
388 AddTestSwitches(cl); | |
389 // Do not add optional datatypes. | |
390 } | |
391 | |
392 virtual ~MigrationReconfigureTest() {} | |
393 | |
394 private: | |
395 DISALLOW_COPY_AND_ASSIGN(MigrationReconfigureTest); | |
396 }; | |
397 | |
398 IN_PROC_BROWSER_TEST_F(MigrationReconfigureTest, SetSyncTabs) { | |
399 if (!ServerSupportsErrorTriggering()) { | |
400 LOG(WARNING) << "Test skipped in this server environment."; | |
401 return; | |
402 } | |
403 | |
404 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; | |
405 ASSERT_FALSE(GetClient(0)->IsTypeRegistered(syncable::SESSIONS)); | |
406 ASSERT_FALSE(GetClient(0)->IsTypePreferred(syncable::SESSIONS)); | |
407 | |
408 // Phase 1: Before migrating anything, create & sync a preference. | |
409 VerifyPrefSync(); | |
410 | |
411 // Phase 2: Trigger setting the sync_tabs field. | |
412 TriggerSetSyncTabs(); | |
413 | |
414 // Phase 3: Modify a bookmark and wait for it to sync. | |
415 ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))) != NULL); | |
416 ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); | |
417 | |
418 // Phase 4: Verify that preferences can still be synchronized. | |
419 VerifyPrefSync(); | |
420 | |
421 // Phase 5: Verify that sessions are registered and enabled. | |
422 ASSERT_TRUE(GetClient(0)->IsTypeRegistered(syncable::SESSIONS)); | |
423 ASSERT_TRUE(GetClient(0)->IsTypePreferred(syncable::SESSIONS)); | |
424 } | |
425 | |
426 IN_PROC_BROWSER_TEST_F(MigrationReconfigureTest, SetSyncTabsAndMigrate) { | |
427 if (!ServerSupportsErrorTriggering()) { | |
428 LOG(WARNING) << "Test skipped in this server environment."; | |
429 return; | |
430 } | |
431 | |
432 ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; | |
433 ASSERT_FALSE(GetClient(0)->IsTypeRegistered(syncable::SESSIONS)); | |
434 ASSERT_FALSE(GetClient(0)->IsTypePreferred(syncable::SESSIONS)); | |
435 | |
436 // Phase 1: Before migrating anything, create & sync a preference. | |
437 VerifyPrefSync(); | |
438 | |
439 // Phase 2: Trigger setting the sync_tabs field. | |
440 TriggerSetSyncTabs(); | |
441 | |
442 // Phase 3: Trigger a preference migration on the server. | |
443 RunMigrationTest(MakeList(syncable::PREFERENCES), MODIFY_BOOKMARK); | |
444 | |
445 // Phase 5: Verify that preferences can still be synchronized. | |
446 VerifyPrefSync(); | |
447 | |
448 // Phase 6: Verify that sessions are registered and enabled. | |
449 ASSERT_TRUE(GetClient(0)->IsTypeRegistered(syncable::SESSIONS)); | |
450 ASSERT_TRUE(GetClient(0)->IsTypePreferred(syncable::SESSIONS)); | |
451 } | |
452 | |
453 } // namespace | |
OLD | NEW |