two_client_typed_urls_sync_test.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 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 "base/i18n/number_formatting.h"
6#include "base/memory/scoped_vector.h"
7#include "base/utf_string_conversions.h"
8#include "chrome/browser/history/history_types.h"
9#include "chrome/browser/sessions/session_service.h"
10#include "chrome/browser/sync/profile_sync_service_harness.h"
11#include "chrome/browser/sync/test/integration/bookmarks_helper.h"
12#include "chrome/browser/sync/test/integration/sync_test.h"
13#include "chrome/browser/sync/test/integration/typed_urls_helper.h"
14
15using typed_urls_helper::AddUrlToHistory;
16using typed_urls_helper::AddUrlToHistoryWithTimestamp;
17using typed_urls_helper::AddUrlToHistoryWithTransition;
18using typed_urls_helper::AreVisitsEqual;
19using typed_urls_helper::AreVisitsUnique;
20using typed_urls_helper::AssertAllProfilesHaveSameURLsAsVerifier;
21using typed_urls_helper::AssertURLRowVectorsAreEqual;
22using typed_urls_helper::DeleteUrlFromHistory;
23using typed_urls_helper::GetTypedUrlsFromClient;
24using typed_urls_helper::GetUrlFromClient;
25using typed_urls_helper::GetVisitsFromClient;
26using typed_urls_helper::RemoveVisitsFromClient;
27
28class TwoClientTypedUrlsSyncTest : public SyncTest {
29 public:
30  TwoClientTypedUrlsSyncTest() : SyncTest(TWO_CLIENT) {}
31  virtual ~TwoClientTypedUrlsSyncTest() {}
32
33  bool CheckClientsEqual() {
34    history::URLRows urls = GetTypedUrlsFromClient(0);
35    history::URLRows urls2 = GetTypedUrlsFromClient(1);
36    AssertURLRowVectorsAreEqual(urls, urls2);
37    // Now check the visits.
38    for (size_t i = 0; i < urls.size() && i < urls2.size(); i++) {
39      history::VisitVector visit1 = GetVisitsFromClient(0, urls[i].id());
40      history::VisitVector visit2 = GetVisitsFromClient(1, urls2[i].id());
41      if (!AreVisitsEqual(visit1, visit2))
42        return false;
43    }
44    return true;
45  }
46
47  bool CheckNoDuplicateVisits() {
48    for (int i = 0; i < num_clients(); ++i) {
49      history::URLRows urls = GetTypedUrlsFromClient(i);
50      for (size_t j = 0; j < urls.size(); ++j) {
51        history::VisitVector visits = GetVisitsFromClient(i, urls[j].id());
52        if (!AreVisitsUnique(visits))
53          return false;
54      }
55    }
56    return true;
57  }
58
59  int GetVisitCountForFirstURL(int index) {
60    history::URLRows urls = GetTypedUrlsFromClient(index);
61    if (urls.size() == 0)
62      return 0;
63    else
64      return urls[0].visit_count();
65  }
66
67 private:
68  DISALLOW_COPY_AND_ASSIGN(TwoClientTypedUrlsSyncTest);
69};
70
71// TCM: 3728323
72IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, Add) {
73  const string16 kHistoryUrl(
74      ASCIIToUTF16("http://www.add-one-history.google.com/"));
75  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
76
77  // Populate one client with a URL, should sync to the other.
78  GURL new_url(kHistoryUrl);
79  AddUrlToHistory(0, new_url);
80  history::URLRows urls = GetTypedUrlsFromClient(0);
81  ASSERT_EQ(1U, urls.size());
82  ASSERT_EQ(new_url, urls[0].url());
83
84  // Let sync finish.
85  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
86
87  // Both clients should have this URL.
88  AssertAllProfilesHaveSameURLsAsVerifier();
89}
90
91IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, AddExpired) {
92  const string16 kHistoryUrl(
93      ASCIIToUTF16("http://www.add-one-history.google.com/"));
94  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
95
96  // Populate one client with a URL, should sync to the other.
97  GURL new_url(kHistoryUrl);
98  // Create a URL with a timestamp 1 year before today.
99  base::Time timestamp = base::Time::Now() - base::TimeDelta::FromDays(365);
100  AddUrlToHistoryWithTimestamp(0,
101                               new_url,
102                               content::PAGE_TRANSITION_TYPED,
103                               history::SOURCE_BROWSED,
104                               timestamp);
105  history::URLRows urls = GetTypedUrlsFromClient(0);
106  ASSERT_EQ(1U, urls.size());
107  ASSERT_EQ(new_url, urls[0].url());
108
109  // Let sync finish.
110  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
111
112  // Second client should still have no URLs since this one is expired.
113  urls = GetTypedUrlsFromClient(1);
114  ASSERT_EQ(0U, urls.size());
115}
116
117// Flake on mac: http://crbug/115526
118#if defined(OS_MACOSX)
119#define MAYBE_AddExpiredThenUpdate DISABLED_AddExpiredThenUpdate
120#else
121#define MAYBE_AddExpiredThenUpdate AddExpiredThenUpdate
122#endif
123IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, MAYBE_AddExpiredThenUpdate) {
124  const string16 kHistoryUrl(
125      ASCIIToUTF16("http://www.add-one-history.google.com/"));
126  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
127
128  // Populate one client with a URL, should sync to the other.
129  GURL new_url(kHistoryUrl);
130  // Create a URL with a timestamp 1 year before today.
131  base::Time timestamp = base::Time::Now() - base::TimeDelta::FromDays(365);
132  AddUrlToHistoryWithTimestamp(0,
133                               new_url,
134                               content::PAGE_TRANSITION_TYPED,
135                               history::SOURCE_BROWSED,
136                               timestamp);
137  std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0);
138  ASSERT_EQ(1U, urls.size());
139  ASSERT_EQ(new_url, urls[0].url());
140
141  // Let sync finish.
142  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
143
144  // Second client should still have no URLs since this one is expired.
145  urls = GetTypedUrlsFromClient(1);
146  ASSERT_EQ(0U, urls.size());
147
148  // Now drive an update on the first client.
149  AddUrlToHistory(0, new_url);
150
151  // Let sync finish again.
152  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
153
154  // Second client should have the URL now.
155  urls = GetTypedUrlsFromClient(1);
156  ASSERT_EQ(1U, urls.size());
157}
158
159// TCM: 3705291
160// flaky, see crbug.com/108511
161IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, DISABLED_AddThenDelete) {
162  const string16 kHistoryUrl(
163      ASCIIToUTF16("http://www.add-one-history.google.com/"));
164  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
165
166  // Populate one client with a URL, should sync to the other.
167  GURL new_url(kHistoryUrl);
168  AddUrlToHistory(0, new_url);
169  history::URLRows urls = GetTypedUrlsFromClient(0);
170  ASSERT_EQ(1U, urls.size());
171  ASSERT_EQ(new_url, urls[0].url());
172
173  // Let sync finish.
174  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
175
176  // Both clients should have this URL.
177  AssertAllProfilesHaveSameURLsAsVerifier();
178
179  // Delete from first client, should delete from second.
180  DeleteUrlFromHistory(0, new_url);
181
182  // Let sync finish.
183  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
184
185  // Neither client should have this URL.
186  AssertAllProfilesHaveSameURLsAsVerifier();
187}
188
189// TCM: 3643277
190IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, DisableEnableSync) {
191  const string16 kUrl1(ASCIIToUTF16("http://history1.google.com/"));
192  const string16 kUrl2(ASCIIToUTF16("http://history2.google.com/"));
193  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
194
195  // Disable typed url sync for one client, leave it active for the other.
196  GetClient(0)->DisableSyncForDatatype(syncer::TYPED_URLS);
197
198  // Add one URL to non-syncing client, add a different URL to the other,
199  // wait for sync cycle to complete. No data should be exchanged.
200  GURL url1(kUrl1);
201  GURL url2(kUrl2);
202  AddUrlToHistory(0, url1);
203  AddUrlToHistory(1, url2);
204  ASSERT_TRUE(GetClient(1)->AwaitFullSyncCompletion("Added a typed url."));
205
206  // Make sure that no data was exchanged.
207  history::URLRows post_sync_urls = GetTypedUrlsFromClient(0);
208  ASSERT_EQ(1U, post_sync_urls.size());
209  ASSERT_EQ(url1, post_sync_urls[0].url());
210  post_sync_urls = GetTypedUrlsFromClient(1);
211  ASSERT_EQ(1U, post_sync_urls.size());
212  ASSERT_EQ(url2, post_sync_urls[0].url());
213
214  // Enable typed url sync, make both URLs are synced to each client.
215  GetClient(0)->EnableSyncForDatatype(syncer::TYPED_URLS);
216  ASSERT_TRUE(AwaitQuiescence());
217
218  AssertAllProfilesHaveSameURLsAsVerifier();
219}
220
221// flaky, see crbug.com/108511
222IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, DISABLED_AddOneDeleteOther) {
223  const string16 kHistoryUrl(
224      ASCIIToUTF16("http://www.add-one-delete-history.google.com/"));
225  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
226
227  // Populate one client with a URL, should sync to the other.
228  GURL new_url(kHistoryUrl);
229  AddUrlToHistory(0, new_url);
230  history::URLRows urls = GetTypedUrlsFromClient(0);
231  ASSERT_EQ(1U, urls.size());
232  ASSERT_EQ(new_url, urls[0].url());
233
234  // Let sync finish.
235  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
236
237  // Both clients should have this URL.
238  AssertAllProfilesHaveSameURLsAsVerifier();
239
240  // Now, delete the URL from the second client.
241  DeleteUrlFromHistory(1, new_url);
242  urls = GetTypedUrlsFromClient(0);
243  ASSERT_EQ(1U, urls.size());
244
245  // Let sync finish.
246  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
247
248  // Both clients should have this URL removed.
249  AssertAllProfilesHaveSameURLsAsVerifier();
250}
251
252// flaky, see crbug.com/108511
253IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
254                       DISABLED_AddOneDeleteOtherAddAgain) {
255  const string16 kHistoryUrl(
256      ASCIIToUTF16("http://www.add-delete-add-history.google.com/"));
257  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
258
259  // Populate one client with a URL, should sync to the other.
260  GURL new_url(kHistoryUrl);
261  AddUrlToHistory(0, new_url);
262  history::URLRows urls = GetTypedUrlsFromClient(0);
263  ASSERT_EQ(1U, urls.size());
264  ASSERT_EQ(new_url, urls[0].url());
265
266  // Let sync finish.
267  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
268
269  // Both clients should have this URL.
270  AssertAllProfilesHaveSameURLsAsVerifier();
271
272  // Now, delete the URL from the second client.
273  DeleteUrlFromHistory(1, new_url);
274  urls = GetTypedUrlsFromClient(0);
275  ASSERT_EQ(1U, urls.size());
276
277  // Let sync finish.
278  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
279
280  // Both clients should have this URL removed.
281  AssertAllProfilesHaveSameURLsAsVerifier();
282
283  // Add it to the first client again, should succeed (tests that the deletion
284  // properly disassociates that URL).
285  AddUrlToHistory(0, new_url);
286
287  // Let sync finish.
288  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
289
290  // Both clients should have this URL added again.
291  AssertAllProfilesHaveSameURLsAsVerifier();
292}
293
294IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
295                       MergeTypedWithNonTypedDuringAssociation) {
296  ASSERT_TRUE(SetupClients());
297  GURL new_url("http://history.com");
298  base::Time timestamp = base::Time::Now();
299  // Put a non-typed URL in both clients with an identical timestamp.
300  // Then add a typed URL to the second client - this test makes sure that
301  // we properly merge both sets of visits together to end up with the same
302  // set of visits on both ends.
303  AddUrlToHistoryWithTimestamp(0, new_url, content::PAGE_TRANSITION_LINK,
304                               history::SOURCE_BROWSED, timestamp);
305  AddUrlToHistoryWithTimestamp(1, new_url, content::PAGE_TRANSITION_LINK,
306                               history::SOURCE_BROWSED, timestamp);
307  AddUrlToHistoryWithTimestamp(1, new_url, content::PAGE_TRANSITION_TYPED,
308                               history::SOURCE_BROWSED,
309                               timestamp + base::TimeDelta::FromSeconds(1));
310
311  // Now start up sync - URLs should get merged. Fully sync client 1 first,
312  // before syncing client 0, so we have both of client 1's URLs in the sync DB
313  // at the time that client 0 does model association.
314  ASSERT_TRUE(GetClient(1)->SetupSync()) << "SetupSync() failed";
315  GetClient(1)->AwaitFullSyncCompletion("Initial client sync");
316  ASSERT_TRUE(GetClient(0)->SetupSync()) << "SetupSync() failed";
317  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
318
319  ASSERT_TRUE(CheckClientsEqual());
320  // At this point, we should have no duplicates (total visit count should be
321  // 2). We only need to check client 0 since we already verified that both
322  // clients are identical above.
323  history::URLRows urls = GetTypedUrlsFromClient(0);
324  ASSERT_EQ(1U, urls.size());
325  ASSERT_EQ(new_url, urls[0].url());
326  ASSERT_TRUE(CheckNoDuplicateVisits());
327  ASSERT_EQ(2, GetVisitCountForFirstURL(0));
328}
329
330// Tests transitioning a URL from non-typed to typed when both clients
331// have already seen that URL (so a merge is required).
332IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
333                       MergeTypedWithNonTypedDuringChangeProcessing) {
334  ASSERT_TRUE(SetupClients());
335  GURL new_url("http://history.com");
336  base::Time timestamp = base::Time::Now();
337  // Setup both clients with the identical typed URL visit. This means we can't
338  // use the verifier in this test, because this will show up as two distinct
339  // visits in the verifier.
340  AddUrlToHistoryWithTimestamp(0, new_url, content::PAGE_TRANSITION_LINK,
341                               history::SOURCE_BROWSED, timestamp);
342  AddUrlToHistoryWithTimestamp(1, new_url, content::PAGE_TRANSITION_LINK,
343                               history::SOURCE_BROWSED, timestamp);
344
345  // Now start up sync. Neither URL should get synced as they do not look like
346  // typed URLs.
347  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
348  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
349  ASSERT_TRUE(CheckClientsEqual());
350  history::URLRows urls = GetTypedUrlsFromClient(0);
351  ASSERT_EQ(0U, urls.size());
352
353  // Now, add a typed visit to the first client.
354  AddUrlToHistoryWithTimestamp(0, new_url, content::PAGE_TRANSITION_TYPED,
355                               history::SOURCE_BROWSED,
356                               timestamp + base::TimeDelta::FromSeconds(1));
357
358  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
359  ASSERT_TRUE(CheckClientsEqual());
360  ASSERT_TRUE(CheckNoDuplicateVisits());
361  urls = GetTypedUrlsFromClient(0);
362  ASSERT_EQ(1U, urls.size());
363  ASSERT_EQ(2, GetVisitCountForFirstURL(0));
364  ASSERT_EQ(2, GetVisitCountForFirstURL(1));
365}
366
367// Tests transitioning a URL from non-typed to typed when one of the clients
368// has never seen that URL before (so no merge is necessary).
369IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, UpdateToNonTypedURL) {
370  const string16 kHistoryUrl(
371      ASCIIToUTF16("http://www.add-delete-add-history.google.com/"));
372  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
373
374  // Populate one client with a non-typed URL, should not be synced.
375  GURL new_url(kHistoryUrl);
376  AddUrlToHistoryWithTransition(0, new_url, content::PAGE_TRANSITION_LINK,
377                                history::SOURCE_BROWSED);
378  history::URLRows urls = GetTypedUrlsFromClient(0);
379  ASSERT_EQ(0U, urls.size());
380
381  // Let sync finish.
382  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
383
384  // Both clients should have 0 typed URLs.
385  AssertAllProfilesHaveSameURLsAsVerifier();
386  urls = GetTypedUrlsFromClient(0);
387  ASSERT_EQ(0U, urls.size());
388
389  // Now, add a typed visit to this URL.
390  AddUrlToHistory(0, new_url);
391
392  // Let sync finish.
393  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
394
395  // Both clients should have this URL as typed and have two visits synced up.
396  ASSERT_TRUE(CheckClientsEqual());
397  urls = GetTypedUrlsFromClient(0);
398  ASSERT_EQ(1U, urls.size());
399  ASSERT_EQ(new_url, urls[0].url());
400  ASSERT_EQ(2, GetVisitCountForFirstURL(0));
401}
402
403IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
404                       SkipImportedVisits) {
405
406  GURL imported_url("http://imported_url.com");
407  GURL browsed_url("http://browsed_url.com");
408  GURL browsed_and_imported_url("http://browsed_and_imported_url.com");
409  ASSERT_TRUE(SetupClients());
410
411  // Create 3 items in our first client - 1 imported, one browsed, one with
412  // both imported and browsed entries.
413  AddUrlToHistoryWithTransition(0, imported_url,
414                                content::PAGE_TRANSITION_TYPED,
415                                history::SOURCE_FIREFOX_IMPORTED);
416  AddUrlToHistoryWithTransition(0, browsed_url,
417                                content::PAGE_TRANSITION_TYPED,
418                                history::SOURCE_BROWSED);
419  AddUrlToHistoryWithTransition(0, browsed_and_imported_url,
420                                content::PAGE_TRANSITION_TYPED,
421                                history::SOURCE_FIREFOX_IMPORTED);
422
423  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
424  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
425  history::URLRows urls = GetTypedUrlsFromClient(1);
426  ASSERT_EQ(1U, urls.size());
427  ASSERT_EQ(browsed_url, urls[0].url());
428
429  // Now browse to 3rd URL - this should cause it to be synced, even though it
430  // was initially imported.
431  AddUrlToHistoryWithTransition(0, browsed_and_imported_url,
432                                content::PAGE_TRANSITION_TYPED,
433                                history::SOURCE_BROWSED);
434  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
435  urls = GetTypedUrlsFromClient(1);
436  ASSERT_EQ(2U, urls.size());
437
438  // Make sure the imported URL didn't make it over.
439  for (size_t i = 0; i < urls.size(); ++i) {
440    ASSERT_NE(imported_url, urls[i].url());
441  }
442}
443
444IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, BookmarksWithTypedVisit) {
445  GURL bookmark_url("http://www.bookmark.google.com/");
446  GURL bookmark_icon_url("http://www.bookmark.google.com/favicon.ico");
447  ASSERT_TRUE(SetupClients());
448  // Create a bookmark.
449  const BookmarkNode* node = bookmarks_helper::AddURL(
450      0, bookmarks_helper::IndexedURLTitle(0), bookmark_url);
451  bookmarks_helper::SetFavicon(0, node, bookmark_icon_url,
452      bookmarks_helper::CreateFavicon(SK_ColorWHITE),
453      bookmarks_helper::FROM_UI);
454  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
455
456  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
457  // A row in the DB for client 1 should have been created as a result of the
458  // sync.
459  history::URLRow row;
460  ASSERT_TRUE(GetUrlFromClient(1, bookmark_url, &row));
461
462  // Now, add a typed visit for client 0 to the bookmark URL and sync it over
463  // - this should not cause a crash.
464  AddUrlToHistory(0, bookmark_url);
465  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
466
467  AssertAllProfilesHaveSameURLsAsVerifier();
468  history::URLRows urls = GetTypedUrlsFromClient(0);
469  ASSERT_EQ(1U, urls.size());
470  ASSERT_EQ(bookmark_url, urls[0].url());
471  ASSERT_EQ(1, GetVisitCountForFirstURL(0));
472}
473