Home | History | Annotate | Download | only in sync
      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