1 // Copyright 2013 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 "chrome/browser/ui/sync/profile_signin_confirmation_helper.h" 6 7 #include "base/basictypes.h" 8 #include "base/bind.h" 9 #include "base/bind_helpers.h" 10 #include "base/callback.h" 11 #include "base/command_line.h" 12 #include "base/compiler_specific.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/message_loop/message_loop.h" 15 #include "base/prefs/pref_notifier_impl.h" 16 #include "base/prefs/pref_service.h" 17 #include "base/prefs/testing_pref_service.h" 18 #include "base/run_loop.h" 19 #include "base/strings/string16.h" 20 #include "base/strings/string_util.h" 21 #include "base/strings/utf_string_conversions.h" 22 #include "chrome/browser/bookmarks/bookmark_model.h" 23 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 24 #include "chrome/browser/extensions/extension_service.h" 25 #include "chrome/browser/extensions/test_extension_system.h" 26 #include "chrome/browser/history/history_service.h" 27 #include "chrome/browser/history/history_service_factory.h" 28 #include "chrome/browser/prefs/browser_prefs.h" 29 #include "chrome/common/extensions/extension.h" 30 #include "chrome/common/extensions/extension_constants.h" 31 #include "chrome/common/extensions/extension_manifest_constants.h" 32 #include "chrome/common/extensions/permissions/permission_set.h" 33 #include "chrome/test/base/testing_pref_service_syncable.h" 34 #include "chrome/test/base/testing_profile.h" 35 #include "chrome/test/base/ui_test_utils.h" 36 #include "components/user_prefs/pref_registry_syncable.h" 37 #include "content/public/test/test_browser_thread_bundle.h" 38 #include "content/public/test/test_utils.h" 39 #include "testing/gmock/include/gmock/gmock.h" 40 #include "testing/gtest/include/gtest/gtest.h" 41 42 #if defined(OS_CHROMEOS) 43 #include "chrome/browser/chromeos/login/user_manager.h" 44 #include "chrome/browser/chromeos/settings/cros_settings.h" 45 #include "chrome/browser/chromeos/settings/device_settings_service.h" 46 #endif 47 48 namespace { 49 50 template<typename T> 51 void GetValueAndQuit(T* result, const base::Closure& quit, T actual) { 52 *result = actual; 53 quit.Run(); 54 } 55 56 template<typename T> 57 T GetCallbackResult( 58 const base::Callback<void(const base::Callback<void(T)>&)>& callback) { 59 T result = false; 60 base::RunLoop loop; 61 callback.Run(base::Bind(&GetValueAndQuit<T>, &result, loop.QuitClosure())); 62 loop.Run(); 63 return result; 64 } 65 66 // A pref store that can have its read_error property changed for testing. 67 class TestingPrefStoreWithCustomReadError : public TestingPrefStore { 68 public: 69 TestingPrefStoreWithCustomReadError() 70 : read_error_(PersistentPrefStore::PREF_READ_ERROR_NO_FILE) { 71 // By default the profile is "new" (NO_FILE means that the profile 72 // wasn't found on disk, so it was created). 73 } 74 virtual PrefReadError GetReadError() const OVERRIDE { 75 return read_error_; 76 } 77 virtual bool IsInitializationComplete() const OVERRIDE { 78 return true; 79 } 80 void set_read_error(PrefReadError read_error) { 81 read_error_ = read_error; 82 } 83 private: 84 virtual ~TestingPrefStoreWithCustomReadError() {} 85 PrefReadError read_error_; 86 }; 87 88 #if defined(OS_WIN) 89 const base::FilePath::CharType kExtensionFilePath[] = 90 FILE_PATH_LITERAL("c:\\foo"); 91 #elif defined(OS_POSIX) 92 const base::FilePath::CharType kExtensionFilePath[] = 93 FILE_PATH_LITERAL("/oo"); 94 #endif 95 96 static scoped_refptr<extensions::Extension> CreateExtension( 97 const std::string& name, 98 const std::string& id) { 99 DictionaryValue manifest; 100 manifest.SetString(extension_manifest_keys::kVersion, "1.0.0.0"); 101 manifest.SetString(extension_manifest_keys::kName, name); 102 std::string error; 103 scoped_refptr<extensions::Extension> extension = 104 extensions::Extension::Create( 105 base::FilePath(kExtensionFilePath).AppendASCII(name), 106 extensions::Manifest::INTERNAL, 107 manifest, 108 extensions::Extension::NO_FLAGS, 109 id, 110 &error); 111 return extension; 112 } 113 114 } // namespace 115 116 class ProfileSigninConfirmationHelperTest : public testing::Test { 117 public: 118 ProfileSigninConfirmationHelperTest() 119 : user_prefs_(NULL), 120 model_(NULL) { 121 } 122 123 virtual void SetUp() OVERRIDE { 124 // Create the profile. 125 TestingProfile::Builder builder; 126 user_prefs_ = new TestingPrefStoreWithCustomReadError; 127 TestingPrefServiceSyncable* pref_service = new TestingPrefServiceSyncable( 128 new TestingPrefStore(), 129 user_prefs_, 130 new TestingPrefStore(), 131 new user_prefs::PrefRegistrySyncable(), 132 new PrefNotifierImpl()); 133 chrome::RegisterUserProfilePrefs(pref_service->registry()); 134 builder.SetPrefService(make_scoped_ptr<PrefServiceSyncable>(pref_service)); 135 profile_ = builder.Build(); 136 137 // Initialize the services we check. 138 profile_->CreateBookmarkModel(true); 139 model_ = BookmarkModelFactory::GetForProfile(profile_.get()); 140 ui_test_utils::WaitForBookmarkModelToLoad(model_); 141 ASSERT_TRUE(profile_->CreateHistoryService(true, false)); 142 extensions::TestExtensionSystem* system = 143 static_cast<extensions::TestExtensionSystem*>( 144 extensions::ExtensionSystem::Get(profile_.get())); 145 CommandLine command_line(CommandLine::NO_PROGRAM); 146 system->CreateExtensionService(&command_line, 147 base::FilePath(kExtensionFilePath), 148 false); 149 } 150 151 virtual void TearDown() OVERRIDE { 152 // TestExtensionSystem uses DeleteSoon, so we need to delete the profile 153 // and then run the message queue to clean up. 154 profile_.reset(); 155 base::RunLoop().RunUntilIdle(); 156 } 157 158 protected: 159 content::TestBrowserThreadBundle thread_bundle_; 160 scoped_ptr<TestingProfile> profile_; 161 TestingPrefStoreWithCustomReadError* user_prefs_; 162 BookmarkModel* model_; 163 164 #if defined OS_CHROMEOS 165 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; 166 chromeos::ScopedTestCrosSettings test_cros_settings_; 167 chromeos::ScopedTestUserManager test_user_manager_; 168 #endif 169 }; 170 171 TEST_F(ProfileSigninConfirmationHelperTest, DoNotPromptForNewProfile) { 172 // Profile is new and there's no profile data. 173 EXPECT_FALSE( 174 GetCallbackResult( 175 base::Bind( 176 &ui::CheckShouldPromptForNewProfile, 177 profile_.get()))); 178 } 179 180 TEST_F(ProfileSigninConfirmationHelperTest, PromptForNewProfile_Bookmarks) { 181 ASSERT_TRUE(model_); 182 183 // Profile is new but has bookmarks. 184 model_->AddURL(model_->bookmark_bar_node(), 0, string16(ASCIIToUTF16("foo")), 185 GURL("http://foo.com")); 186 EXPECT_TRUE( 187 GetCallbackResult( 188 base::Bind( 189 &ui::CheckShouldPromptForNewProfile, 190 profile_.get()))); 191 } 192 193 TEST_F(ProfileSigninConfirmationHelperTest, PromptForNewProfile_Extensions) { 194 ExtensionService* extensions = 195 extensions::ExtensionSystem::Get(profile_.get())->extension_service(); 196 ASSERT_TRUE(extensions); 197 198 // Profile is new but has synced extensions. 199 200 // (The web store doesn't count.) 201 scoped_refptr<extensions::Extension> webstore = 202 CreateExtension("web store", extension_misc::kWebStoreAppId); 203 extensions->extension_prefs()->AddGrantedPermissions( 204 webstore->id(), make_scoped_refptr(new extensions::PermissionSet).get()); 205 extensions->AddExtension(webstore.get()); 206 EXPECT_FALSE(GetCallbackResult( 207 base::Bind(&ui::CheckShouldPromptForNewProfile, profile_.get()))); 208 209 scoped_refptr<extensions::Extension> extension = 210 CreateExtension("foo", std::string()); 211 extensions->extension_prefs()->AddGrantedPermissions( 212 extension->id(), make_scoped_refptr(new extensions::PermissionSet).get()); 213 extensions->AddExtension(extension.get()); 214 EXPECT_TRUE(GetCallbackResult( 215 base::Bind(&ui::CheckShouldPromptForNewProfile, profile_.get()))); 216 } 217 218 TEST_F(ProfileSigninConfirmationHelperTest, PromptForNewProfile_History) { 219 HistoryService* history = HistoryServiceFactory::GetForProfile( 220 profile_.get(), 221 Profile::EXPLICIT_ACCESS); 222 ASSERT_TRUE(history); 223 224 // Profile is new but has more than $(kHistoryEntriesBeforeNewProfilePrompt) 225 // history items. 226 char buf[18]; 227 for (int i = 0; i < 10; i++) { 228 base::snprintf(buf, arraysize(buf), "http://foo.com/%d", i); 229 history->AddPage( 230 GURL(std::string(buf)), base::Time::Now(), NULL, 1, 231 GURL(), history::RedirectList(), content::PAGE_TRANSITION_LINK, 232 history::SOURCE_BROWSED, false); 233 } 234 EXPECT_TRUE( 235 GetCallbackResult( 236 base::Bind( 237 &ui::CheckShouldPromptForNewProfile, 238 profile_.get()))); 239 } 240 241 TEST_F(ProfileSigninConfirmationHelperTest, PromptForNewProfile_TypedURLs) { 242 HistoryService* history = HistoryServiceFactory::GetForProfile( 243 profile_.get(), 244 Profile::EXPLICIT_ACCESS); 245 ASSERT_TRUE(history); 246 247 // Profile is new but has a typed URL. 248 history->AddPage( 249 GURL("http://example.com"), base::Time::Now(), NULL, 1, 250 GURL(), history::RedirectList(), content::PAGE_TRANSITION_TYPED, 251 history::SOURCE_BROWSED, false); 252 EXPECT_TRUE( 253 GetCallbackResult( 254 base::Bind( 255 &ui::CheckShouldPromptForNewProfile, 256 profile_.get()))); 257 } 258 259 TEST_F(ProfileSigninConfirmationHelperTest, PromptForNewProfile_Restarted) { 260 // Browser has been shut down since profile was created. 261 user_prefs_->set_read_error(PersistentPrefStore::PREF_READ_ERROR_NONE); 262 EXPECT_TRUE( 263 GetCallbackResult( 264 base::Bind( 265 &ui::CheckShouldPromptForNewProfile, 266 profile_.get()))); 267 } 268