1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "sync/internal_api/js_sync_encryption_handler_observer.h" 6 7 #include "base/basictypes.h" 8 #include "base/location.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/values.h" 11 #include "sync/internal_api/public/base/model_type.h" 12 #include "sync/internal_api/public/util/sync_string_conversions.h" 13 #include "sync/internal_api/public/util/weak_handle.h" 14 #include "sync/js/js_event_details.h" 15 #include "sync/js/js_test_util.h" 16 #include "sync/test/fake_encryptor.h" 17 #include "sync/util/cryptographer.h" 18 #include "sync/util/time.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 namespace syncer { 22 namespace { 23 24 using ::testing::InSequence; 25 using ::testing::StrictMock; 26 27 class JsSyncEncryptionHandlerObserverTest : public testing::Test { 28 protected: 29 JsSyncEncryptionHandlerObserverTest() { 30 js_sync_encryption_handler_observer_.SetJsEventHandler( 31 mock_js_event_handler_.AsWeakHandle()); 32 } 33 34 private: 35 // This must be destroyed after the member variables below in order 36 // for WeakHandles to be destroyed properly. 37 base::MessageLoop message_loop_; 38 39 protected: 40 StrictMock<MockJsEventHandler> mock_js_event_handler_; 41 JsSyncEncryptionHandlerObserver js_sync_encryption_handler_observer_; 42 43 void PumpLoop() { 44 message_loop_.RunUntilIdle(); 45 } 46 }; 47 48 TEST_F(JsSyncEncryptionHandlerObserverTest, NoArgNotifiations) { 49 InSequence dummy; 50 51 EXPECT_CALL(mock_js_event_handler_, 52 HandleJsEvent("onEncryptionComplete", 53 HasDetails(JsEventDetails()))); 54 55 js_sync_encryption_handler_observer_.OnEncryptionComplete(); 56 PumpLoop(); 57 } 58 59 TEST_F(JsSyncEncryptionHandlerObserverTest, OnPassphraseRequired) { 60 InSequence dummy; 61 62 base::DictionaryValue reason_passphrase_not_required_details; 63 base::DictionaryValue reason_encryption_details; 64 base::DictionaryValue reason_decryption_details; 65 66 reason_passphrase_not_required_details.SetString( 67 "reason", 68 PassphraseRequiredReasonToString(REASON_PASSPHRASE_NOT_REQUIRED)); 69 reason_encryption_details.SetString( 70 "reason", 71 PassphraseRequiredReasonToString(REASON_ENCRYPTION)); 72 reason_decryption_details.SetString( 73 "reason", 74 PassphraseRequiredReasonToString(REASON_DECRYPTION)); 75 76 EXPECT_CALL(mock_js_event_handler_, 77 HandleJsEvent("onPassphraseRequired", 78 HasDetailsAsDictionary( 79 reason_passphrase_not_required_details))); 80 EXPECT_CALL(mock_js_event_handler_, 81 HandleJsEvent("onPassphraseRequired", 82 HasDetailsAsDictionary(reason_encryption_details))); 83 EXPECT_CALL(mock_js_event_handler_, 84 HandleJsEvent("onPassphraseRequired", 85 HasDetailsAsDictionary(reason_decryption_details))); 86 87 js_sync_encryption_handler_observer_.OnPassphraseRequired( 88 REASON_PASSPHRASE_NOT_REQUIRED, 89 sync_pb::EncryptedData()); 90 js_sync_encryption_handler_observer_.OnPassphraseRequired(REASON_ENCRYPTION, 91 sync_pb::EncryptedData()); 92 js_sync_encryption_handler_observer_.OnPassphraseRequired(REASON_DECRYPTION, 93 sync_pb::EncryptedData()); 94 PumpLoop(); 95 } 96 97 TEST_F(JsSyncEncryptionHandlerObserverTest, OnBootstrapTokenUpdated) { 98 base::DictionaryValue bootstrap_token_details; 99 bootstrap_token_details.SetString("bootstrapToken", "<redacted>"); 100 bootstrap_token_details.SetString("type", "PASSPHRASE_BOOTSTRAP_TOKEN"); 101 102 EXPECT_CALL(mock_js_event_handler_, 103 HandleJsEvent( 104 "onBootstrapTokenUpdated", 105 HasDetailsAsDictionary(bootstrap_token_details))); 106 107 js_sync_encryption_handler_observer_.OnBootstrapTokenUpdated( 108 "sensitive_token", PASSPHRASE_BOOTSTRAP_TOKEN); 109 PumpLoop(); 110 } 111 112 TEST_F(JsSyncEncryptionHandlerObserverTest, OnEncryptedTypesChanged) { 113 base::DictionaryValue expected_details; 114 base::ListValue* encrypted_type_values = new base::ListValue(); 115 const bool encrypt_everything = false; 116 expected_details.Set("encryptedTypes", encrypted_type_values); 117 expected_details.SetBoolean("encryptEverything", encrypt_everything); 118 ModelTypeSet encrypted_types; 119 120 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { 121 ModelType type = ModelTypeFromInt(i); 122 encrypted_types.Put(type); 123 encrypted_type_values->Append(new base::StringValue( 124 ModelTypeToString(type))); 125 } 126 127 EXPECT_CALL(mock_js_event_handler_, 128 HandleJsEvent("onEncryptedTypesChanged", 129 HasDetailsAsDictionary(expected_details))); 130 131 js_sync_encryption_handler_observer_.OnEncryptedTypesChanged( 132 encrypted_types, encrypt_everything); 133 PumpLoop(); 134 } 135 136 137 TEST_F(JsSyncEncryptionHandlerObserverTest, OnCryptographerStateChanged) { 138 base::DictionaryValue expected_details; 139 bool expected_ready = false; 140 bool expected_pending = false; 141 expected_details.SetBoolean("ready", expected_ready); 142 expected_details.SetBoolean("hasPendingKeys", expected_pending); 143 ModelTypeSet encrypted_types; 144 145 EXPECT_CALL(mock_js_event_handler_, 146 HandleJsEvent("onCryptographerStateChanged", 147 HasDetailsAsDictionary(expected_details))); 148 149 FakeEncryptor encryptor; 150 Cryptographer cryptographer(&encryptor); 151 152 js_sync_encryption_handler_observer_.OnCryptographerStateChanged( 153 &cryptographer); 154 PumpLoop(); 155 } 156 157 TEST_F(JsSyncEncryptionHandlerObserverTest, OnPassphraseTypeChanged) { 158 InSequence dummy; 159 160 base::DictionaryValue passphrase_type_details; 161 passphrase_type_details.SetString("passphraseType", "IMPLICIT_PASSPHRASE"); 162 passphrase_type_details.SetInteger("explicitPassphraseTime", 10); 163 EXPECT_CALL(mock_js_event_handler_, 164 HandleJsEvent("onPassphraseTypeChanged", 165 HasDetailsAsDictionary(passphrase_type_details))); 166 167 js_sync_encryption_handler_observer_.OnPassphraseTypeChanged( 168 IMPLICIT_PASSPHRASE, ProtoTimeToTime(10)); 169 PumpLoop(); 170 } 171 172 } // namespace 173 } // namespace syncer 174