summaryrefslogtreecommitdiffstats
path: root/chrome/test/live_sync
diff options
context:
space:
mode:
authortim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-05 20:06:15 +0000
committertim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-05 20:06:15 +0000
commite7ef7150c893a1ff2fe4197ce9d76ccb21001caa (patch)
tree639aa7b62035bbe557dff59d2c43c7a635d0f15c /chrome/test/live_sync
parentcc4ba248e6714e6cf29bfa956d415977d78db246 (diff)
downloadchromium_src-e7ef7150c893a1ff2fe4197ce9d76ccb21001caa.zip
chromium_src-e7ef7150c893a1ff2fe4197ce9d76ccb21001caa.tar.gz
chromium_src-e7ef7150c893a1ff2fe4197ce9d76ccb21001caa.tar.bz2
Add the sync files to chrome.gyp. They still don't result in anything building because
the files are wrapped in #ifdef CHROME_PERSONALIZATION which is not defined anywhere at the moment. Add live_sync to chrome\test and corresponding target to chrome.gyp Review URL: http://codereview.chromium.org/159902 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22521 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/test/live_sync')
-rw-r--r--chrome/test/live_sync/bookmark_model_verifier.cc162
-rw-r--r--chrome/test/live_sync/bookmark_model_verifier.h95
-rw-r--r--chrome/test/live_sync/live_bookmarks_sync_test.cc80
-rw-r--r--chrome/test/live_sync/live_bookmarks_sync_test.h69
-rw-r--r--chrome/test/live_sync/profile_sync_service_test_harness.cc253
-rw-r--r--chrome/test/live_sync/profile_sync_service_test_harness.h111
-rw-r--r--chrome/test/live_sync/single_client_live_bookmarks_sync_unittest.cc157
-rw-r--r--chrome/test/live_sync/two_client_live_bookmarks_sync_test.cc1116
8 files changed, 2043 insertions, 0 deletions
diff --git a/chrome/test/live_sync/bookmark_model_verifier.cc b/chrome/test/live_sync/bookmark_model_verifier.cc
new file mode 100644
index 0000000..f5280fb
--- /dev/null
+++ b/chrome/test/live_sync/bookmark_model_verifier.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef CHROME_PERSONALIZATION
+
+#include "chrome/test/live_sync/bookmark_model_verifier.h"
+
+#include <vector>
+#include <stack>
+
+#include "app/tree_node_iterator.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_utils.h"
+#include "chrome/browser/test/live_sync/live_bookmarks_sync_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// static
+void BookmarkModelVerifier::ExpectBookmarkInfoMatch(
+ const BookmarkNode* expected, const BookmarkNode* actual) {
+ EXPECT_EQ(expected->GetTitle(), actual->GetTitle());
+ EXPECT_EQ(expected->is_folder(), actual->is_folder());
+ EXPECT_EQ(expected->GetURL(), actual->GetURL());
+ EXPECT_EQ(expected->GetParent()->IndexOfChild(expected),
+ actual->GetParent()->IndexOfChild(actual));
+}
+
+BookmarkModelVerifier::BookmarkModelVerifier() {
+ verifier_profile_.reset(LiveBookmarksSyncTest::MakeProfile(L"verifier"));
+ verifier_ = verifier_profile_->GetBookmarkModel();
+}
+
+BookmarkModelVerifier* BookmarkModelVerifier::Create() {
+ BookmarkModelVerifier* v = new BookmarkModelVerifier();
+ LiveBookmarksSyncTest::BlockUntilLoaded(v->verifier_);
+ return v;
+}
+
+void BookmarkModelVerifier::ExpectMatch(BookmarkModel* actual) {
+ ExpectModelsMatch(verifier_, actual);
+}
+
+// static
+void BookmarkModelVerifier::ExpectModelsMatch(
+ BookmarkModel* expected, BookmarkModel* actual) {
+ TreeNodeIterator<const BookmarkNode> e_iterator(expected->root_node());
+ TreeNodeIterator<const BookmarkNode> a_iterator(actual->root_node());
+
+ // Pre-order traversal of each model, comparing at each step.
+ while (e_iterator.has_next()) {
+ const BookmarkNode* e_node = e_iterator.Next();
+ ASSERT_TRUE(a_iterator.has_next());
+ const BookmarkNode* a_node = a_iterator.Next();
+ ExpectBookmarkInfoMatch(e_node, a_node);
+ }
+ ASSERT_FALSE(a_iterator.has_next());
+}
+
+void BookmarkModelVerifier::FindNodeInVerifier(BookmarkModel* foreign_model,
+ const BookmarkNode* foreign_node,
+ const BookmarkNode** result) {
+ // Climb the tree.
+ std::stack<int> path;
+ const BookmarkNode* walker = foreign_node;
+ while (walker != foreign_model->root_node()) {
+ path.push(walker->GetParent()->IndexOfChild(walker));
+ walker = walker->GetParent();
+ }
+
+ // Swing over to the other tree.
+ walker = verifier_->root_node();
+
+ // Climb down.
+ while (!path.empty()) {
+ ASSERT_TRUE(walker->is_folder());
+ ASSERT_LT(path.top(), walker->GetChildCount());
+ walker = walker->GetChild(path.top());
+ path.pop();
+ }
+
+ ExpectBookmarkInfoMatch(foreign_node, walker);
+ *result = walker;
+}
+
+const BookmarkNode* BookmarkModelVerifier::AddGroup(BookmarkModel* model,
+ const BookmarkNode* parent, int index, const string16& title) {
+ const BookmarkNode* v_parent = NULL;
+ FindNodeInVerifier(model, parent, &v_parent);
+ const BookmarkNode* result = model->AddGroup(parent, index, title);
+ EXPECT_TRUE(result);
+ if (!result) return NULL;
+ const BookmarkNode* v_node = verifier_->AddGroup(v_parent, index, title);
+ EXPECT_TRUE(v_node);
+ if (!v_node) return NULL;
+ ExpectBookmarkInfoMatch(v_node, result);
+ return result;
+}
+
+const BookmarkNode* BookmarkModelVerifier::AddURL(BookmarkModel* model,
+ const BookmarkNode* parent, int index, const string16& title,
+ const GURL& url) {
+ const BookmarkNode* v_parent = NULL;
+ FindNodeInVerifier(model, parent, &v_parent);
+ const BookmarkNode* result = model->AddURL(parent, index, title, url);
+ EXPECT_TRUE(result);
+ if (!result) return NULL;
+ const BookmarkNode* v_node = verifier_->AddURL(v_parent, index, title, url);
+ EXPECT_TRUE(v_node);
+ if (!v_node) return NULL;
+ ExpectBookmarkInfoMatch(v_node, result);
+ return result;
+}
+
+void BookmarkModelVerifier::SetTitle(BookmarkModel* model,
+ const BookmarkNode* node,
+ const string16& title) {
+ const BookmarkNode* v_node = NULL;
+ FindNodeInVerifier(model, node, &v_node);
+ model->SetTitle(node, title);
+ verifier_->SetTitle(v_node, title);
+}
+
+void BookmarkModelVerifier::Move(BookmarkModel* model, const BookmarkNode* node,
+ const BookmarkNode* new_parent, int index) {
+ const BookmarkNode* v_new_parent = NULL;
+ const BookmarkNode* v_node = NULL;
+ FindNodeInVerifier(model, new_parent, &v_new_parent);
+ FindNodeInVerifier(model, node, &v_node);
+ model->Move(node, new_parent, index);
+ verifier_->Move(v_node, v_new_parent, index);
+}
+
+void BookmarkModelVerifier::Remove(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index) {
+ const BookmarkNode* v_parent = NULL;
+ FindNodeInVerifier(model, parent, &v_parent);
+ ExpectBookmarkInfoMatch(parent->GetChild(index), v_parent->GetChild(index));
+ model->Remove(parent, index);
+ verifier_->Remove(v_parent, index);
+}
+
+void BookmarkModelVerifier::SortChildren(BookmarkModel* model,
+ const BookmarkNode* parent) {
+ const BookmarkNode* v_parent = NULL;
+ FindNodeInVerifier(model, parent, &v_parent);
+ model->SortChildren(parent);
+ verifier_->SortChildren(v_parent);
+}
+
+void BookmarkModelVerifier::SetURL(BookmarkModel* model,
+ const BookmarkNode* node,
+ const GURL& new_url) {
+ const BookmarkNode* v_node = NULL;
+ FindNodeInVerifier(model, node, &v_node);
+ bookmark_utils::ApplyEditsWithNoGroupChange(model, node->GetParent(),
+ node, node->GetTitle(), new_url, NULL);
+ bookmark_utils::ApplyEditsWithNoGroupChange(verifier_, v_node->GetParent(),
+ v_node, v_node->GetTitle(), new_url, NULL);
+}
+
+#endif // CHROME_PERSONALIZATION
diff --git a/chrome/test/live_sync/bookmark_model_verifier.h b/chrome/test/live_sync/bookmark_model_verifier.h
new file mode 100644
index 0000000..889ab71
--- /dev/null
+++ b/chrome/test/live_sync/bookmark_model_verifier.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef CHROME_PERSONALIZATION
+
+#ifndef CHROME_TEST_LIVE_SYNC_BOOKMARK_MODEL_VERIFIER_H_
+#define CHROME_TEST_LIVE_SYNC_BOOKMARK_MODEL_VERIFIER_H_
+
+#include <string>
+#include "chrome/browser/profile.h"
+#include "googleurl/src/gurl.h"
+
+class BookmarkModel;
+class BookmarkNode;
+
+// A tool to perform bookmark model operations on a model and have
+// the changes echoed in a "verifier" model that can be used as an expected
+// hierarchy to compare against.
+// Note when we refer to the "same" nodes in |model| and |verifier| parameters,
+// we mean same the canonical bookmark entity, because |verifier| is expected
+// to be a replica of |model|.
+class BookmarkModelVerifier {
+ public:
+ ~BookmarkModelVerifier() { }
+
+ // Creates a BookmarkModelVerifier and waits until the model has loaded.
+ // Caller takes ownership.
+ static BookmarkModelVerifier* Create();
+
+ // Adds the same folder to |model| and |verifier|.
+ // See BookmarkModel::AddGroup for details.
+ const BookmarkNode* AddGroup(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index,
+ const string16& title);
+
+ // Adds the same bookmark to |model| and |verifier|.
+ // See BookmarkModel::AddURL for details.
+ const BookmarkNode* AddURL(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index,
+ const string16& title,
+ const GURL& url);
+
+ // Sets the title of the same node in |model| and |verifier|.
+ // See BookmarkModel::SetTitle for details.
+ void SetTitle(BookmarkModel* model, const BookmarkNode* node,
+ const string16& title);
+
+ // Moves the same node to the same position in both |model| and |verifier|.
+ // See BookmarkModel::Move for details.
+ void Move(BookmarkModel* model,
+ const BookmarkNode* node,
+ const BookmarkNode* new_parent,
+ int index);
+
+ // Removes the same node in |model| and |verifier|.
+ // See BookmarkModel::Remove for details.
+ void Remove(BookmarkModel* model, const BookmarkNode* parent, int index);
+
+ // Sorts children of the same parent node in |model| and |verifier|.
+ // See BookmarkModel::SortChildren for details.
+ void SortChildren(BookmarkModel* model, const BookmarkNode* parent);
+
+ void SetURL(BookmarkModel* model,
+ const BookmarkNode* node,
+ const GURL& new_url);
+
+ // Asserts that the verifier model and |actual| are equivalent.
+ void ExpectMatch(BookmarkModel* actual);
+
+ // Asserts that the two hierarchies are equivalent in terms of the data model.
+ // (e.g some peripheral fields like creation times are allowed to mismatch).
+ static void ExpectModelsMatch(BookmarkModel* expected, BookmarkModel* actual);
+
+ private:
+ BookmarkModelVerifier();
+ void FindNodeInVerifier(BookmarkModel* foreign_model,
+ const BookmarkNode* foreign_node,
+ const BookmarkNode** result);
+
+ // Does a deep comparison of BookmarkNode fields between the two parameters,
+ // and asserts equality.
+ static void ExpectBookmarkInfoMatch(const BookmarkNode* expected,
+ const BookmarkNode* actual);
+
+ scoped_ptr<Profile> verifier_profile_;
+ BookmarkModel* verifier_;
+ DISALLOW_COPY_AND_ASSIGN(BookmarkModelVerifier);
+};
+
+#endif // CHROME_TEST_LIVE_SYNC_BOOKMARK_MODEL_VERIFIER_H_
+
+#endif // CHROME_PERSONALIZATION
diff --git a/chrome/test/live_sync/live_bookmarks_sync_test.cc b/chrome/test/live_sync/live_bookmarks_sync_test.cc
new file mode 100644
index 0000000..43c1db0
--- /dev/null
+++ b/chrome/test/live_sync/live_bookmarks_sync_test.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifdef CHROME_PERSONALIZATION
+
+#include "chrome/test/live_sync/live_bookmarks_sync_test.h"
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/profile_manager.h"
+#include "chrome/test/ui_test_utils.h"
+
+// BookmarkLoadObserver is used when blocking until the BookmarkModel
+// finishes loading. As soon as the BookmarkModel finishes loading the message
+// loop is quit.
+class BookmarkLoadObserver : public BookmarkModelObserver {
+ public:
+ BookmarkLoadObserver() {}
+ virtual void Loaded(BookmarkModel* model) {
+ MessageLoop::current()->Quit();
+ }
+
+ virtual void BookmarkNodeMoved(BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index) {}
+ virtual void BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index) {}
+ virtual void BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) {}
+ virtual void BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node) {}
+ virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
+ const BookmarkNode* node) {}
+ virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ const BookmarkNode* node) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BookmarkLoadObserver);
+};
+
+// static
+void LiveBookmarksSyncTest::BlockUntilLoaded(BookmarkModel* m) {
+ if (m->IsLoaded())
+ return;
+ BookmarkLoadObserver observer;
+ m->AddObserver(&observer);
+ ui_test_utils::RunMessageLoop();
+ m->RemoveObserver(&observer);
+ ASSERT_TRUE(m->IsLoaded());
+}
+
+// static
+const BookmarkNode* LiveBookmarksSyncTest::GetByUniqueURL(BookmarkModel* m,
+ const GURL& url) {
+ std::vector<const BookmarkNode*> nodes;
+ m->GetNodesByURL(url, &nodes);
+ EXPECT_EQ(1, nodes.size());
+ return nodes[0];
+}
+
+// static
+Profile* LiveBookmarksSyncTest::MakeProfile(const string16& name) {
+ string16 path_string;
+ PathService::Get(chrome::DIR_USER_DATA, &path_string);
+ file_util::AppendToPath(&path_string, name);
+ FilePath path(path_string);
+ return ProfileManager::CreateProfile(path, name, L"", L"");
+}
+
+#endif // CHROME_PERSONALIZATION
diff --git a/chrome/test/live_sync/live_bookmarks_sync_test.h b/chrome/test/live_sync/live_bookmarks_sync_test.h
new file mode 100644
index 0000000..0c603802
--- /dev/null
+++ b/chrome/test/live_sync/live_bookmarks_sync_test.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef CHROME_PERSONALIZATION
+
+#ifndef CHROME_TEST_LIVE_SYNC_LIVE_BOOKMARKS_SYNC_TEST_H_
+#define CHROME_TEST_LIVE_SYNC_LIVE_BOOKMARKS_SYNC_TEST_H_
+
+#include <string>
+
+#include "base/command_line.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/browser/sync/personalization.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "googleurl/src/gurl.h"
+
+class BookmarkModel;
+class BookmarkNode;
+class Profile;
+
+// TODO(timsteele): This should be moved out of personalization_unit_tests into
+// its own project that doesn't get run by default on the standard buildbot
+// without a valid sync server set up.
+class LiveBookmarksSyncTest : public InProcessBrowserTest {
+ public:
+ LiveBookmarksSyncTest() { }
+ ~LiveBookmarksSyncTest() { }
+
+ virtual void SetUp() {
+ // At this point, the browser hasn't been launched, and no services are
+ // available. But we can verify our command line parameters and fail
+ // early.
+ const CommandLine* cl = CommandLine::ForCurrentProcess();
+ username_ = WideToUTF8(cl->GetSwitchValue(switches::kSyncUserForTest));
+ password_ = WideToUTF8(cl->GetSwitchValue(switches::kSyncPasswordForTest));
+ ASSERT_FALSE(username_.empty()) << "Can't run live server test "
+ << "without specifying --" << switches::kSyncUserForTest;
+ ASSERT_FALSE(password_.empty()) << "Can't run live server test "
+ << "without specifying --" << switches::kSyncPasswordForTest;
+
+ // Yield control back to the InProcessBrowserTest framework.
+ InProcessBrowserTest::SetUp();
+ }
+
+ // Helper to get a handle on a bookmark in |m| when the url is known to be
+ // unique.
+ static const BookmarkNode* GetByUniqueURL(BookmarkModel* m, const GURL& url);
+
+ // Helper to ProfileManager::CreateProfile that handles path creation.
+ static Profile* MakeProfile(const string16& name);
+
+ // Utility to block (by running the current MessageLoop) until the model has
+ // loaded. Note this is required instead of using m->BlockTillLoaded, as that
+ // cannot be called from the main thread (deadlock will occur).
+ static void BlockUntilLoaded(BookmarkModel* m);
+
+ protected:
+ std::string username_;
+ std::string password_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LiveBookmarksSyncTest);
+};
+
+#endif // CHROME_TEST_SYNC_LIVE_BOOKMARKS_SYNC_TEST_H_
+
+#endif // CHROME_PERSONALIZATION
diff --git a/chrome/test/live_sync/profile_sync_service_test_harness.cc b/chrome/test/live_sync/profile_sync_service_test_harness.cc
new file mode 100644
index 0000000..57ceeb6
--- /dev/null
+++ b/chrome/test/live_sync/profile_sync_service_test_harness.cc
@@ -0,0 +1,253 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifdef CHROME_PERSONALIZATION
+
+#include "base/message_loop.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/browser/sync/auth_error_state.h"
+#include "chrome/test/live_sync/profile_sync_service_test_harness.h"
+#include "chrome/test/ui_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// The default value for min_updates_needed_ when we're not in a call to
+// WaitForUpdatesRecievedAtLeast.
+static const int kMinUpdatesNeededNone = -1;
+
+static const ProfileSyncService::Status kInvalidStatus = {};
+
+// Simple class to implement a timeout using PostDelayedTask. If it is not
+// aborted before picked up by a message queue, then it asserts with the message
+// provided. This class is not thread safe.
+class StateChangeTimeoutEvent
+ : public base::RefCountedThreadSafe<StateChangeTimeoutEvent> {
+ public:
+ explicit StateChangeTimeoutEvent(ProfileSyncServiceTestHarness* caller,
+ const std::string& message);
+ ~StateChangeTimeoutEvent();
+
+ // The entry point to the class from PostDelayedTask.
+ void Callback();
+
+ // Cancels the actions of the callback. Returns true if success, false
+ // if the callback has already timed out.
+ bool Abort();
+
+ private:
+ bool aborted_;
+ bool did_timeout_;
+
+ // Due to synchronization of the IO loop, the caller will always be alive
+ // if the class is not aborted.
+ ProfileSyncServiceTestHarness* caller_;
+
+ // Informative message to assert in the case of a timeout.
+ std::string message_;
+
+ DISALLOW_COPY_AND_ASSIGN(StateChangeTimeoutEvent);
+};
+
+StateChangeTimeoutEvent::StateChangeTimeoutEvent(
+ ProfileSyncServiceTestHarness* caller,
+ const std::string& message)
+ : aborted_(false), did_timeout_(false), caller_(caller), message_(message) {
+}
+
+StateChangeTimeoutEvent::~StateChangeTimeoutEvent() {
+}
+
+void StateChangeTimeoutEvent::Callback() {
+ if (!aborted_) {
+ if (!caller_->RunStateChangeMachine()) {
+ // Report the message.
+ did_timeout_ = true;
+ EXPECT_FALSE(aborted_) << message_;
+ caller_->SignalStateComplete();
+ }
+ }
+}
+
+bool StateChangeTimeoutEvent::Abort() {
+ aborted_ = true;
+ caller_ = NULL;
+ return !did_timeout_;
+}
+
+class ConflictTimeoutEvent
+ : public base::RefCountedThreadSafe<ConflictTimeoutEvent> {
+ public:
+ explicit ConflictTimeoutEvent(ProfileSyncServiceTestHarness* caller)
+ : caller_(caller), did_run_(false) {
+ }
+ ~ConflictTimeoutEvent() { }
+
+ // The entry point to the class from PostDelayedTask.
+ void Callback();
+ bool did_run_;
+
+ private:
+
+ // Due to synchronization of the IO loop, the caller will always be alive
+ // if the class is not aborted.
+ ProfileSyncServiceTestHarness* caller_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConflictTimeoutEvent);
+};
+
+void ConflictTimeoutEvent::Callback() {
+ caller_->SignalStateComplete();
+ did_run_ = true;
+}
+
+
+ProfileSyncServiceTestHarness::ProfileSyncServiceTestHarness(
+ Profile* p, const std::string& username, const std::string& password)
+ : wait_state_(WAITING_FOR_INITIAL_CALLBACK), profile_(p), service_(NULL),
+ last_status_(kInvalidStatus), min_updates_needed_(kMinUpdatesNeededNone),
+ username_(username), password_(password) {
+ // Ensure the profile has enough prefs registered for use by sync.
+ if (!p->GetPrefs()->IsPrefRegistered(prefs::kAcceptLanguages))
+ TabContents::RegisterUserPrefs(p->GetPrefs());
+ if (!p->GetPrefs()->IsPrefRegistered(prefs::kCookieBehavior))
+ Browser::RegisterUserPrefs(p->GetPrefs());
+}
+
+bool ProfileSyncServiceTestHarness::SetupSync() {
+ service_ = profile_->GetProfilePersonalization()->sync_service();
+ profile_->GetPrefs()->SetBoolean(prefs::kSyncHasSetupCompleted, true);
+ service_->EnableForUser();
+
+ // Needed to avoid showing the login dialog. Well aware this is egregious.
+ service_->expecting_first_run_auth_needed_event_ = false;
+ service_->AddObserver(this);
+ return WaitForServiceInit();
+}
+
+void ProfileSyncServiceTestHarness::SignalStateCompleteWithNextState(
+ WaitState next_state) {
+
+ wait_state_ = next_state;
+ SignalStateComplete();
+}
+
+void ProfileSyncServiceTestHarness::SignalStateComplete() {
+ MessageLoopForUI::current()->Quit();
+}
+
+bool ProfileSyncServiceTestHarness::RunStateChangeMachine() {
+ WaitState state = wait_state_;
+ ProfileSyncService::Status status(service_->QueryDetailedSyncStatus());
+ switch (wait_state_) {
+ case WAITING_FOR_INITIAL_CALLBACK:
+ SignalStateCompleteWithNextState(WAITING_FOR_READY_TO_PROCESS_CHANGES);
+ break;
+ case WAITING_FOR_READY_TO_PROCESS_CHANGES:
+ if (service_->ready_to_process_changes_) {
+ SignalStateCompleteWithNextState(WAITING_FOR_NOTHING);
+ }
+ break;
+ case WAITING_FOR_TIMESTAMP_UPDATE: {
+ const base::Time current_timestamp = service_->last_synced_time();
+ if (current_timestamp == last_timestamp_) {
+ break;
+ }
+ EXPECT_TRUE(last_timestamp_ < current_timestamp);
+ last_timestamp_ = current_timestamp;
+ SignalStateCompleteWithNextState(WAITING_FOR_NOTHING);
+ break;
+ }
+ case WAITING_FOR_UPDATES:
+ if (status.updates_received < min_updates_needed_) {
+ break;
+ }
+ SignalStateCompleteWithNextState(WAITING_FOR_NOTHING);
+ break;
+ case WAITING_FOR_NOTHING:
+ default:
+ // Invalid state during observer callback which may be triggered by other
+ // classes using the the UI message loop. Defer to their handling.
+ break;
+ }
+ last_status_ = status;
+ return state != wait_state_;
+}
+
+void ProfileSyncServiceTestHarness::OnStateChanged() {
+ RunStateChangeMachine();
+}
+
+bool ProfileSyncServiceTestHarness::AwaitSyncCycleCompletion(
+ const std::string& reason) {
+ wait_state_ = WAITING_FOR_TIMESTAMP_UPDATE;
+ return AwaitStatusChangeWithTimeout(60, reason);
+}
+
+bool ProfileSyncServiceTestHarness::AwaitMutualSyncCycleCompletion(
+ ProfileSyncServiceTestHarness* partner) {
+ return AwaitSyncCycleCompletion("Sync cycle completion on active client.") &&
+ partner->AwaitSyncCycleCompletion(
+ "Sync cycle completion on passive client.");
+}
+
+bool ProfileSyncServiceTestHarness::AwaitStatusChangeWithTimeout(
+ int timeout_seconds,
+ const std::string& reason) {
+ scoped_refptr<StateChangeTimeoutEvent> timeout_signal(
+ new StateChangeTimeoutEvent(this, reason));
+ MessageLoopForUI* loop = MessageLoopForUI::current();
+ loop->PostDelayedTask(
+ FROM_HERE,
+ NewRunnableMethod(timeout_signal.get(),
+ &StateChangeTimeoutEvent::Callback),
+ 1000 * timeout_seconds);
+ ui_test_utils::RunMessageLoop();
+ return timeout_signal->Abort();
+}
+
+bool ProfileSyncServiceTestHarness::AwaitMutualSyncCycleCompletionWithConflict(
+ ProfileSyncServiceTestHarness* partner) {
+
+ if (!AwaitMutualSyncCycleCompletion(partner)) {
+ return false;
+ }
+ if (!partner->AwaitMutualSyncCycleCompletion(this)) {
+ return false;
+ }
+
+ scoped_refptr<ConflictTimeoutEvent> timeout_signal(
+ new ConflictTimeoutEvent(this));
+
+ // Now we want to wait an extra 20 seconds to ensure any rebounding updates
+ // due to a conflict are processed and observed by each client.
+ MessageLoopForUI* loop = MessageLoopForUI::current();
+ loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(timeout_signal.get(),
+ &ConflictTimeoutEvent::Callback), 1000 * 20);
+ // It is possible that timeout has not run yet and loop exited due to
+ // OnStateChanged event. So to avoid pre-mature termination of loop,
+ // we are re-running the loop until did_run_ becomes true.
+ while (!timeout_signal->did_run_) {
+ ui_test_utils::RunMessageLoop();
+ }
+ return true;
+}
+
+bool ProfileSyncServiceTestHarness::WaitForServiceInit() {
+ // Wait for the initial (auth needed) callback.
+ EXPECT_EQ(wait_state_, WAITING_FOR_INITIAL_CALLBACK);
+ if (!AwaitStatusChangeWithTimeout(30, "Waiting for authwatcher calback.")) {
+ return false;
+ }
+
+ // Wait for the OnBackendInitialized callback.
+ service_->backend()->Authenticate(username_, password_);
+ EXPECT_EQ(wait_state_, WAITING_FOR_READY_TO_PROCESS_CHANGES);
+ if (!AwaitStatusChangeWithTimeout(30, "Waiting on backend initialization.")) {
+ return false;
+ }
+ return service_->sync_initialized();
+}
+
+#endif // CHROME_PERSONALIZATION
diff --git a/chrome/test/live_sync/profile_sync_service_test_harness.h b/chrome/test/live_sync/profile_sync_service_test_harness.h
new file mode 100644
index 0000000..48f40f1
--- /dev/null
+++ b/chrome/test/live_sync/profile_sync_service_test_harness.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifdef CHROME_PERSONALIZATION
+
+#ifndef CHROME_TEST_LIVE_SYNC_PROFILE_SYNC_SERVICE_TEST_HARNESS_H_
+#define CHROME_TEST_LIVE_SYNC_PROFILE_SYNC_SERVICE_TEST_HARNESS_H_
+
+#include <string>
+
+#include "base/time.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+
+class Profile;
+
+// An instance of this class is basically our notion of a "sync client" for
+// test purposes. It harnesses the ProfileSyncService member of the profile
+// passed to it on construction and automates certain things like setup and
+// authentication. It provides ways to "wait" adequate periods of time for
+// several clients to get to the same state.
+class ProfileSyncServiceTestHarness : public ProfileSyncServiceObserver {
+ public:
+ ProfileSyncServiceTestHarness(Profile* p, const std::string& username,
+ const std::string& password);
+
+ // Creates a ProfileSyncService for the profile passed at construction and
+ // enables sync. Returns true only after sync has been fully initialized and
+ // authenticated, and we are ready to process changes.
+ bool SetupSync();
+
+ // ProfileSyncServiceObserver implementation.
+ virtual void OnStateChanged();
+
+ // Blocks the caller until this harness has completed a single sync cycle
+ // since the previous one. Returns true if a sync cycle has completed.
+ bool AwaitSyncCycleCompletion(const std::string& reason);
+
+ // Wait an extra 20 seconds to ensure any rebounding updates
+ // due to a conflict are processed and observed by each client.
+ bool AwaitMutualSyncCycleCompletionWithConflict(
+ ProfileSyncServiceTestHarness* partner);
+
+ // Calling this acts as a barrier and blocks the caller until |this| and
+ // |partner| have both completed a sync cycle. When calling this method,
+ // the |partner| should be the passive responder who responds to the actions
+ // of |this|. This method relies upon the synchronization of callbacks
+ // from the message queue. Returns true if two sync cycles have completed.
+ bool AwaitMutualSyncCycleCompletion(ProfileSyncServiceTestHarness* partner);
+
+ ProfileSyncService* service() { return service_; }
+
+ // See ProfileSyncService::ShouldPushChanges().
+ bool ServiceIsPushingChanges() { return service_->ShouldPushChanges(); }
+
+ private:
+ friend class StateChangeTimeoutEvent;
+ friend class ConflictTimeoutEvent;
+
+ enum WaitState {
+ WAITING_FOR_INITIAL_CALLBACK = 0,
+ WAITING_FOR_READY_TO_PROCESS_CHANGES,
+ WAITING_FOR_TIMESTAMP_UPDATE,
+ WAITING_FOR_UPDATES,
+ WAITING_FOR_NOTHING,
+ NUMBER_OF_STATES
+ };
+
+ // Called from the observer when the current wait state has been completed.
+ void SignalStateCompleteWithNextState(WaitState next_state);
+ void SignalStateComplete();
+
+ // Finite state machine for controlling state. Returns true only if a state
+ // change has taken place.
+ bool RunStateChangeMachine();
+
+ // Returns true if a status change took place, false on timeout.
+ virtual bool AwaitStatusChangeWithTimeout(int timeout_seconds,
+ const std::string& reason);
+
+ // Returns true if the service initialized correctly.
+ bool WaitForServiceInit();
+
+ WaitState wait_state_;
+
+ Profile* profile_;
+ ProfileSyncService* service_;
+
+ // State tracking. Used for debugging and tracking of state.
+ ProfileSyncService::Status last_status_;
+
+ // When awaiting quiescence, we are waiting for a change to this value. It
+ // is set to the current (ui-threadsafe) last synced timestamp returned by
+ // the sync service when AwaitQuiescence is called, and then we wait for an
+ // OnStatusChanged event to observe a new, more recent last synced timestamp.
+ base::Time last_timestamp_;
+
+ // The minimum value of the 'updates_received' member of SyncManager Status
+ // we need to wait to observe in OnStateChanged when told to
+ // WaitForUpdatesReceivedAtLeast.
+ int64 min_updates_needed_;
+
+ // Credentials used for GAIA authentication.
+ std::string username_;
+ std::string password_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceTestHarness);
+};
+
+#endif // CHROME_TEST_SYNC_PROFILE_SYNC_SERVICE_TEST_HARNESS_H_
+
+#endif // CHROME_PERSONALIZATION
diff --git a/chrome/test/live_sync/single_client_live_bookmarks_sync_unittest.cc b/chrome/test/live_sync/single_client_live_bookmarks_sync_unittest.cc
new file mode 100644
index 0000000..006b93e
--- /dev/null
+++ b/chrome/test/live_sync/single_client_live_bookmarks_sync_unittest.cc
@@ -0,0 +1,157 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef CHROME_PERSONALIZATION
+
+#include "base/command_line.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/sync/personalization.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/test/live_sync/bookmark_model_verifier.h"
+#include "chrome/test/live_sync/profile_sync_service_test_harness.h"
+#include "chrome/test/live_sync/live_bookmarks_sync_test.h"
+
+class SingleClientLiveBookmarksSyncTest : public LiveBookmarksSyncTest {
+ public:
+ SingleClientLiveBookmarksSyncTest() { }
+ ~SingleClientLiveBookmarksSyncTest() { }
+
+ bool SetupSync() {
+ client_.reset(new ProfileSyncServiceTestHarness(
+ browser()->profile(), username_, password_));
+ return client_->SetupSync();
+ }
+
+ ProfileSyncServiceTestHarness* client() { return client_.get(); }
+ ProfileSyncService* service() { return client_->service(); }
+
+ private:
+ scoped_ptr<ProfileSyncServiceTestHarness> client_;
+
+ DISALLOW_COPY_AND_ASSIGN(SingleClientLiveBookmarksSyncTest);
+};
+
+IN_PROC_BROWSER_TEST_F(SingleClientLiveBookmarksSyncTest, Sanity) {
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* m = browser()->profile()->GetBookmarkModel();
+ BlockUntilLoaded(m);
+
+ // Starting state:
+ // other_node
+ // -> top
+ // -> tier1_a
+ // -> http://mail.google.com "tier1_a_url0"
+ // -> http://www.pandora.com "tier1_a_url1"
+ // -> http://www.facebook.com "tier1_a_url2"
+ // -> tier1_b
+ // -> http://www.nhl.com "tier1_b_url0"
+ const BookmarkNode* top = verifier->AddGroup(m, m->other_node(), 0, L"top");
+ const BookmarkNode* tier1_a = verifier->AddGroup(m, top, 0, L"tier1_a");
+ const BookmarkNode* tier1_b = verifier->AddGroup(m, top, 1, L"tier1_b");
+ const BookmarkNode* t1au0 = verifier->AddURL(m, tier1_a, 0, L"tier1_a_url0",
+ GURL(L"http://mail.google.com"));
+ const BookmarkNode* t1au1 = verifier->AddURL(m, tier1_a, 1, L"tier1_a_url1",
+ GURL(L"http://www.pandora.com"));
+ const BookmarkNode* t1au2 = verifier->AddURL(
+ m, tier1_a, 2, L"tier1_a_url2", GURL(L"http://www.facebook.com"));
+ const BookmarkNode* t1bu0 = verifier->AddURL(m, tier1_b, 0, L"tier1_b_url0",
+ GURL(L"http://www.nhl.com"));
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ // SetupSync returns after init, which means got_zero_updates, which means
+ // before we merge and associate, so we now have to wait for our above state
+ // to round-trip.
+ ASSERT_TRUE(client()->AwaitSyncCycleCompletion(
+ "Waiting for initial sync completed."));
+ verifier->ExpectMatch(m);
+
+ // Ultimately we want to end up with the following model; but this test is
+ // more about the journey than the destination.
+ //
+ // bookmark_bar
+ // -> CNN (www.cnn.com)
+ // -> tier1_a
+ // -> tier1_a_url2 (www.facebook.com)
+ // -> tier1_a_url1 (www.pandora.com)
+ // -> Porsche (www.porsche.com)
+ // -> Bank of America (www.bankofamerica.com)
+ // -> Seattle Bubble
+ // other_node
+ // -> top
+ // -> tier1_b
+ // -> Wired News (www.wired.com)
+ // -> tier2_b
+ // -> tier1_b_url0
+ // -> tier3_b
+ // -> Toronto Maple Leafs (mapleleafs.nhl.com)
+ // -> Wynn (www.wynnlasvegas.com)
+ // -> tier1_a_url0
+ const BookmarkNode* bar = m->GetBookmarkBarNode();
+ const BookmarkNode* cnn =
+ verifier->AddURL(m, bar, 0, L"CNN", GURL(L"http://www.cnn.com"));
+ verifier->Move(m, tier1_a, bar, 1); // 1 should be the end at this point.
+ ASSERT_TRUE(client()->AwaitSyncCycleCompletion("Bookmark moved."));
+ verifier->ExpectMatch(m);
+
+ const BookmarkNode* porsche = verifier->AddURL(
+ m, bar, 2, L"Porsche", GURL(L"http://www.porsche.com"));
+ // Rearrange stuff in tier1_a.
+ EXPECT_EQ(tier1_a, t1au2->GetParent());
+ EXPECT_EQ(tier1_a, t1au1->GetParent());
+ verifier->Move(m, t1au2, tier1_a, 0);
+ verifier->Move(m, t1au1, tier1_a, 2);
+ ASSERT_TRUE(client()->AwaitSyncCycleCompletion("Rearrange stuff in tier1_a"));
+ verifier->ExpectMatch(m);
+
+ EXPECT_EQ(1, t1au0->GetParent()->IndexOfChild(t1au0));
+ verifier->Move(m, t1au0, bar, bar->GetChildCount());
+ const BookmarkNode* boa = verifier->AddURL(m, bar, bar->GetChildCount(),
+ L"Bank of America", GURL(L"https://www.bankofamerica.com"));
+ verifier->Move(m, t1au0, top, top->GetChildCount());
+ const BookmarkNode* bubble = verifier->AddURL(m, bar, bar->GetChildCount(),
+ L"Seattle Bubble", GURL(L"http://seattlebubble.com"));
+ const BookmarkNode* wired = verifier->AddURL(m, bar, 2, L"Wired News",
+ GURL(L"http://www.wired.com"));
+ const BookmarkNode* tier2_b = verifier->AddGroup(m, tier1_b, 0, L"tier2_b");
+ verifier->Move(m, t1bu0, tier2_b, 0);
+ verifier->Move(m, porsche, bar, 0);
+ verifier->SetTitle(m, wired, L"News Wired");
+ verifier->SetTitle(m, porsche, L"ICanHazPorsche?");
+ ASSERT_TRUE(client()->AwaitSyncCycleCompletion("Change title."));
+ verifier->ExpectMatch(m);
+
+ EXPECT_EQ(t1au0->id(), top->GetChild(top->GetChildCount() - 1)->id());
+ verifier->Remove(m, top, top->GetChildCount() - 1);
+ verifier->Move(m, wired, tier1_b, 0);
+ verifier->Move(m, porsche, bar, 3);
+ const BookmarkNode* tier3_b = verifier->AddGroup(m, tier2_b, 1, L"tier3_b");
+ const BookmarkNode* leafs = verifier->AddURL(
+ m, tier1_a, 0, L"Toronto Maple Leafs",
+ GURL(L"http://mapleleafs.nhl.com"));
+ const BookmarkNode* wynn = verifier->AddURL(
+ m, bar, 1, L"Wynn", GURL(L"http://www.wynnlasvegas.com"));
+
+ verifier->Move(m, wynn, tier3_b, 0);
+ verifier->Move(m, leafs, tier3_b, 0);
+ ASSERT_TRUE(client()->AwaitSyncCycleCompletion(
+ "Move after addition of bookmarks."));
+ verifier->ExpectMatch(m);
+}
+
+// Connects a client with no bookmarks to a cloud account. As a natural
+// consequence of shutdown, this will encode the BookmarkModel as JSON to the
+// 'Bookmarks' file. This is mostly useful to verify server state.
+// DISABLED because it should be; we use this as a utility more than a test.
+IN_PROC_BROWSER_TEST_F(SingleClientLiveBookmarksSyncTest, DISABLED_GetUpdates) {
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ BlockUntilLoaded(browser()->profile()->GetBookmarkModel());
+ EXPECT_TRUE(client()->ServiceIsPushingChanges());
+ ProfileSyncService::Status status(service()->QueryDetailedSyncStatus());
+ EXPECT_EQ(status.summary, ProfileSyncService::Status::READY);
+ EXPECT_EQ(status.unsynced_count, 0);
+}
+
+#endif // CHROME_PERSONALIZATION
diff --git a/chrome/test/live_sync/two_client_live_bookmarks_sync_test.cc b/chrome/test/live_sync/two_client_live_bookmarks_sync_test.cc
new file mode 100644
index 0000000..f9c8454
--- /dev/null
+++ b/chrome/test/live_sync/two_client_live_bookmarks_sync_test.cc
@@ -0,0 +1,1116 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef CHROME_PERSONALIZATION
+
+#include <stdlib.h>
+
+#include "base/string16.h"
+#include "base/rand_util.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_utils.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/test/live_sync/bookmark_model_verifier.h"
+#include "chrome/test/live_sync/profile_sync_service_test_harness.h"
+#include "chrome/test/live_sync/live_bookmarks_sync_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TwoClientLiveBookmarksSyncTest : public LiveBookmarksSyncTest {
+ public:
+ TwoClientLiveBookmarksSyncTest() {
+ // Set the initial timeout value to 5 min.
+ InProcessBrowserTest::SetInitialTimeoutInMS(300000);
+ }
+ virtual ~TwoClientLiveBookmarksSyncTest() {}
+ bool SetupSync() {
+ profile2_.reset(MakeProfile(L"clienttwo"));
+ client1_.reset(new ProfileSyncServiceTestHarness(
+ browser()->profile(), username_, password_));
+ client2_.reset(new ProfileSyncServiceTestHarness(
+ profile2_.get(), username_, password_));
+ return client1_->SetupSync() && client2_->SetupSync();
+ }
+
+ ProfileSyncServiceTestHarness* client1() { return client1_.get(); }
+ ProfileSyncServiceTestHarness* client2() { return client2_.get(); }
+ Profile* profile1() { return browser()->profile(); }
+ Profile* profile2() { return profile2_.get(); }
+
+ void Cleanup() {
+ client2_.reset();
+ profile2_.reset();
+ }
+
+ private:
+ scoped_ptr<Profile> profile2_;
+ scoped_ptr<ProfileSyncServiceTestHarness> client1_;
+ scoped_ptr<ProfileSyncServiceTestHarness> client2_;
+
+ DISALLOW_COPY_AND_ASSIGN(TwoClientLiveBookmarksSyncTest);
+};
+
+// Test case Naming Convention:
+// SC/MC - SingleClient / MultiClient.
+// Suffix Number - Indicates test scribe testcase ID.
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest, Sanity) {
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+ const BookmarkNode* bbn_two = model_two->GetBookmarkBarNode();
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ GURL google_url("http://www.google.com");
+ // Start adding some bookmarks to each model. The scope is to enforce that
+ // the BookmarkNode*'s are not used after they may be invalidated by sync
+ // operations that alter the models.
+ {
+ const BookmarkNode* google_one = verifier->AddURL(model_one, bbn_one, 0,
+ L"Google", google_url);
+
+ // To make this test deterministic, we wait here so there is no race to
+ // decide which bookmark actually gets position 0.
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ const BookmarkNode* yahoo_two = verifier->AddURL(model_two, bbn_two, 0,
+ L"Yahoo", GURL("http://www.yahoo.com"));
+ }
+ ASSERT_TRUE(client2()->AwaitMutualSyncCycleCompletion(client1()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ const BookmarkNode* new_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 2, L"New Folder");
+ verifier->Move(model_one, GetByUniqueURL(model_one, google_url),
+ new_folder_one, 0);
+ verifier->SetTitle(model_one, bbn_one->GetChild(0), L"Yahoo!!");
+ const BookmarkNode* cnn_one = verifier->AddURL(model_one,
+ bbn_one, 1, L"CNN", GURL("http://www.cnn.com"));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ const BookmarkNode* facebook_two = verifier->AddURL(model_two,
+ bbn_two, 0, L"Facebook", GURL("http://www.facebook.com"));
+ }
+
+ // AwaitMutualSyncCycleCompletion blocks the calling object before the
+ // argument, so because we have made changes from client2 here we need to swap
+ // the calling order.
+ ASSERT_TRUE(client2()->AwaitMutualSyncCycleCompletion(client1()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ verifier->SortChildren(model_two, bbn_two);
+
+ ASSERT_TRUE(client2()->AwaitMutualSyncCycleCompletion(client1()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ // Do something crazy and modify the same item from both clients!!
+ const BookmarkNode* google_one = GetByUniqueURL(model_one, google_url);
+ const BookmarkNode* google_two = GetByUniqueURL(model_two, google_url);
+ model_one->SetTitle(google_one, L"Google++");
+ model_two->SetTitle(google_two, L"Google--");
+ }
+ // The extra wait here is because both clients generated changes, and the
+ // first client reaches a happy state before the second client gets a chance
+ // to push, so we explicitly double check. This shouldn't be necessary once
+ // we have an easy way to verify the head version on each client.
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletionWithConflict(client2()));
+ BookmarkModelVerifier::ExpectModelsMatch(model_one, model_two);
+
+ Cleanup();
+}
+
+// TODO(timsteele): There are really two tests here, one case where conflict
+// resolution causes the URL to be overwritten, and one where we see duplicate
+// bookmarks created due to the Remove/Add semantic for "Edit URL" and the race
+// between the local edit and server edit. The latter is bug 1956259 and is
+// still under investigation, I don't have enough info to write two separate
+// tests yet.
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SimultaneousURLChanges) {
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+ const BookmarkNode* bbn_two = model_two->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ GURL initial_url(L"http://www.google.com");
+ GURL second_url(L"http://www.google.com/abc");
+ GURL third_url(L"http://www.google.com/def");
+ std::wstring title = L"Google";
+ {
+ const BookmarkNode* google = verifier->AddURL(model_one, bbn_one, 0,
+ title, initial_url);
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+
+ {
+ const BookmarkNode* google_one = GetByUniqueURL(model_one, initial_url);
+ const BookmarkNode* google_two = GetByUniqueURL(model_two, initial_url);
+ bookmark_utils::ApplyEditsWithNoGroupChange(model_one, bbn_one, google_one,
+ title, second_url, NULL);
+ bookmark_utils::ApplyEditsWithNoGroupChange(model_two, bbn_two, google_two,
+ title, third_url, NULL);
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletionWithConflict(client2()));
+ BookmarkModelVerifier::ExpectModelsMatch(model_one, model_two);
+
+ {
+ const BookmarkNode* google_one = bbn_one->GetChild(0);
+ model_one->SetTitle(google_one, L"Google1");
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ BookmarkModelVerifier::ExpectModelsMatch(model_one, model_two);
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_CleanAccount_AddFirstFolder_370558) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ // Let's add first bookmark folder to client1
+ const BookmarkNode* new_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 0, L"TestFolder");
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_CleanAccount_AddFirstBMWithoutFavicon_370559) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's add first bookmark(without favicon)
+ {
+ const BookmarkNode* nofavicon_bm = verifier->AddURL(model_one, bbn_one, 0,
+ L"TestBookmark", GURL("http://www.nofaviconurl.com"));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_CleanAccount_AddNonHTTPBMs_370560) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's add few non-http bookmarks(without favicon)
+ {
+ const BookmarkNode* ftp_bm = verifier->AddURL(model_one, bbn_one, 0,
+ L"FTPBookmark", GURL("ftp://ftp.testbookmark.com"));
+ const BookmarkNode* file_bm = verifier->AddURL(model_one, bbn_one, 0,
+ L"FileBookmark", GURL("file:///"));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_CleanAccount_AddFirstBM_UnderFolder_370561) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ // Let's add first bookmark folder to client1
+ const BookmarkNode* new_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 0, L"BM TestFolder");
+ // Add first bookmark to newly created folder
+ const BookmarkNode* test_bm1 = verifier->AddURL(
+ model_one, new_folder_one, 0,
+ L"BM Test", GURL("http://www.bmtest.com"));
+ }
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_SingleClient_RenameBMName_371817) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Add first bookmark
+ const BookmarkNode* test_bm1 = verifier->AddURL(
+ model_one, bbn_one, 0, L"Test BM", GURL("http://www.bmtest.com"));
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ // Rename recently added BM
+ verifier->SetTitle(model_one, test_bm1, L"New Test BM");
+ }
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_RenameBMFolder_371824) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's add first bookmark folder to client1
+ const BookmarkNode* new_folder_one = verifier->AddGroup(model_one, bbn_one, 0,
+ L"TestBMFolder");
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Rename recently added Bookmark folder
+ verifier->SetTitle(model_one, new_folder_one, L"New TestBMFolder");
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_DeleteBM_EmptyAccountAfterThisDelete_371832) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's add first bookmark(without favicon)
+ {
+ const BookmarkNode* nofavicon_bm = verifier->AddURL(model_one, bbn_one, 0,
+ L"TestBookmark", GURL("http://www.nofaviconurl.com"));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ // Delete this newly created bookmark
+ verifier->Remove(model_one, bbn_one, 0);
+ }
+ client1()->AwaitMutualSyncCycleCompletionWithConflict(client2());
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_DeleteBM_NonEmptyAccountAfterThisDelete_371833) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add some bookmarks(without favicon)
+ for (int index = 0; index < 20; index++) {
+ string16 title(L"TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm = verifier->AddURL(
+ model_one, bbn_one, index,
+ title, GURL(url));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ // Delete this newly created bookmark
+ verifier->Remove(model_one, bbn_one, 0);
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_RepositioningBM_ab_To_ba_371931) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ const BookmarkNode* bm_a = verifier->AddURL(
+ model_one, bbn_one, 0, L"Bookmark A",
+ GURL("http://www.nofaviconurla.com"));
+ const BookmarkNode* bm_b = verifier->AddURL(
+ model_one, bbn_one, 1, L"Bookmark B",
+ GURL("http://www.nofaviconurlb.com"));
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ // Move bm_a to new position
+ verifier->Move(model_one, bm_a, bbn_one, 2);
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_Repositioning_NonEmptyBMFolder_ab_To_ba_372026) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ const BookmarkNode* bm_folder_a =
+ verifier->AddGroup(model_one, bbn_one, 0, L"TestBMFolderA");
+ const BookmarkNode* bm_folder_b =
+ verifier->AddGroup(model_one, bbn_one, 1, L"TestBMFolderB");
+ for (int index = 0; index < 10; index++) {
+ int random_int = base::RandInt(1, 100);
+ // To create randomness in order, 60% of time add bookmarks
+ if (random_int > 40) {
+ string16 title(L"Folder A - ChildTestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm =
+ verifier->AddURL(model_one, bm_folder_a, index, title, GURL(url));
+ } else {
+ // Remaining % of time - Add Bookmark folders
+ string16 title(L"Folder A - ChildTestBMFolder");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ const BookmarkNode* bm_folder =
+ verifier->AddGroup(model_one, bm_folder_a, index, title);
+ }
+ }
+
+ for (int index = 0; index < 10; index++) {
+ int random_int = base::RandInt(1, 100);
+ // To create randomness in order, 60% of time add bookmarks
+ if (random_int > 40) {
+ string16 title(L"Folder B - ChildTestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm =
+ verifier->AddURL(model_one, bm_folder_b, index, title, GURL(url));
+ } else {
+ // Remaining % of time - Add Bookmark folders
+ string16 title(L"Folder B - ChildTestBMFolder");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ const BookmarkNode* bm_folder =
+ verifier->AddGroup(model_one, bm_folder_b, index, title);
+ }
+ }
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ {
+ // Move bm_a to new position
+ verifier->Move(model_one, bm_folder_a, bbn_one, 2);
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_CleanAccount_AddSeveralBMs_UnderBMBarAndOtherBM_370562) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+ const BookmarkNode* other_bm_one = model_one->other_node();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add some bookmarks(without favicon)
+ for (int index = 0; index < 20; index++) {
+ string16 title(L"TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm =
+ verifier->AddURL(model_one, bbn_one, index, title, GURL(url));
+ }
+ for (int index = 0; index < 10; index++) {
+ string16 title(L"TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm =
+ verifier->AddURL(model_one, other_bm_one, index, title, GURL(url));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_CleanAccount_AddSeveralBMs_And_SeveralFolders_370563) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+ const BookmarkNode* other_bm_one = model_one->other_node();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add some bookmarks(without favicon)
+ for (int index = 0; index < 15; index++) {
+ int random_int = base::RandInt(1, 100);
+ // To create randomness in order, 40% of time add bookmarks
+ if (random_int > 60) {
+ string16 title(L"BB - TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm =
+ verifier->AddURL(model_one, bbn_one, index, title, GURL(url));
+ } else {
+ // Remaining % of time - Add Bookmark folders
+ string16 title(L"BB - TestBMFolder");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ const BookmarkNode* bm_folder = verifier->AddGroup(model_one, bbn_one,
+ index, title);
+ int random_int2 = base::RandInt(1, 100);
+ // 60% of time we will add bookmarks to added folder
+ if (random_int2 > 40) {
+ for (int index = 0; index < 20; index++) {
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ string16 child_title(title);
+ child_title.append(L" - ChildTestBM");
+ child_title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm = verifier->AddURL(model_one,
+ bm_folder, index, child_title, GURL(url));
+ }
+ }
+ }
+ }
+ LOG(INFO) << "Adding several bookmarks under other bookmarks";
+ for (int index = 0; index < 10; index++) {
+ string16 title(L"Other - TestBookmark");
+ string16 url(L"http://www.nofaviconurl-other");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm =
+ verifier->AddURL(model_one, other_bm_one, index, title, GURL(url));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_RenameBMURL_371822) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add first bookmark(without favicon)
+ const BookmarkNode* nofavicon_bm =
+ verifier->AddURL(model_one, bbn_one, 0, L"Google",
+ GURL("http://www.google.com"));
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's rename/change URL
+ verifier->SetURL(model_one, nofavicon_bm, GURL("http://www.cnn.com"));
+ // Wait for changes to sync and then verify
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_RenameEmptyBMFolder_371825) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's add first bookmark folder to client1
+ const BookmarkNode* bm_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 0, L"TestFolder");
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's rename newly added bookmark folder
+ verifier->SetTitle(model_one, bm_folder_one, L"New TestFolder");
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_DeleteFirstBM_Under_BMFolder_NonEmptyFolderAfterDelete_371835) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add first bookmark folder to client1
+ const BookmarkNode* bm_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 0, L"TestFolder");
+ // Let's add some bookmarks(without favicon) to this folder
+ for (int index = 0; index < 10; index++) {
+ string16 title(L"TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm =
+ verifier->AddURL(model_one, bm_folder_one, index, title, GURL(url));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ // Delete first bookmark under this folder
+ verifier->Remove(model_one, bm_folder_one, 0);
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ Cleanup();
+}
+
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_DeleteLastBM_Under_BMFolder_NonEmptyFolderAfterDelete_371836) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add first bookmark folder to client1
+ const BookmarkNode* bm_folder_one = verifier->AddGroup(model_one, bbn_one,
+ 0, L"TestFolder");
+ // Let's add some bookmarks(without favicon) to this folder
+ for (int index = 0; index < 10; index++) {
+ string16 title(L"TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm = verifier->AddURL(
+ model_one, bm_folder_one,
+ index, title, GURL(url));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ // Delete last bookmark under this folder
+ verifier->Remove(model_one, bm_folder_one,
+ (bm_folder_one->GetChildCount() - 1));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ Cleanup();
+}
+
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_DelMiddleBM_Under_BMFold_NonEmptyFoldAfterDel_371856) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add first bookmark folder to client1
+ const BookmarkNode* bm_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 0, L"TestFolder");
+ // Let's add some bookmarks(without favicon) to this folder
+ for (int index = 0; index < 10; index++) {
+ string16 title(L"TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm =
+ verifier->AddURL(model_one, bm_folder_one, index, title, GURL(url));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ {
+ // Delete middle bookmark under this folder
+ verifier->Remove(model_one, bm_folder_one, 4);
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ Cleanup();
+}
+
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_DeleteBMs_Under_BMFolder_EmptyFolderAfterDelete_371857) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add first bookmark folder to client1
+ const BookmarkNode* bm_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 0, L"TestFolder");
+ // Let's add some bookmarks(without favicon) to this folder
+ for (int index = 0; index < 10; index++) {
+ string16 title(L"TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm =
+ verifier->AddURL(model_one, bm_folder_one, index, title, GURL(url));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ int child_count = bm_folder_one->GetChildCount();
+ // Let's delete all the bookmarks added under this new folder
+ for (int index = 0; index < child_count; index++) {
+ verifier->Remove(model_one, bm_folder_one, 0);
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ }
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_DeleteEmptyBMFolder_EmptyAccountAfterDelete_371858) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's add first bookmark folder to client1
+ const BookmarkNode* bm_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 0, L"TestFolder");
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's delete this empty bookmark folder
+ verifier->Remove(model_one, bbn_one, 0);
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ Cleanup();
+}
+
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_DeleteEmptyBMFolder_NonEmptyAccountAfterDelete_371869) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+ const BookmarkNode* other_bm_one = model_one->other_node();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add first bookmark folder to client1
+ const BookmarkNode* bm_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 0, L"TestFolder");
+ // Let's add some bookmarks(without favicon)
+ for (int index = 1; index < 15; index++) {
+ int random_int = base::RandInt(1, 100);
+ // To create randomness in order, 40% of time add bookmarks
+ if (random_int > 60) {
+ string16 title(L"BB - TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm = verifier->AddURL(model_one, bbn_one,
+ index, title, GURL(url));
+ } else {
+ // Remaining % of time - Add Bookmark folders
+ string16 title(L"BB - TestBMFolder");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ const BookmarkNode* bm_folder = verifier->AddGroup(model_one, bbn_one,
+ index, title);
+ }
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's delete the first empty bookmark folder
+ verifier->Remove(model_one, bbn_one, 0);
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_DelBMFoldWithBMsAndBMFolds_NonEmptyACAfterDelete_371880) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+ const BookmarkNode* other_bm_one = model_one->other_node();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add bookmark and bookmark folder to client1
+ const BookmarkNode* yahoo = verifier->AddURL(model_one, bbn_one, 0,
+ L"Yahoo", GURL("http://www.yahoo.com"));
+ const BookmarkNode* bm_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 1, L"TestFolder");
+ // Let's add some bookmarks(without favicon) and folders to
+ // bookmark bar
+ for (int index = 2; index < 10; index++) {
+ int random_int = base::RandInt(1, 100);
+ // To create randomness in order, 40% of time add bookmarks
+ if (random_int > 60) {
+ string16 title(L"BB - TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm = verifier->AddURL(model_one, bbn_one,
+ index, title, GURL(url));
+ } else {
+ // Remaining % of time - Add Bookmark folders
+ string16 title(L"BB - TestBMFolder");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ const BookmarkNode* bm_folder = verifier->AddGroup(model_one, bbn_one,
+ index, title);
+ }
+ }
+
+ // Let's add some bookmarks(without favicon) and folders to
+ // bm_folder_one ('TestFolder')
+ for (int index = 0; index < 10; index++) {
+ int random_int = base::RandInt(1, 100);
+ // To create randomness in order, 40% of time add bookmarks
+ if (random_int > 60) {
+ string16 title(L"Level2 - TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm = verifier->AddURL(model_one,
+ bm_folder_one, index, title, GURL(url));
+ } else {
+ // Remaining % of time - Add Bookmark folders
+ string16 title(L"Level2 - TestBMFolder");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ const BookmarkNode* l2_bm_folder = verifier->AddGroup(model_one,
+ bm_folder_one, index, title);
+ int random_int2 = base::RandInt(1, 100);
+ // 70% of time - Let's add more levels of bookmarks and folders to
+ // l2_bm_folder
+ if (random_int2 > 30) {
+ for (int index2 = 0; index2 < 10; index2++) {
+ int random_int3 = base::RandInt(1, 100);
+ // To create randomness in order, 40% of time add bookmarks
+ if (random_int3 > 60) {
+ string16 title(L"Level3 - TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index2);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm = verifier->AddURL(model_one,
+ l2_bm_folder, index2, title, GURL(url));
+ } else {
+ // Remaining % of time - Add Bookmark folders
+ string16 title(L"Level3 - TestBMFolder");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ const BookmarkNode* l3_bm_folder =
+ verifier->AddGroup(model_one, l2_bm_folder, index2, title);
+ }
+ } // end inner for loop
+ }
+ }
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's delete the bookmark folder (bm_folder_one)
+ verifier->Remove(model_one, bm_folder_one, 0);
+
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_Moving_BMsFromBookmarkBar_To_BMFolder_371954) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+ const BookmarkNode* other_bm_one = model_one->other_node();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add bookmark and bookmark folder to client1
+ const BookmarkNode* yahoo = verifier->AddURL(model_one, bbn_one, 0,
+ L"Yahoo", GURL("http://www.yahoo.com"));
+ const BookmarkNode* bm_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 1, L"TestFolder");
+ // Let's add some bookmarks(without favicon) to bookmark bar
+ for (int index = 2; index < 10; index++) {
+ int random_int = base::RandInt(1, 100);
+ string16 title(L"BB - TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm = verifier->AddURL(model_one, bbn_one,
+ index, title, GURL(url));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's move bookmarks from bookmark bar to BMfolder (bm_folder_one)
+ int child_count_to_move = bbn_one->GetChildCount() - 2;
+ for (int index = 0; index < child_count_to_move; index++) {
+ verifier->Move(model_one, bbn_one->GetChild(2),
+ bm_folder_one, index);
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ }
+ Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(TwoClientLiveBookmarksSyncTest,
+ SC_Moving_BMsFromBMFolder_To_BookmarkBar_371957) {
+
+ ASSERT_TRUE(SetupSync()) << "Failed to SetupSync";
+ scoped_ptr<BookmarkModelVerifier> verifier(BookmarkModelVerifier::Create());
+ BookmarkModel* model_one = profile1()->GetBookmarkModel();
+ BookmarkModel* model_two = profile2()->GetBookmarkModel();
+ const BookmarkNode* bbn_one = model_one->GetBookmarkBarNode();
+ const BookmarkNode* other_bm_one = model_one->other_node();
+
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ // Let's add bookmark and bookmark folder to client1
+ const BookmarkNode* yahoo = verifier->AddURL(model_one, bbn_one, 0,
+ L"Yahoo", GURL("http://www.yahoo.com"));
+ const BookmarkNode* bm_folder_one =
+ verifier->AddGroup(model_one, bbn_one, 1, L"TestFolder");
+ // Let's add some bookmarks(without favicon) to bm_folder_one
+ for (int index = 0; index < 10; index++) {
+ int random_int = base::RandInt(1, 100);
+ string16 title(L"BB - TestBookmark");
+ string16 url(L"http://www.nofaviconurl");
+ string16 index_str = IntToString16(index);
+ title.append(index_str);
+ url.append(index_str);
+ url.append(L".com");
+ const BookmarkNode* nofavicon_bm = verifier->AddURL(model_one,
+ bm_folder_one, index, title, GURL(url));
+ }
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+
+ // Let's move bookmarks from BMfolder(bm_folder_one) to bookmark bar
+ int child_count_to_move = bm_folder_one->GetChildCount();
+ for (int index = 0; index < child_count_to_move; index++) {
+ verifier->Move(model_one, bm_folder_one->GetChild(0),
+ bbn_one, bbn_one->GetChildCount());
+ ASSERT_TRUE(client1()->AwaitMutualSyncCycleCompletion(client2()));
+ verifier->ExpectMatch(model_one);
+ verifier->ExpectMatch(model_two);
+ }
+ Cleanup();
+}
+
+#endif // CHROME_PERSONALIZATION