Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(381)

Side by Side Diff: chrome/browser/sync/engine/syncapi_unittest.cc

Issue 6465005: [Sync] Initial support for encrypting any datatype (no UI hookup yet). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments. Rest of unit tests. Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Unit tests for the SyncApi. Note that a lot of the underlying 5 // Unit tests for the SyncApi. Note that a lot of the underlying
6 // functionality is provided by the Syncable layer, which has its own 6 // functionality is provided by the Syncable layer, which has its own
7 // unit tests. We'll test SyncApi specific things in this harness. 7 // unit tests. We'll test SyncApi specific things in this harness.
8 8
9 #include <map>
10
9 #include "base/basictypes.h" 11 #include "base/basictypes.h"
10 #include "base/message_loop.h" 12 #include "base/message_loop.h"
11 #include "base/scoped_ptr.h" 13 #include "base/scoped_ptr.h"
12 #include "base/scoped_temp_dir.h" 14 #include "base/scoped_temp_dir.h"
13 #include "base/string_number_conversions.h" 15 #include "base/string_number_conversions.h"
16 #include "base/string_util.h"
14 #include "base/utf_string_conversions.h" 17 #include "base/utf_string_conversions.h"
15 #include "base/values.h" 18 #include "base/values.h"
16 #include "chrome/browser/browser_thread.h" 19 #include "chrome/browser/browser_thread.h"
20 #include "chrome/browser/sync/engine/model_safe_worker.h"
17 #include "chrome/browser/sync/engine/syncapi.h" 21 #include "chrome/browser/sync/engine/syncapi.h"
18 #include "chrome/browser/sync/js_arg_list.h" 22 #include "chrome/browser/sync/js_arg_list.h"
19 #include "chrome/browser/sync/js_backend.h" 23 #include "chrome/browser/sync/js_backend.h"
20 #include "chrome/browser/sync/js_event_handler.h" 24 #include "chrome/browser/sync/js_event_handler.h"
21 #include "chrome/browser/sync/js_event_router.h" 25 #include "chrome/browser/sync/js_event_router.h"
22 #include "chrome/browser/sync/js_test_util.h" 26 #include "chrome/browser/sync/js_test_util.h"
23 #include "chrome/browser/sync/protocol/password_specifics.pb.h" 27 #include "chrome/browser/sync/protocol/password_specifics.pb.h"
24 #include "chrome/browser/sync/protocol/proto_value_conversions.h" 28 #include "chrome/browser/sync/protocol/proto_value_conversions.h"
29 #include "chrome/browser/sync/sessions/sync_session.h"
25 #include "chrome/browser/sync/syncable/directory_manager.h" 30 #include "chrome/browser/sync/syncable/directory_manager.h"
31 #include "chrome/browser/sync/syncable/nigori_util.h"
26 #include "chrome/browser/sync/syncable/syncable.h" 32 #include "chrome/browser/sync/syncable/syncable.h"
33 #include "chrome/browser/sync/syncable/syncable_id.h"
34 #include "chrome/browser/sync/util/cryptographer.h"
27 #include "chrome/test/sync/engine/test_directory_setter_upper.h" 35 #include "chrome/test/sync/engine/test_directory_setter_upper.h"
28 #include "jingle/notifier/base/notifier_options.h" 36 #include "jingle/notifier/base/notifier_options.h"
29 #include "testing/gmock/include/gmock/gmock.h" 37 #include "testing/gmock/include/gmock/gmock.h"
30 #include "testing/gtest/include/gtest/gtest.h" 38 #include "testing/gtest/include/gtest/gtest.h"
31 39
40 using browser_sync::Cryptographer;
32 using browser_sync::HasArgsAsList; 41 using browser_sync::HasArgsAsList;
33 using browser_sync::KeyParams; 42 using browser_sync::KeyParams;
34 using browser_sync::JsArgList; 43 using browser_sync::JsArgList;
35 using browser_sync::MockJsEventHandler; 44 using browser_sync::MockJsEventHandler;
36 using browser_sync::MockJsEventRouter; 45 using browser_sync::MockJsEventRouter;
46 using browser_sync::ModelSafeRoutingInfo;
47 using browser_sync::ModelSafeWorker;
48 using browser_sync::ModelSafeWorkerRegistrar;
49 using browser_sync::sessions::SyncSessionSnapshot;
50 using syncable::ModelType;
51 using syncable::ModelTypeSet;
37 using testing::_; 52 using testing::_;
38 using testing::SaveArg; 53 using testing::SaveArg;
39 using testing::StrictMock; 54 using testing::StrictMock;
40 55
41 namespace sync_api { 56 namespace sync_api {
42 57
58 namespace {
59
60 // Utility methods for creating nodes through the syncapi.
61 int64 MakeNode(UserShare* share,
62 ModelType model_type,
63 const std::string& client_tag) {
64 WriteTransaction trans(share);
65 ReadNode root_node(&trans);
66 root_node.InitByRootLookup();
67 WriteNode node(&trans);
68 EXPECT_TRUE(node.InitUniqueByCreation(model_type, root_node, client_tag));
69 node.SetIsFolder(false);
70 return node.GetId();
71 }
72
73 int64 MakeNodeWithParent(UserShare* share,
74 ModelType model_type,
75 const std::string& client_tag,
76 int64 parent_id) {
77 WriteTransaction trans(share);
78 ReadNode parent_node(&trans);
79 parent_node.InitByIdLookup(parent_id);
80 WriteNode node(&trans);
81 EXPECT_TRUE(node.InitUniqueByCreation(model_type, parent_node, client_tag));
82 node.SetIsFolder(false);
83
84 return node.GetId();
85 }
86
87 int64 MakeFolderWithParent(UserShare* share,
88 ModelType model_type,
89 int64 parent_id,
90 BaseNode* predecessor) {
91 WriteTransaction trans(share);
92 ReadNode parent_node(&trans);
93 parent_node.InitByIdLookup(parent_id);
94 WriteNode node(&trans);
95 EXPECT_TRUE(node.InitByCreation(model_type, parent_node, predecessor));
96 node.SetIsFolder(true);
97 return node.GetId();
98 }
99
100 // Creates the "synced" root node for a particular datatype. We use the syncable
101 // methods here so that the syncer treats these nodes as if they were already
102 // received from the server.
103 int64 MakeServerNodeForType(UserShare* share,
104 ModelType model_type) {
105 sync_pb::EntitySpecifics specifics;
106 syncable::AddDefaultExtensionValue(model_type, &specifics);
107 syncable::ScopedDirLookup dir(share->dir_manager.get(), share->name);
108 if (!dir.good())
109 return 0;
110 syncable::WriteTransaction trans(dir, syncable::UNITTEST, __FILE__, __LINE__);
111 // Attempt to lookup by nigori tag.
112 std::string type_tag = syncable::ModelTypeToRootTag(model_type);
113 syncable::Id node_id = syncable::Id::CreateFromServerId(type_tag);
114 syncable::MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM,
115 node_id);
116 if (!entry.good())
117 return 0;
118 entry.Put(syncable::BASE_VERSION, 1);
119 entry.Put(syncable::SERVER_VERSION, 1);
120 entry.Put(syncable::IS_UNAPPLIED_UPDATE, false);
121 entry.Put(syncable::SERVER_PARENT_ID, syncable::kNullId);
122 entry.Put(syncable::SERVER_IS_DIR, false);
123 entry.Put(syncable::SERVER_SPECIFICS, specifics);
124 entry.Put(syncable::UNIQUE_SERVER_TAG, type_tag);
125 entry.Put(syncable::NON_UNIQUE_NAME, type_tag);
126 entry.Put(syncable::IS_DEL, false);
127 entry.Put(syncable::SPECIFICS, specifics);
128 return entry.Get(syncable::META_HANDLE);
129 }
130
131 } // namespace
132
43 class SyncApiTest : public testing::Test { 133 class SyncApiTest : public testing::Test {
44 public: 134 public:
45 virtual void SetUp() { 135 virtual void SetUp() {
46 setter_upper_.SetUp(); 136 setter_upper_.SetUp();
47 share_.dir_manager.reset(setter_upper_.manager()); 137 share_.dir_manager.reset(setter_upper_.manager());
48 share_.name = setter_upper_.name(); 138 share_.name = setter_upper_.name();
49 } 139 }
50 140
51 virtual void TearDown() { 141 virtual void TearDown() {
52 // |share_.dir_manager| does not actually own its value. 142 // |share_.dir_manager| does not actually own its value.
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 bool is_folder = false; 393 bool is_folder = false;
304 EXPECT_TRUE(value.GetBoolean("isFolder", &is_folder)); 394 EXPECT_TRUE(value.GetBoolean("isFolder", &is_folder));
305 EXPECT_EQ(node.GetIsFolder(), is_folder); 395 EXPECT_EQ(node.GetIsFolder(), is_folder);
306 } 396 }
307 { 397 {
308 std::string title; 398 std::string title;
309 EXPECT_TRUE(value.GetString("title", &title)); 399 EXPECT_TRUE(value.GetString("title", &title));
310 EXPECT_EQ(node.GetTitle(), UTF8ToWide(title)); 400 EXPECT_EQ(node.GetTitle(), UTF8ToWide(title));
311 } 401 }
312 { 402 {
313 syncable::ModelType expected_model_type = node.GetModelType(); 403 ModelType expected_model_type = node.GetModelType();
314 std::string type_str; 404 std::string type_str;
315 EXPECT_TRUE(value.GetString("type", &type_str)); 405 EXPECT_TRUE(value.GetString("type", &type_str));
316 if (expected_model_type >= syncable::FIRST_REAL_MODEL_TYPE) { 406 if (expected_model_type >= syncable::FIRST_REAL_MODEL_TYPE) {
317 syncable::ModelType model_type = 407 ModelType model_type =
318 syncable::ModelTypeFromString(type_str); 408 syncable::ModelTypeFromString(type_str);
319 EXPECT_EQ(expected_model_type, model_type); 409 EXPECT_EQ(expected_model_type, model_type);
320 } else if (expected_model_type == syncable::TOP_LEVEL_FOLDER) { 410 } else if (expected_model_type == syncable::TOP_LEVEL_FOLDER) {
321 EXPECT_EQ("Top-level folder", type_str); 411 EXPECT_EQ("Top-level folder", type_str);
322 } else if (expected_model_type == syncable::UNSPECIFIED) { 412 } else if (expected_model_type == syncable::UNSPECIFIED) {
323 EXPECT_EQ("Unspecified", type_str); 413 EXPECT_EQ("Unspecified", type_str);
324 } else { 414 } else {
325 ADD_FAILURE(); 415 ADD_FAILURE();
326 } 416 }
327 } 417 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 virtual ~TestHttpPostProviderFactory() {} 451 virtual ~TestHttpPostProviderFactory() {}
362 virtual HttpPostProviderInterface* Create() { 452 virtual HttpPostProviderInterface* Create() {
363 NOTREACHED(); 453 NOTREACHED();
364 return NULL; 454 return NULL;
365 } 455 }
366 virtual void Destroy(HttpPostProviderInterface* http) { 456 virtual void Destroy(HttpPostProviderInterface* http) {
367 NOTREACHED(); 457 NOTREACHED();
368 } 458 }
369 }; 459 };
370 460
371 class SyncManagerTest : public testing::Test { 461 class SyncManagerObserverMock : public SyncManager::Observer {
462 public:
463 MOCK_METHOD4(OnChangesApplied,
464 void(ModelType,
465 const BaseTransaction*,
466 const SyncManager::ChangeRecord*,
467 int));
468 MOCK_METHOD1(OnChangesComplete, void(ModelType));
469 MOCK_METHOD1(OnSyncCycleCompleted,
470 void(const SyncSessionSnapshot*));
471 MOCK_METHOD0(OnInitializationComplete, void());
472 MOCK_METHOD1(OnAuthError, void(const GoogleServiceAuthError&));
473 MOCK_METHOD1(OnPassphraseRequired, void(bool));
474 MOCK_METHOD1(OnPassphraseAccepted, void(const std::string&));
475 MOCK_METHOD0(OnPaused, void());
476 MOCK_METHOD0(OnResumed, void());
477 MOCK_METHOD0(OnStopSyncingPermanently, void());
478 MOCK_METHOD1(OnUpdatedToken, void(const std::string&));
479 MOCK_METHOD0(OnClearServerDataFailed, void());
480 MOCK_METHOD0(OnClearServerDataSucceeded, void());
481 MOCK_METHOD1(OnEncryptionComplete, void(const ModelTypeSet&));
482 };
483
484 class SyncManagerTest : public testing::Test,
485 public ModelSafeWorkerRegistrar {
372 protected: 486 protected:
373 SyncManagerTest() : ui_thread_(BrowserThread::UI, &ui_loop_) {} 487 SyncManagerTest() : ui_thread_(BrowserThread::UI, &ui_loop_) {}
374 488
489 // Test implementation.
375 void SetUp() { 490 void SetUp() {
376 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 491 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
377 sync_manager_.Init(temp_dir_.path(), "bogus", 0, false, 492 sync_manager_.Init(temp_dir_.path(), "bogus", 0, false,
378 new TestHttpPostProviderFactory(), NULL, "bogus", 493 new TestHttpPostProviderFactory(), this, "bogus",
379 SyncCredentials(), notifier::NotifierOptions(), 494 SyncCredentials(), notifier::NotifierOptions(),
380 "", true /* setup_for_test_mode */); 495 "", true /* setup_for_test_mode */);
496 sync_manager_.SetObserver(&observer_);
497 ModelSafeRoutingInfo routes;
498 GetModelSafeRoutingInfo(&routes);
499 for (ModelSafeRoutingInfo::iterator i = routes.begin(); i != routes.end();
500 ++i) {
501 EXPECT_CALL(observer_, OnChangesApplied(i->first, _, _, 1))
502 .RetiresOnSaturation();
503 EXPECT_CALL(observer_, OnChangesComplete(i->first))
504 .RetiresOnSaturation();
505 type_roots_[i->first] = MakeServerNodeForType(
506 sync_manager_.GetUserShare(), i->first);
507 }
381 } 508 }
382 509
383 void TearDown() { 510 void TearDown() {
511 sync_manager_.RemoveObserver();
384 sync_manager_.Shutdown(); 512 sync_manager_.Shutdown();
385 } 513 }
386 514
515 // ModelSafeWorkerRegistrar implementation.
516 virtual void GetWorkers(std::vector<ModelSafeWorker*>* out) {
517 NOTIMPLEMENTED();
518 out->clear();
519 }
520 virtual void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
521 (*out)[syncable::NIGORI] = browser_sync::GROUP_PASSIVE;
522 (*out)[syncable::BOOKMARKS] = browser_sync::GROUP_PASSIVE;
523 (*out)[syncable::THEMES] = browser_sync::GROUP_PASSIVE;
524 (*out)[syncable::SESSIONS] = browser_sync::GROUP_PASSIVE;
525 }
526
527 // Helper methods.
528 bool SetUpEncryption() {
529 // We need to create the nigori node as if it were an applied server update.
530 UserShare* share = sync_manager_.GetUserShare();
531 int64 nigori_id = GetIdForDataType(syncable::NIGORI);
532 if (nigori_id == kInvalidId)
533 return false;
534
535 // Set the nigori cryptographer information.
536 Cryptographer* cryptographer = share->dir_manager->cryptographer();
537 if (!cryptographer)
538 return false;
539 KeyParams params = {"localhost", "dummy", "foobar"};
540 cryptographer->AddKey(params);
541 sync_pb::NigoriSpecifics nigori;
542 cryptographer->GetKeys(nigori.mutable_encrypted());
543 WriteTransaction trans(share);
544 WriteNode node(&trans);
545 node.InitByIdLookup(nigori_id);
546 node.SetNigoriSpecifics(nigori);
547 return cryptographer->is_ready();
548 }
549
550 int64 GetIdForDataType(ModelType type) {
551 if (type_roots_.count(type) == 0)
552 return 0;
553 return type_roots_[type];
554 }
555
387 private: 556 private:
388 // Needed by |ui_thread_|. 557 // Needed by |ui_thread_|.
389 MessageLoopForUI ui_loop_; 558 MessageLoopForUI ui_loop_;
390 // Needed by |sync_manager_|. 559 // Needed by |sync_manager_|.
391 BrowserThread ui_thread_; 560 BrowserThread ui_thread_;
392 // Needed by |sync_manager_|. 561 // Needed by |sync_manager_|.
393 ScopedTempDir temp_dir_; 562 ScopedTempDir temp_dir_;
563 // Sync Id's for the roots of the enabled datatypes.
564 std::map<ModelType, int64> type_roots_;
394 565
395 protected: 566 protected:
396 SyncManager sync_manager_; 567 SyncManager sync_manager_;
568 StrictMock<SyncManagerObserverMock> observer_;
397 }; 569 };
398 570
399 TEST_F(SyncManagerTest, ParentJsEventRouter) { 571 TEST_F(SyncManagerTest, ParentJsEventRouter) {
400 StrictMock<MockJsEventRouter> event_router; 572 StrictMock<MockJsEventRouter> event_router;
401 browser_sync::JsBackend* js_backend = sync_manager_.GetJsBackend(); 573 browser_sync::JsBackend* js_backend = sync_manager_.GetJsBackend();
402 EXPECT_EQ(NULL, js_backend->GetParentJsEventRouter()); 574 EXPECT_EQ(NULL, js_backend->GetParentJsEventRouter());
403 js_backend->SetParentJsEventRouter(&event_router); 575 js_backend->SetParentJsEventRouter(&event_router);
404 EXPECT_EQ(&event_router, js_backend->GetParentJsEventRouter()); 576 EXPECT_EQ(&event_router, js_backend->GetParentJsEventRouter());
405 js_backend->RemoveParentJsEventRouter(); 577 js_backend->RemoveParentJsEventRouter();
406 EXPECT_EQ(NULL, js_backend->GetParentJsEventRouter()); 578 EXPECT_EQ(NULL, js_backend->GetParentJsEventRouter());
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 sync_manager_.TriggerOnIncomingNotificationForTest(model_types); 840 sync_manager_.TriggerOnIncomingNotificationForTest(model_types);
669 841
670 js_backend->SetParentJsEventRouter(&event_router); 842 js_backend->SetParentJsEventRouter(&event_router);
671 sync_manager_.TriggerOnIncomingNotificationForTest(model_types); 843 sync_manager_.TriggerOnIncomingNotificationForTest(model_types);
672 js_backend->RemoveParentJsEventRouter(); 844 js_backend->RemoveParentJsEventRouter();
673 845
674 sync_manager_.TriggerOnIncomingNotificationForTest(empty_model_types); 846 sync_manager_.TriggerOnIncomingNotificationForTest(empty_model_types);
675 sync_manager_.TriggerOnIncomingNotificationForTest(model_types); 847 sync_manager_.TriggerOnIncomingNotificationForTest(model_types);
676 } 848 }
677 849
850 TEST_F(SyncManagerTest, EncryptDataTypesWithNoData) {
851 EXPECT_TRUE(SetUpEncryption());
852 ModelTypeSet encrypted_types;
853 encrypted_types.insert(syncable::BOOKMARKS);
854 EXPECT_CALL(observer_, OnEncryptionComplete(encrypted_types));
855 sync_manager_.EncryptDataTypes(encrypted_types);
856 {
857 ReadTransaction trans(sync_manager_.GetUserShare());
858 EXPECT_EQ(encrypted_types,
859 GetEncryptedDataTypesFromSyncer(trans.GetWrappedTrans()));
860 }
861 }
862
863 TEST_F(SyncManagerTest, EncryptDataTypesWithData) {
864 size_t batch_size = 5;
865 EXPECT_TRUE(SetUpEncryption());
866
867 // Create some unencrypted unsynced data.
868 int64 folder = MakeFolderWithParent(sync_manager_.GetUserShare(),
869 syncable::BOOKMARKS,
870 GetIdForDataType(syncable::BOOKMARKS),
871 NULL);
872 // First batch_size nodes are children of folder.
873 size_t i;
874 for (i = 0; i < batch_size; ++i) {
875 MakeNodeWithParent(sync_manager_.GetUserShare(), syncable::BOOKMARKS,
876 StringPrintf("%zu", i), folder);
877 }
878 // Next batch_size nodes are a different type and on their own.
879 for (; i < 2*batch_size; ++i) {
880 MakeNodeWithParent(sync_manager_.GetUserShare(), syncable::SESSIONS,
881 StringPrintf("%zu", i),
882 GetIdForDataType(syncable::SESSIONS));
883 }
884 // Last batch_size nodes are a third type that will not need encryption.
885 for (; i < 3*batch_size; ++i) {
886 MakeNodeWithParent(sync_manager_.GetUserShare(), syncable::THEMES,
887 StringPrintf("%zu", i),
888 GetIdForDataType(syncable::THEMES));
889 }
890
891 {
892 ReadTransaction trans(sync_manager_.GetUserShare());
893 EXPECT_TRUE(syncable::VerifyDataTypeEncryption(trans.GetWrappedTrans(),
894 syncable::BOOKMARKS,
895 false /* not encrypted */));
896 EXPECT_TRUE(syncable::VerifyDataTypeEncryption(trans.GetWrappedTrans(),
897 syncable::SESSIONS,
898 false /* not encrypted */));
899 EXPECT_TRUE(syncable::VerifyDataTypeEncryption(trans.GetWrappedTrans(),
900 syncable::THEMES,
901 false /* not encrypted */));
902 }
903
904 ModelTypeSet encrypted_types;
905 encrypted_types.insert(syncable::BOOKMARKS);
906 encrypted_types.insert(syncable::SESSIONS);
907 EXPECT_CALL(observer_, OnEncryptionComplete(encrypted_types));
908 sync_manager_.EncryptDataTypes(encrypted_types);
909
910 {
911 ReadTransaction trans(sync_manager_.GetUserShare());
912 EXPECT_EQ(encrypted_types,
913 GetEncryptedDataTypesFromSyncer(trans.GetWrappedTrans()));
914 EXPECT_TRUE(syncable::VerifyDataTypeEncryption(trans.GetWrappedTrans(),
915 syncable::BOOKMARKS,
916 true /* is encrypted */));
917 EXPECT_TRUE(syncable::VerifyDataTypeEncryption(trans.GetWrappedTrans(),
918 syncable::SESSIONS,
919 true /* is encrypted */));
920 EXPECT_TRUE(syncable::VerifyDataTypeEncryption(trans.GetWrappedTrans(),
921 syncable::THEMES,
922 false /* not encrypted */));
923 }
924 }
925
678 } // namespace 926 } // namespace
679 927
680 } // namespace browser_sync 928 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698