diff options
author | tim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-05 20:06:15 +0000 |
---|---|---|
committer | tim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-05 20:06:15 +0000 |
commit | e7ef7150c893a1ff2fe4197ce9d76ccb21001caa (patch) | |
tree | 639aa7b62035bbe557dff59d2c43c7a635d0f15c /chrome/test/live_sync | |
parent | cc4ba248e6714e6cf29bfa956d415977d78db246 (diff) | |
download | chromium_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.cc | 162 | ||||
-rw-r--r-- | chrome/test/live_sync/bookmark_model_verifier.h | 95 | ||||
-rw-r--r-- | chrome/test/live_sync/live_bookmarks_sync_test.cc | 80 | ||||
-rw-r--r-- | chrome/test/live_sync/live_bookmarks_sync_test.h | 69 | ||||
-rw-r--r-- | chrome/test/live_sync/profile_sync_service_test_harness.cc | 253 | ||||
-rw-r--r-- | chrome/test/live_sync/profile_sync_service_test_harness.h | 111 | ||||
-rw-r--r-- | chrome/test/live_sync/single_client_live_bookmarks_sync_unittest.cc | 157 | ||||
-rw-r--r-- | chrome/test/live_sync/two_client_live_bookmarks_sync_test.cc | 1116 |
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 |