summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync/profile_sync_service_unittest.cc
diff options
context:
space:
mode:
authorKristian Monsen <kristianm@google.com>2011-05-31 20:30:28 +0100
committerKristian Monsen <kristianm@google.com>2011-06-14 20:31:41 -0700
commit72a454cd3513ac24fbdd0e0cb9ad70b86a99b801 (patch)
tree382278a54ce7a744d62fa510a9a80688cc12434b /chrome/browser/sync/profile_sync_service_unittest.cc
parentc4becdd46e31d261b930e4b5a539cbc1d45c23a6 (diff)
downloadexternal_chromium-72a454cd3513ac24fbdd0e0cb9ad70b86a99b801.zip
external_chromium-72a454cd3513ac24fbdd0e0cb9ad70b86a99b801.tar.gz
external_chromium-72a454cd3513ac24fbdd0e0cb9ad70b86a99b801.tar.bz2
Merge Chromium.org at r11.0.672.0: Initial merge by git.
Change-Id: I8b4aaf611a2a405fe3fe10e8a94ea7658645c192
Diffstat (limited to 'chrome/browser/sync/profile_sync_service_unittest.cc')
-rw-r--r--chrome/browser/sync/profile_sync_service_unittest.cc310
1 files changed, 280 insertions, 30 deletions
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc
index 74cfc24..04fc316 100644
--- a/chrome/browser/sync/profile_sync_service_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_unittest.cc
@@ -13,11 +13,13 @@
#include "base/string_util.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
+#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync/abstract_profile_sync_service_test.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/bookmark_change_processor.h"
@@ -27,11 +29,12 @@
#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/glue/sync_backend_host_mock.h"
+#include "chrome/browser/sync/js_arg_list.h"
+#include "chrome/browser/sync/js_test_util.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_factory_mock.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
-#include "chrome/common/chrome_switches.h"
#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
@@ -44,27 +47,99 @@ using browser_sync::BookmarkChangeProcessor;
using browser_sync::BookmarkModelAssociator;
using browser_sync::ChangeProcessor;
using browser_sync::DataTypeController;
+using browser_sync::HasArgs;
+using browser_sync::JsArgList;
+using browser_sync::MockJsEventHandler;
using browser_sync::ModelAssociator;
using browser_sync::SyncBackendHost;
using browser_sync::SyncBackendHostMock;
using browser_sync::UnrecoverableErrorHandler;
using testing::_;
+using testing::AtMost;
using testing::Return;
+using testing::StrictMock;
using testing::WithArg;
using testing::Invoke;
+// TODO(akalin): Bookmark-specific tests should be moved into their
+// own file.
class TestBookmarkModelAssociator : public BookmarkModelAssociator {
public:
- TestBookmarkModelAssociator(ProfileSyncService* service,
+ TestBookmarkModelAssociator(
+ TestProfileSyncService* service,
UnrecoverableErrorHandler* persist_ids_error_handler)
: BookmarkModelAssociator(service, persist_ids_error_handler),
- helper_(new TestModelAssociatorHelper()) {
- }
+ id_factory_(service->id_factory()) {}
+
+ // TODO(akalin): This logic lazily creates any tagged node that is
+ // requested. A better way would be to have utility functions to
+ // create sync nodes from some bookmark structure and to use that.
virtual bool GetSyncIdForTaggedNode(const std::string& tag, int64* sync_id) {
- return helper_->GetSyncIdForTaggedNode(this, tag, sync_id);
+ std::wstring tag_wide;
+ if (!UTF8ToWide(tag.c_str(), tag.length(), &tag_wide)) {
+ NOTREACHED() << "Unable to convert UTF8 to wide for string: " << tag;
+ return false;
+ }
+
+ bool root_exists = false;
+ syncable::ModelType type = model_type();
+ {
+ sync_api::WriteTransaction trans(sync_service()->GetUserShare());
+ sync_api::ReadNode uber_root(&trans);
+ uber_root.InitByRootLookup();
+
+ sync_api::ReadNode root(&trans);
+ root_exists = root.InitByTagLookup(
+ ProfileSyncServiceTestHelper::GetTagForType(type));
+ }
+
+ if (!root_exists) {
+ bool created = ProfileSyncServiceTestHelper::CreateRoot(
+ type,
+ sync_service()->GetUserShare(),
+ id_factory_);
+ if (!created)
+ return false;
+ }
+
+ sync_api::WriteTransaction trans(sync_service()->GetUserShare());
+ sync_api::ReadNode root(&trans);
+ EXPECT_TRUE(root.InitByTagLookup(
+ ProfileSyncServiceTestHelper::GetTagForType(type)));
+
+ // First, try to find a node with the title among the root's children.
+ // This will be the case if we are testing model persistence, and
+ // are reloading a sync repository created earlier in the test.
+ int64 last_child_id = sync_api::kInvalidId;
+ for (int64 id = root.GetFirstChildId(); id != sync_api::kInvalidId; /***/) {
+ sync_api::ReadNode child(&trans);
+ child.InitByIdLookup(id);
+ last_child_id = id;
+ if (tag_wide == child.GetTitle()) {
+ *sync_id = id;
+ return true;
+ }
+ id = child.GetSuccessorId();
+ }
+
+ sync_api::ReadNode predecessor_node(&trans);
+ sync_api::ReadNode* predecessor = NULL;
+ if (last_child_id != sync_api::kInvalidId) {
+ predecessor_node.InitByIdLookup(last_child_id);
+ predecessor = &predecessor_node;
+ }
+ sync_api::WriteNode node(&trans);
+ // Create new fake tagged nodes at the end of the ordering.
+ node.InitByCreation(type, root, predecessor);
+ node.SetIsFolder(true);
+ node.SetTitle(tag_wide);
+ node.SetExternalId(0);
+ *sync_id = node.GetId();
+ return true;
}
+
private:
- scoped_ptr<TestModelAssociatorHelper> helper_;
+ browser_sync::TestIdFactory* id_factory_;
};
// FakeServerChange constructs a list of sync_api::ChangeRecords while modifying
@@ -244,14 +319,16 @@ class ProfileSyncServiceTest : public testing::Test {
}
void StartSyncService() {
- StartSyncServiceAndSetInitialSyncEnded(true);
+ StartSyncServiceAndSetInitialSyncEnded(true, true);
}
- void StartSyncServiceAndSetInitialSyncEnded(bool set_initial_sync_ended) {
+ void StartSyncServiceAndSetInitialSyncEnded(
+ bool set_initial_sync_ended,
+ bool issue_auth_token) {
if (!service_.get()) {
// Set bootstrap to true and it will provide a logged in user for test
service_.reset(new TestProfileSyncService(&factory_,
profile_.get(),
- "test", false, NULL));
+ "test", true, NULL));
if (!set_initial_sync_ended)
service_->dont_set_initial_sync_ended_on_init();
@@ -271,10 +348,11 @@ class ProfileSyncServiceTest : public testing::Test {
profile_.get(),
service_.get()));
- profile_->GetTokenService()->IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "token");
+ if (issue_auth_token) {
+ profile_->GetTokenService()->IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "token");
+ }
service_->Initialize();
- MessageLoop::current()->Run();
}
}
@@ -343,7 +421,7 @@ class ProfileSyncServiceTest : public testing::Test {
}
void ExpectSyncerNodeMatching(const BookmarkNode* bnode) {
- sync_api::ReadTransaction trans(service_->backend_->GetUserShareHandle());
+ sync_api::ReadTransaction trans(service_->GetUserShare());
ExpectSyncerNodeMatching(&trans, bnode);
}
@@ -421,7 +499,7 @@ class ProfileSyncServiceTest : public testing::Test {
}
void ExpectModelMatch() {
- sync_api::ReadTransaction trans(service_->backend_->GetUserShareHandle());
+ sync_api::ReadTransaction trans(service_->GetUserShare());
ExpectModelMatch(&trans);
}
@@ -434,8 +512,6 @@ class ProfileSyncServiceTest : public testing::Test {
model_->GetBookmarkBarNode()->id());
}
- SyncBackendHost* backend() { return service_->backend_.get(); }
-
// This serves as the "UI loop" on which the ProfileSyncService lives and
// operates. It is needed because the SyncBackend can post tasks back to
// the service, meaning it can't be null. It doesn't have to be running,
@@ -549,7 +625,7 @@ TEST_F(ProfileSyncServiceTest, ServerChangeProcessing) {
LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
StartSyncService();
- sync_api::WriteTransaction trans(backend()->GetUserShareHandle());
+ sync_api::WriteTransaction trans(service_->GetUserShare());
FakeServerChange adds(&trans);
int64 f1 = adds.AddFolder(L"Server Folder B", bookmark_bar_id(), 0);
@@ -638,7 +714,7 @@ TEST_F(ProfileSyncServiceTest, ServerChangeRequiringFosterParent) {
LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
StartSyncService();
- sync_api::WriteTransaction trans(backend()->GetUserShareHandle());
+ sync_api::WriteTransaction trans(service_->GetUserShare());
// Stress the immediate children of other_node because that's where
// ApplyModelChanges puts a temporary foster parent node.
@@ -647,11 +723,11 @@ TEST_F(ProfileSyncServiceTest, ServerChangeRequiringFosterParent) {
int64 f0 = other_bookmarks_id(); // + other_node
int64 f1 = adds.AddFolder(L"f1", f0, 0); // + f1
int64 f2 = adds.AddFolder(L"f2", f1, 0); // + f2
- int64 u3 = adds.AddURL( L"u3", url, f2, 0); // + u3
- int64 u4 = adds.AddURL( L"u4", url, f2, u3); // + u4
- int64 u5 = adds.AddURL( L"u5", url, f1, f2); // + u5
+ int64 u3 = adds.AddURL( L"u3", url, f2, 0); // + u3 NOLINT
+ int64 u4 = adds.AddURL( L"u4", url, f2, u3); // + u4 NOLINT
+ int64 u5 = adds.AddURL( L"u5", url, f1, f2); // + u5 NOLINT
int64 f6 = adds.AddFolder(L"f6", f1, u5); // + f6
- int64 u7 = adds.AddURL( L"u7", url, f0, f1); // + u7
+ int64 u7 = adds.AddURL( L"u7", url, f0, f1); // + u7 NOLINT
vector<sync_api::SyncManager::ChangeRecord>::const_iterator it;
// The bookmark model shouldn't yet have seen any of the nodes of |adds|.
@@ -687,7 +763,7 @@ TEST_F(ProfileSyncServiceTest, ServerChangeWithNonCanonicalURL) {
StartSyncService();
{
- sync_api::WriteTransaction trans(backend()->GetUserShareHandle());
+ sync_api::WriteTransaction trans(service_->GetUserShare());
FakeServerChange adds(&trans);
std::string url("http://dev.chromium.org");
@@ -718,7 +794,7 @@ TEST_F(ProfileSyncServiceTest, DISABLED_ServerChangeWithInvalidURL) {
int child_count = 0;
{
- sync_api::WriteTransaction trans(backend()->GetUserShareHandle());
+ sync_api::WriteTransaction trans(service_->GetUserShare());
FakeServerChange adds(&trans);
std::string url("x");
@@ -835,7 +911,7 @@ TEST_F(ProfileSyncServiceTest, UnrecoverableErrorSuspendsService) {
// updating the ProfileSyncService state. This should introduce
// inconsistency between the two models.
{
- sync_api::WriteTransaction trans(service_->backend_->GetUserShareHandle());
+ sync_api::WriteTransaction trans(service_->GetUserShare());
sync_api::WriteNode sync_node(&trans);
EXPECT_TRUE(associator()->InitSyncNodeFromChromeId(node->id(),
&sync_node));
@@ -883,6 +959,180 @@ TEST_F(ProfileSyncServiceTest, MergeDuplicates) {
ExpectModelMatch();
}
+TEST_F(ProfileSyncServiceTest, JsFrontendHandlersBasic) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSyncService();
+
+ StrictMock<MockJsEventHandler> event_handler;
+
+ browser_sync::SyncBackendHostForProfileSyncTest* test_backend =
+ service_->GetBackendForTest();
+
+ EXPECT_TRUE(service_->sync_initialized());
+ ASSERT_TRUE(test_backend != NULL);
+ ASSERT_TRUE(test_backend->GetJsBackend() != NULL);
+ EXPECT_EQ(NULL, test_backend->GetJsBackend()->GetParentJsEventRouter());
+
+ browser_sync::JsFrontend* js_backend = service_->GetJsFrontend();
+ js_backend->AddHandler(&event_handler);
+ ASSERT_TRUE(test_backend->GetJsBackend() != NULL);
+ EXPECT_TRUE(test_backend->GetJsBackend()->GetParentJsEventRouter() != NULL);
+
+ js_backend->RemoveHandler(&event_handler);
+ EXPECT_EQ(NULL, test_backend->GetJsBackend()->GetParentJsEventRouter());
+}
+
+TEST_F(ProfileSyncServiceTest,
+ JsFrontendHandlersDelayedBackendInitialization) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSyncServiceAndSetInitialSyncEnded(true, false);
+
+ StrictMock<MockJsEventHandler> event_handler;
+ EXPECT_CALL(event_handler,
+ HandleJsEvent("onSyncServiceStateChanged",
+ HasArgs(JsArgList()))).Times(3);
+ // For some reason, these two events don't fire on Linux.
+ EXPECT_CALL(event_handler, HandleJsEvent("onChangesApplied", _))
+ .Times(AtMost(1));
+ EXPECT_CALL(event_handler, HandleJsEvent("onChangesComplete", _))
+ .Times(AtMost(1));
+
+ EXPECT_EQ(NULL, service_->GetBackendForTest());
+ EXPECT_FALSE(service_->sync_initialized());
+
+ browser_sync::JsFrontend* js_backend = service_->GetJsFrontend();
+ js_backend->AddHandler(&event_handler);
+ // Since we're doing synchronous initialization, backend should be
+ // initialized by this call.
+ profile_->GetTokenService()->IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "token");
+
+ browser_sync::SyncBackendHostForProfileSyncTest* test_backend =
+ service_->GetBackendForTest();
+
+ EXPECT_TRUE(service_->sync_initialized());
+ ASSERT_TRUE(test_backend != NULL);
+ ASSERT_TRUE(test_backend->GetJsBackend() != NULL);
+ EXPECT_TRUE(test_backend->GetJsBackend()->GetParentJsEventRouter() != NULL);
+
+ js_backend->RemoveHandler(&event_handler);
+ EXPECT_EQ(NULL, test_backend->GetJsBackend()->GetParentJsEventRouter());
+}
+
+TEST_F(ProfileSyncServiceTest, JsFrontendProcessMessageBasic) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSyncService();
+
+ StrictMock<MockJsEventHandler> event_handler;
+
+ ListValue arg_list1;
+ arg_list1.Append(Value::CreateBooleanValue(true));
+ arg_list1.Append(Value::CreateIntegerValue(5));
+ JsArgList args1(arg_list1);
+ EXPECT_CALL(event_handler, HandleJsEvent("testMessage1", HasArgs(args1)));
+
+ ListValue arg_list2;
+ arg_list2.Append(Value::CreateStringValue("test"));
+ arg_list2.Append(arg_list1.DeepCopy());
+ JsArgList args2(arg_list2);
+ EXPECT_CALL(event_handler,
+ HandleJsEvent("delayTestMessage2", HasArgs(args2)));
+
+ ListValue arg_list3;
+ arg_list3.Append(arg_list1.DeepCopy());
+ arg_list3.Append(arg_list2.DeepCopy());
+ JsArgList args3(arg_list3);
+
+ browser_sync::JsFrontend* js_backend = service_->GetJsFrontend();
+
+ // Never replied to.
+ js_backend->ProcessMessage("notRepliedTo", args3, &event_handler);
+
+ // Replied to later.
+ js_backend->ProcessMessage("delayTestMessage2", args2, &event_handler);
+
+ js_backend->AddHandler(&event_handler);
+
+ // Replied to immediately.
+ js_backend->ProcessMessage("testMessage1", args1, &event_handler);
+
+ // Fires off reply for delayTestMessage2.
+ message_loop_.RunAllPending();
+
+ // Never replied to.
+ js_backend->ProcessMessage("delayNotRepliedTo", args3, &event_handler);
+
+ js_backend->RemoveHandler(&event_handler);
+
+ message_loop_.RunAllPending();
+
+ // Never replied to.
+ js_backend->ProcessMessage("notRepliedTo", args3, &event_handler);
+}
+
+TEST_F(ProfileSyncServiceTest,
+ JsFrontendProcessMessageBasicDelayedBackendInitialization) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSyncServiceAndSetInitialSyncEnded(true, false);
+
+ StrictMock<MockJsEventHandler> event_handler;
+ // For some reason, these two events don't fire on Linux.
+ EXPECT_CALL(event_handler, HandleJsEvent("onChangesApplied", _))
+ .Times(AtMost(1));
+ EXPECT_CALL(event_handler, HandleJsEvent("onChangesComplete", _))
+ .Times(AtMost(1));
+
+ ListValue arg_list1;
+ arg_list1.Append(Value::CreateBooleanValue(true));
+ arg_list1.Append(Value::CreateIntegerValue(5));
+ JsArgList args1(arg_list1);
+ EXPECT_CALL(event_handler, HandleJsEvent("testMessage1", HasArgs(args1)));
+
+ ListValue arg_list2;
+ arg_list2.Append(Value::CreateStringValue("test"));
+ arg_list2.Append(arg_list1.DeepCopy());
+ JsArgList args2(arg_list2);
+ EXPECT_CALL(event_handler, HandleJsEvent("testMessage2", HasArgs(args2)));
+
+ ListValue arg_list3;
+ arg_list3.Append(arg_list1.DeepCopy());
+ arg_list3.Append(arg_list2.DeepCopy());
+ JsArgList args3(arg_list3);
+ EXPECT_CALL(event_handler,
+ HandleJsEvent("delayTestMessage3", HasArgs(args3)));
+
+ const JsArgList kNoArgs;
+
+ EXPECT_CALL(event_handler, HandleJsEvent("onSyncServiceStateChanged",
+ HasArgs(kNoArgs))).Times(3);
+
+ browser_sync::JsFrontend* js_backend = service_->GetJsFrontend();
+
+ // We expect a reply for this message, even though its sent before
+ // |event_handler| is added as a handler.
+ js_backend->ProcessMessage("testMessage1", args1, &event_handler);
+
+ js_backend->AddHandler(&event_handler);
+
+ js_backend->ProcessMessage("testMessage2", args2, &event_handler);
+ js_backend->ProcessMessage("delayTestMessage3", args3, &event_handler);
+
+ // Fires testMessage1 and testMessage2.
+ profile_->GetTokenService()->IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "token");
+
+ // Fires delayTestMessage3.
+ message_loop_.RunAllPending();
+
+ js_backend->ProcessMessage("delayNotRepliedTo", kNoArgs, &event_handler);
+
+ js_backend->RemoveHandler(&event_handler);
+
+ message_loop_.RunAllPending();
+
+ js_backend->ProcessMessage("notRepliedTo", kNoArgs, &event_handler);
+}
+
struct TestData {
const wchar_t* title;
const char* url;
@@ -1324,7 +1574,8 @@ TEST_F(ProfileSyncServiceTestWithData, RecoverAfterDeletingSyncDataDirectory) {
WriteTestDataToBookmarkModel();
// While the service is running.
- FilePath sync_data_directory = backend()->sync_data_folder_path();
+ FilePath sync_data_directory =
+ service_->GetBackendForTest()->sync_data_folder_path();
// Simulate a normal shutdown for the sync service (don't disable it for
// the user, which would reset the preferences and delete the sync data
@@ -1336,7 +1587,7 @@ TEST_F(ProfileSyncServiceTestWithData, RecoverAfterDeletingSyncDataDirectory) {
// Restart the sync service. Don't fake out setting initial sync ended; lets
// make sure the system does in fact nudge and wait for this to happen.
- StartSyncServiceAndSetInitialSyncEnded(false);
+ StartSyncServiceAndSetInitialSyncEnded(false, true);
// Make sure we're back in sync. In real life, the user would need
// to reauthenticate before this happens, but in the test, authentication
@@ -1385,11 +1636,10 @@ TEST_F(ProfileSyncServiceTestWithData, TestStartupWithOldSyncData) {
profile_.get(),
service_.get()));
- service_->Initialize(); // will call disableForUser because sync setup
- // hasn't been completed.
+ service_->Initialize(); // will call disableForUser because sync setup
+ // hasn't been completed.
}
- ASSERT_FALSE(service_->backend());
ASSERT_FALSE(service_->HasSyncSetupCompleted());
// Create some tokens in the token service; the service will startup when