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