Chromium Code Reviews| Index: chrome/browser/sync/internal_api/syncapi_unittest.cc |
| diff --git a/chrome/browser/sync/internal_api/syncapi_unittest.cc b/chrome/browser/sync/internal_api/syncapi_unittest.cc |
| index 6e3c296963837f23388ea3cb4d357eb60592b60a..66a71b9494619b107bf63193b5b5bbf9068e97ad 100644 |
| --- a/chrome/browser/sync/internal_api/syncapi_unittest.cc |
| +++ b/chrome/browser/sync/internal_api/syncapi_unittest.cc |
| @@ -73,9 +73,13 @@ using browser_sync::sessions::SyncSessionSnapshot; |
| using browser_sync::WeakHandle; |
| using content::BrowserThread; |
| using syncable::GetAllRealModelTypes; |
| +using syncable::IS_DEL; |
| +using syncable::IS_UNSYNCED; |
| using syncable::kEncryptedString; |
| using syncable::ModelType; |
| using syncable::ModelTypeSet; |
| +using syncable::NON_UNIQUE_NAME; |
| +using syncable::SPECIFICS; |
| using test::ExpectDictStringValue; |
| using testing::_; |
| using testing::AnyNumber; |
| @@ -179,6 +183,37 @@ int64 MakeServerNodeForType(UserShare* share, |
| return entry.Get(syncable::META_HANDLE); |
| } |
| +// Simulates creating a "synced" node as a child of the root datatype node. |
| +int64 MakeServerNode(UserShare* share, ModelType model_type, |
| + const std::string& client_tag, |
| + const std::string& hashed_tag, |
| + const sync_pb::EntitySpecifics& specifics) { |
| + syncable::ScopedDirLookup dir(share->dir_manager.get(), share->name); |
| + EXPECT_TRUE(dir.good()); |
| + syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir); |
| + syncable::Entry root_entry(&trans, syncable::GET_BY_SERVER_TAG, |
| + syncable::ModelTypeToRootTag(model_type)); |
| + EXPECT_TRUE(root_entry.good()); |
| + syncable::Id root_id = root_entry.Get(syncable::ID); |
| + syncable::Id node_id = syncable::Id::CreateFromServerId(client_tag); |
| + syncable::MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM, |
| + node_id); |
| + EXPECT_TRUE(entry.good()); |
| + entry.Put(syncable::BASE_VERSION, 1); |
| + entry.Put(syncable::SERVER_VERSION, 1); |
| + entry.Put(syncable::IS_UNAPPLIED_UPDATE, false); |
| + entry.Put(syncable::SERVER_PARENT_ID, root_id); |
| + entry.Put(syncable::PARENT_ID, root_id); |
| + entry.Put(syncable::SERVER_IS_DIR, false); |
| + entry.Put(syncable::IS_DIR, false); |
| + entry.Put(syncable::SERVER_SPECIFICS, specifics); |
| + entry.Put(syncable::NON_UNIQUE_NAME, client_tag); |
| + entry.Put(syncable::UNIQUE_CLIENT_TAG, hashed_tag); |
| + entry.Put(syncable::IS_DEL, false); |
| + entry.Put(syncable::SPECIFICS, specifics); |
| + return entry.Get(syncable::META_HANDLE); |
| +} |
| + |
| } // namespace |
| class SyncApiTest : public testing::Test { |
| @@ -651,6 +686,8 @@ class SyncNotifierMock : public sync_notifier::SyncNotifier { |
| MOCK_METHOD1(SendNotification, void(const syncable::ModelTypeSet&)); |
| }; |
| +} // namespace |
| + |
| class SyncManagerTest : public testing::Test, |
| public ModelSafeWorkerRegistrar, |
| public SyncManager::ChangeDelegate { |
| @@ -747,7 +784,7 @@ class SyncManagerTest : public testing::Test, |
| virtual void OnChangesComplete(syncable::ModelType model_type) OVERRIDE {} |
| // Helper methods. |
| - bool SetUpEncryption(bool write_to_nigori) { |
| + bool SetUpEncryption(bool write_to_nigori, bool encrypt_everything) { |
|
akalin
2011/12/09 23:52:42
use enums instead of bools?
Nicolas Zea
2011/12/12 20:12:26
Done.
|
| // Mock the Mac Keychain service. The real Keychain can block on user input. |
| #if defined(OS_MACOSX) |
| Encryptor::UseMockKeychain(true); |
| @@ -773,9 +810,12 @@ class SyncManagerTest : public testing::Test, |
| return false; |
| KeyParams params = {"localhost", "dummy", "foobar"}; |
| cryptographer->AddKey(params); |
| + if (encrypt_everything) |
| + cryptographer->set_encrypt_everything(); |
| if (write_to_nigori) { |
| sync_pb::NigoriSpecifics nigori; |
| cryptographer->GetKeys(nigori.mutable_encrypted()); |
| + cryptographer->UpdateNigoriFromEncryptedTypes(&nigori); |
| WriteNode node(&trans); |
| EXPECT_TRUE(node.InitByIdLookup(nigori_id)); |
| node.SetNigoriSpecifics(nigori); |
| @@ -831,6 +871,26 @@ class SyncManagerTest : public testing::Test, |
| PumpLoop(); |
| } |
| + // Looks up an entry by client tag and resets IS_UNSYNCED value to false. |
| + // Returns true if entry was previously unsynced, false if IS_UNSYNCED was |
| + // already false. |
| + bool ResetUnsyncedEntry(syncable::ModelType type, |
| + const std::string& client_tag) { |
| + UserShare* share = sync_manager_.GetUserShare(); |
| + syncable::ScopedDirLookup dir(share->dir_manager.get(), share->name); |
| + EXPECT_TRUE(dir.good()); |
| + syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir); |
| + const std::string hash = BaseNode::GenerateSyncableHash(type, client_tag); |
| + syncable::MutableEntry entry(&trans, syncable::GET_BY_CLIENT_TAG, |
| + hash); |
| + EXPECT_TRUE(entry.good()); |
| + if (!entry.Get(IS_UNSYNCED)) |
| + return false; |
| + else |
| + entry.Put(IS_UNSYNCED, false); |
| + return true; |
| + } |
| + |
| private: |
| // Needed by |ui_thread_|. |
| MessageLoopForUI ui_loop_; |
| @@ -1205,7 +1265,7 @@ TEST_F(SyncManagerTest, OnIncomingNotification) { |
| } |
| TEST_F(SyncManagerTest, RefreshEncryptionReady) { |
| - EXPECT_TRUE(SetUpEncryption(true)); |
| + EXPECT_TRUE(SetUpEncryption(true, false)); |
| EXPECT_CALL(observer_, OnEncryptionComplete()); |
| sync_manager_.RefreshEncryption(); |
| syncable::ModelTypeSet encrypted_types = |
| @@ -1236,7 +1296,7 @@ TEST_F(SyncManagerTest, RefreshEncryptionNotReady) { |
| // Attempt to refresh encryption when nigori is empty. |
| TEST_F(SyncManagerTest, RefreshEncryptionEmptyNigori) { |
| - EXPECT_TRUE(SetUpEncryption(false)); |
| + EXPECT_TRUE(SetUpEncryption(false, false)); |
| EXPECT_CALL(observer_, OnEncryptionComplete()); |
| sync_manager_.RefreshEncryption(); // Should write to nigori. |
| syncable::ModelTypeSet encrypted_types = |
| @@ -1256,7 +1316,7 @@ TEST_F(SyncManagerTest, RefreshEncryptionEmptyNigori) { |
| } |
| TEST_F(SyncManagerTest, EncryptDataTypesWithNoData) { |
| - EXPECT_TRUE(SetUpEncryption(true)); |
| + EXPECT_TRUE(SetUpEncryption(true, false)); |
| EXPECT_CALL(observer_, |
| OnEncryptedTypesChanged(GetAllRealModelTypes(), true)); |
| EXPECT_CALL(observer_, OnEncryptionComplete()); |
| @@ -1266,7 +1326,7 @@ TEST_F(SyncManagerTest, EncryptDataTypesWithNoData) { |
| TEST_F(SyncManagerTest, EncryptDataTypesWithData) { |
| size_t batch_size = 5; |
| - EXPECT_TRUE(SetUpEncryption(true)); |
| + EXPECT_TRUE(SetUpEncryption(true, false)); |
| // Create some unencrypted unsynced data. |
| int64 folder = MakeFolderWithParent(sync_manager_.GetUserShare(), |
| @@ -1372,7 +1432,7 @@ TEST_F(SyncManagerTest, EncryptDataTypesWithData) { |
| } |
| TEST_F(SyncManagerTest, SetPassphraseWithPassword) { |
| - EXPECT_TRUE(SetUpEncryption(true)); |
| + EXPECT_TRUE(SetUpEncryption(true, false)); |
| { |
| WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); |
| ReadNode root_node(&trans); |
| @@ -1401,7 +1461,7 @@ TEST_F(SyncManagerTest, SetPassphraseWithPassword) { |
| } |
| TEST_F(SyncManagerTest, SetPassphraseWithEmptyPasswordNode) { |
| - EXPECT_TRUE(SetUpEncryption(true)); |
| + EXPECT_TRUE(SetUpEncryption(true, false)); |
| int64 node_id = 0; |
| std::string tag = "foo"; |
| { |
| @@ -1431,11 +1491,9 @@ TEST_F(SyncManagerTest, SetPassphraseWithEmptyPasswordNode) { |
| } |
| } |
| -} // namespace |
| - |
| // Friended by WriteNode, so can't be in an anonymouse namespace. |
| TEST_F(SyncManagerTest, EncryptBookmarksWithLegacyData) { |
| - EXPECT_TRUE(SetUpEncryption(true)); |
| + EXPECT_TRUE(SetUpEncryption(true, false)); |
| std::string title; |
| SyncAPINameToServerName("Google", &title); |
| std::string url = "http://www.google.com"; |
| @@ -1537,4 +1595,116 @@ TEST_F(SyncManagerTest, EncryptBookmarksWithLegacyData) { |
| } |
| } |
| +// Verifies WriteNode::UpdateEntryWithEncryption does not make unnecessary |
| +// changes. |
| +TEST_F(SyncManagerTest, UpdateEntryWithEncryption) { |
| + std::string client_tag = "title"; |
| + sync_pb::EntitySpecifics entity_specifics; |
| + entity_specifics.MutableExtension(sync_pb::bookmark)->set_url("url"); |
| + entity_specifics.MutableExtension(sync_pb::bookmark)->set_title("title"); |
| + MakeServerNode(sync_manager_.GetUserShare(), syncable::BOOKMARKS, client_tag, |
| + BaseNode::GenerateSyncableHash(syncable::BOOKMARKS, |
| + client_tag), |
| + entity_specifics); |
| + // New node shouldn't start off unsynced. |
|
akalin
2011/12/09 23:52:42
can you put newlines between the 'sections' of thi
Nicolas Zea
2011/12/12 20:12:26
Done.
|
| + EXPECT_FALSE(ResetUnsyncedEntry(syncable::BOOKMARKS, client_tag)); |
| + // Manually change to the same data. Should not set is_unsynced. |
| + { |
| + WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); |
| + WriteNode node(&trans); |
| + EXPECT_TRUE(node.InitByClientTagLookup(syncable::BOOKMARKS, client_tag)); |
| + node.SetEntitySpecifics(entity_specifics); |
| + } |
| + EXPECT_FALSE(ResetUnsyncedEntry(syncable::BOOKMARKS, client_tag)); |
| + // Encrypt the datatatype, should set is_unsynced. |
| + EXPECT_CALL(observer_, |
| + OnEncryptedTypesChanged(GetAllRealModelTypes(), true)); |
| + EXPECT_CALL(observer_, OnEncryptionComplete()); |
| + EXPECT_TRUE(SetUpEncryption(true, true)); |
| + sync_manager_.RefreshEncryption(); |
| + { |
| + ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); |
| + ReadNode node(&trans); |
| + EXPECT_TRUE(node.InitByClientTagLookup(syncable::BOOKMARKS, client_tag)); |
| + const syncable::Entry* node_entry = node.GetEntry(); |
| + const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS); |
| + EXPECT_TRUE(specifics.has_encrypted()); |
| + EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME)); |
| + Cryptographer* cryptographer = trans.GetCryptographer(); |
| + EXPECT_TRUE(cryptographer->is_ready()); |
| + EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( |
| + specifics.encrypted())); |
| + } |
| + EXPECT_TRUE(ResetUnsyncedEntry(syncable::BOOKMARKS, client_tag)); |
| + // Set a new passphrase. Should set is_unsynced. |
| + testing::Mock::VerifyAndClearExpectations(&observer_); |
| + EXPECT_CALL(observer_, OnPassphraseAccepted(_)); |
| + EXPECT_CALL(observer_, OnEncryptionComplete()); |
| + sync_manager_.SetPassphrase("new_passphrase", true); |
| + { |
| + ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); |
| + ReadNode node(&trans); |
| + EXPECT_TRUE(node.InitByClientTagLookup(syncable::BOOKMARKS, client_tag)); |
| + const syncable::Entry* node_entry = node.GetEntry(); |
| + const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS); |
| + EXPECT_TRUE(specifics.has_encrypted()); |
| + EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME)); |
| + Cryptographer* cryptographer = trans.GetCryptographer(); |
| + EXPECT_TRUE(cryptographer->is_ready()); |
| + EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( |
| + specifics.encrypted())); |
| + } |
| + EXPECT_TRUE(ResetUnsyncedEntry(syncable::BOOKMARKS, client_tag)); |
| + // Force a re-encrypt everything. Should not set is_unsynced. |
| + testing::Mock::VerifyAndClearExpectations(&observer_); |
| + EXPECT_CALL(observer_, OnEncryptionComplete()); |
| + sync_manager_.RefreshEncryption(); |
| + { |
| + ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); |
| + ReadNode node(&trans); |
| + EXPECT_TRUE(node.InitByClientTagLookup(syncable::BOOKMARKS, client_tag)); |
| + const syncable::Entry* node_entry = node.GetEntry(); |
| + const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS); |
| + EXPECT_TRUE(specifics.has_encrypted()); |
| + EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME)); |
| + Cryptographer* cryptographer = trans.GetCryptographer(); |
| + EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( |
| + specifics.encrypted())); |
| + } |
| + EXPECT_FALSE(ResetUnsyncedEntry(syncable::BOOKMARKS, client_tag)); |
| + // Manually change to the same data. Should not set is_unsynced. |
| + { |
| + WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); |
| + WriteNode node(&trans); |
| + EXPECT_TRUE(node.InitByClientTagLookup(syncable::BOOKMARKS, client_tag)); |
| + node.SetEntitySpecifics(entity_specifics); |
| + const syncable::Entry* node_entry = node.GetEntry(); |
| + const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS); |
| + EXPECT_TRUE(specifics.has_encrypted()); |
| + EXPECT_FALSE(node_entry->Get(IS_UNSYNCED)); |
| + EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME)); |
| + Cryptographer* cryptographer = trans.GetCryptographer(); |
| + EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( |
| + specifics.encrypted())); |
| + } |
| + EXPECT_FALSE(ResetUnsyncedEntry(syncable::BOOKMARKS, client_tag)); |
| + // Manually change to different data. Should set is_unsynced. |
| + { |
| + entity_specifics.MutableExtension(sync_pb::bookmark)->set_url("url2"); |
| + entity_specifics.MutableExtension(sync_pb::bookmark)->set_title("title2"); |
| + WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); |
| + WriteNode node(&trans); |
| + EXPECT_TRUE(node.InitByClientTagLookup(syncable::BOOKMARKS, client_tag)); |
| + node.SetEntitySpecifics(entity_specifics); |
| + const syncable::Entry* node_entry = node.GetEntry(); |
| + const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS); |
| + EXPECT_TRUE(specifics.has_encrypted()); |
| + EXPECT_TRUE(node_entry->Get(IS_UNSYNCED)); |
| + EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME)); |
| + Cryptographer* cryptographer = trans.GetCryptographer(); |
| + EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( |
| + specifics.encrypted())); |
| + } |
| +} |
| + |
| } // namespace browser_sync |