// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/profile_resetter/profile_resetter.h" #include #include #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_path_override.h" #include "build/build_config.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service_test_base.h" #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profile_resetter/brandcode_config_fetcher.h" #include "chrome/browser/profile_resetter/profile_reset_report.pb.h" #include "chrome/browser/profile_resetter/profile_resetter_test_base.h" #include "chrome/browser/profile_resetter/resettable_settings_snapshot.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/search_engines/ui_thread_search_terms_data.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/web_data_service_factory.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/browser_with_test_window_test.h" #include "components/content_settings/core/browser/content_settings_info.h" #include "components/content_settings/core/browser/content_settings_registry.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/browser/website_settings_info.h" #include "components/prefs/pref_service.h" #include "components/search_engines/template_url_service.h" #include "components/search_engines/template_url_service_client.h" #include "content/public/browser/web_contents.h" #include "content/public/test/test_browser_thread.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" #include "extensions/common/manifest_constants.h" #include "net/http/http_response_headers.h" #include "net/http/http_status_code.h" #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_request_status.h" #include "url/gurl.h" #if defined(OS_WIN) #include "base/files/file_util.h" #include "base/path_service.h" #include "base/process/process_handle.h" #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" #include "base/win/scoped_com_initializer.h" #include "base/win/shortcut.h" #endif namespace { const char kDistributionConfig[] = "{" " \"homepage\" : \"http://www.foo.com\"," " \"homepage_is_newtabpage\" : false," " \"browser\" : {" " \"show_home_button\" : true" " }," " \"session\" : {" " \"restore_on_startup\" : 4," " \"startup_urls\" : [\"http://goo.gl\", \"http://foo.de\"]" " }," " \"search_provider_overrides\" : [" " {" " \"name\" : \"first\"," " \"keyword\" : \"firstkey\"," " \"search_url\" : \"http://www.foo.com/s?q={searchTerms}\"," " \"favicon_url\" : \"http://www.foo.com/favicon.ico\"," " \"suggest_url\" : \"http://www.foo.com/s?q={searchTerms}\"," " \"encoding\" : \"UTF-8\"," " \"id\" : 1001" " }" " ]," " \"extensions\" : {" " \"settings\" : {" " \"placeholder_for_id\": {" " }" " }" " }" "}"; const char kXmlConfig[] = "" "" "" "" "placeholder_for_data" "" "" ""; using extensions::Extension; using extensions::Manifest; // ProfileResetterTest -------------------------------------------------------- // ProfileResetterTest sets up the extension, WebData and TemplateURL services. class ProfileResetterTest : public extensions::ExtensionServiceTestBase, public ProfileResetterTestBase { public: ProfileResetterTest(); ~ProfileResetterTest() override; protected: void SetUp() override; TestingProfile* profile() { return profile_.get(); } static scoped_ptr CreateTemplateURLService( content::BrowserContext* context); private: #if defined(OS_WIN) base::ScopedPathOverride user_desktop_override_; base::ScopedPathOverride app_dir_override_; base::ScopedPathOverride start_menu_override_; base::ScopedPathOverride taskbar_pins_override_; base::win::ScopedCOMInitializer com_init_; #endif }; ProfileResetterTest::ProfileResetterTest() #if defined(OS_WIN) : user_desktop_override_(base::DIR_USER_DESKTOP), app_dir_override_(base::DIR_APP_DATA), start_menu_override_(base::DIR_START_MENU), taskbar_pins_override_(base::DIR_TASKBAR_PINS) #endif {} ProfileResetterTest::~ProfileResetterTest() { } void ProfileResetterTest::SetUp() { extensions::ExtensionServiceTestBase::SetUp(); InitializeEmptyExtensionService(); profile()->CreateWebDataService(); TemplateURLServiceFactory::GetInstance()->SetTestingFactory( profile(), &ProfileResetterTest::CreateTemplateURLService); resetter_.reset(new ProfileResetter(profile())); } // static scoped_ptr ProfileResetterTest::CreateTemplateURLService( content::BrowserContext* context) { Profile* profile = static_cast(context); return make_scoped_ptr(new TemplateURLService( profile->GetPrefs(), scoped_ptr(new UIThreadSearchTermsData(profile)), WebDataServiceFactory::GetKeywordWebDataForProfile( profile, ServiceAccessType::EXPLICIT_ACCESS), scoped_ptr(), NULL, NULL, base::Closure())); } // PinnedTabsResetTest -------------------------------------------------------- class PinnedTabsResetTest : public BrowserWithTestWindowTest, public ProfileResetterTestBase { protected: void SetUp() override; content::WebContents* CreateWebContents(); }; void PinnedTabsResetTest::SetUp() { BrowserWithTestWindowTest::SetUp(); resetter_.reset(new ProfileResetter(profile())); } content::WebContents* PinnedTabsResetTest::CreateWebContents() { return content::WebContents::Create( content::WebContents::CreateParams(profile())); } // ConfigParserTest ----------------------------------------------------------- // URLFetcher delegate that simply records the upload data. struct URLFetcherRequestListener : net::URLFetcherDelegate { URLFetcherRequestListener(); ~URLFetcherRequestListener() override; void OnURLFetchComplete(const net::URLFetcher* source) override; std::string upload_data; net::URLFetcherDelegate* real_delegate; }; URLFetcherRequestListener::URLFetcherRequestListener() : real_delegate(NULL) { } URLFetcherRequestListener::~URLFetcherRequestListener() { } void URLFetcherRequestListener::OnURLFetchComplete( const net::URLFetcher* source) { const net::TestURLFetcher* test_fetcher = static_cast(source); upload_data = test_fetcher->upload_data(); DCHECK(real_delegate); real_delegate->OnURLFetchComplete(source); } class ConfigParserTest : public testing::Test { protected: ConfigParserTest(); virtual ~ConfigParserTest(); scoped_ptr WaitForRequest(const GURL& url); net::FakeURLFetcherFactory& factory() { return factory_; } private: scoped_ptr CreateFakeURLFetcher( const GURL& url, net::URLFetcherDelegate* fetcher_delegate, const std::string& response_data, net::HttpStatusCode response_code, net::URLRequestStatus::Status status); MOCK_METHOD0(Callback, void(void)); base::MessageLoopForIO loop_; content::TestBrowserThread ui_thread_; content::TestBrowserThread io_thread_; URLFetcherRequestListener request_listener_; net::FakeURLFetcherFactory factory_; }; ConfigParserTest::ConfigParserTest() : ui_thread_(content::BrowserThread::UI, &loop_), io_thread_(content::BrowserThread::IO, &loop_), factory_(NULL, base::Bind(&ConfigParserTest::CreateFakeURLFetcher, base::Unretained(this))) { } ConfigParserTest::~ConfigParserTest() {} scoped_ptr ConfigParserTest::WaitForRequest( const GURL& url) { EXPECT_CALL(*this, Callback()); scoped_ptr fetcher( new BrandcodeConfigFetcher(base::Bind(&ConfigParserTest::Callback, base::Unretained(this)), url, "ABCD")); base::MessageLoop::current()->RunUntilIdle(); EXPECT_FALSE(fetcher->IsActive()); // Look for the brand code in the request. EXPECT_NE(std::string::npos, request_listener_.upload_data.find("ABCD")); return fetcher; } scoped_ptr ConfigParserTest::CreateFakeURLFetcher( const GURL& url, net::URLFetcherDelegate* fetcher_delegate, const std::string& response_data, net::HttpStatusCode response_code, net::URLRequestStatus::Status status) { request_listener_.real_delegate = fetcher_delegate; scoped_ptr fetcher( new net::FakeURLFetcher( url, &request_listener_, response_data, response_code, status)); scoped_refptr download_headers = new net::HttpResponseHeaders(""); download_headers->AddHeader("Content-Type: text/xml"); fetcher->set_response_headers(download_headers); return fetcher; } // A helper class to create/delete/check a Chrome desktop shortcut on Windows. class ShortcutHandler { public: ShortcutHandler(); ~ShortcutHandler(); static bool IsSupported(); ShortcutCommand CreateWithArguments(const base::string16& name, const base::string16& args); void CheckShortcutHasArguments(const base::string16& desired_args) const; void Delete(); private: #if defined(OS_WIN) base::FilePath shortcut_path_; #endif DISALLOW_COPY_AND_ASSIGN(ShortcutHandler); }; #if defined(OS_WIN) ShortcutHandler::ShortcutHandler() { } ShortcutHandler::~ShortcutHandler() { if (!shortcut_path_.empty()) Delete(); } // static bool ShortcutHandler::IsSupported() { return true; } ShortcutCommand ShortcutHandler::CreateWithArguments( const base::string16& name, const base::string16& args) { EXPECT_TRUE(shortcut_path_.empty()); base::FilePath path_to_create; EXPECT_TRUE(PathService::Get(base::DIR_USER_DESKTOP, &path_to_create)); path_to_create = path_to_create.Append(name); EXPECT_FALSE(base::PathExists(path_to_create)) << path_to_create.value(); base::FilePath path_exe; EXPECT_TRUE(PathService::Get(base::FILE_EXE, &path_exe)); base::win::ShortcutProperties shortcut_properties; shortcut_properties.set_target(path_exe); shortcut_properties.set_arguments(args); EXPECT_TRUE(base::win::CreateOrUpdateShortcutLink( path_to_create, shortcut_properties, base::win::SHORTCUT_CREATE_ALWAYS)) << path_to_create.value(); shortcut_path_ = path_to_create; return ShortcutCommand(shortcut_path_, args); } void ShortcutHandler::CheckShortcutHasArguments( const base::string16& desired_args) const { EXPECT_FALSE(shortcut_path_.empty()); base::string16 args; EXPECT_TRUE(base::win::ResolveShortcut(shortcut_path_, NULL, &args)); EXPECT_EQ(desired_args, args); } void ShortcutHandler::Delete() { EXPECT_FALSE(shortcut_path_.empty()); EXPECT_TRUE(base::DeleteFile(shortcut_path_, false)); shortcut_path_.clear(); } #else ShortcutHandler::ShortcutHandler() {} ShortcutHandler::~ShortcutHandler() {} // static bool ShortcutHandler::IsSupported() { return false; } ShortcutCommand ShortcutHandler::CreateWithArguments( const base::string16& name, const base::string16& args) { return ShortcutCommand(); } void ShortcutHandler::CheckShortcutHasArguments( const base::string16& desired_args) const { } void ShortcutHandler::Delete() { } #endif // defined(OS_WIN) // helper functions ----------------------------------------------------------- scoped_refptr CreateExtension(const base::string16& name, const base::FilePath& path, Manifest::Location location, extensions::Manifest::Type type, bool installed_by_default) { base::DictionaryValue manifest; manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0"); manifest.SetString(extensions::manifest_keys::kName, name); switch (type) { case extensions::Manifest::TYPE_THEME: manifest.Set(extensions::manifest_keys::kTheme, new base::DictionaryValue); break; case extensions::Manifest::TYPE_HOSTED_APP: manifest.SetString(extensions::manifest_keys::kLaunchWebURL, "http://www.google.com"); manifest.SetString(extensions::manifest_keys::kUpdateURL, "http://clients2.google.com/service/update2/crx"); break; case extensions::Manifest::TYPE_EXTENSION: // do nothing break; default: NOTREACHED(); } manifest.SetString(extensions::manifest_keys::kOmniboxKeyword, name); std::string error; scoped_refptr extension = Extension::Create( path, location, manifest, installed_by_default ? Extension::WAS_INSTALLED_BY_DEFAULT : Extension::NO_FLAGS, &error); EXPECT_TRUE(extension.get() != NULL) << error; return extension; } void ReplaceString(std::string* str, const std::string& placeholder, const std::string& substitution) { ASSERT_NE(static_cast(NULL), str); size_t placeholder_pos = str->find(placeholder); ASSERT_NE(std::string::npos, placeholder_pos); str->replace(placeholder_pos, placeholder.size(), substitution); } /********************* Tests *********************/ TEST_F(ProfileResetterTest, ResetNothing) { // The callback should be called even if there is nothing to reset. ResetAndWait(0); } TEST_F(ProfileResetterTest, ResetDefaultSearchEngineNonOrganic) { ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE, kDistributionConfig); TemplateURLService* model = TemplateURLServiceFactory::GetForProfile(profile()); TemplateURL* default_engine = model->GetDefaultSearchProvider(); ASSERT_NE(static_cast(NULL), default_engine); EXPECT_EQ(base::ASCIIToUTF16("first"), default_engine->short_name()); EXPECT_EQ(base::ASCIIToUTF16("firstkey"), default_engine->keyword()); EXPECT_EQ("http://www.foo.com/s?q={searchTerms}", default_engine->url()); } TEST_F(ProfileResetterTest, ResetDefaultSearchEnginePartially) { // Search engine's logic is tested by // TemplateURLServiceTest.RepairPrepopulatedSearchEngines. // Make sure TemplateURLService has loaded. ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE); TemplateURLService* model = TemplateURLServiceFactory::GetForProfile(profile()); TemplateURLService::TemplateURLVector urls = model->GetTemplateURLs(); // The second call should produce no effect. ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE); EXPECT_EQ(urls, model->GetTemplateURLs()); } TEST_F(ProfileResetterTest, ResetHomepageNonOrganic) { PrefService* prefs = profile()->GetPrefs(); DCHECK(prefs); prefs->SetBoolean(prefs::kHomePageIsNewTabPage, true); prefs->SetString(prefs::kHomePage, "http://google.com"); prefs->SetBoolean(prefs::kShowHomeButton, false); ResetAndWait(ProfileResetter::HOMEPAGE, kDistributionConfig); EXPECT_FALSE(prefs->GetBoolean(prefs::kHomePageIsNewTabPage)); EXPECT_EQ("http://www.foo.com", prefs->GetString(prefs::kHomePage)); EXPECT_TRUE(prefs->GetBoolean(prefs::kShowHomeButton)); } TEST_F(ProfileResetterTest, ResetHomepagePartially) { PrefService* prefs = profile()->GetPrefs(); DCHECK(prefs); prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false); prefs->SetString(prefs::kHomePage, "http://www.foo.com"); prefs->SetBoolean(prefs::kShowHomeButton, true); ResetAndWait(ProfileResetter::HOMEPAGE); EXPECT_TRUE(prefs->GetBoolean(prefs::kHomePageIsNewTabPage)); EXPECT_EQ("http://www.foo.com", prefs->GetString(prefs::kHomePage)); EXPECT_FALSE(prefs->GetBoolean(prefs::kShowHomeButton)); } TEST_F(ProfileResetterTest, ResetContentSettings) { HostContentSettingsMap* host_content_settings_map = HostContentSettingsMapFactory::GetForProfile(profile()); GURL url("http://example.org"); std::map default_settings; // TODO(raymes): Clean up this test so that we don't have such ugly iteration // over the content settings. content_settings::ContentSettingsRegistry* registry = content_settings::ContentSettingsRegistry::GetInstance(); for (const content_settings::ContentSettingsInfo* info : *registry) { ContentSettingsType content_type = info->website_settings_info()->type(); if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT || content_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) { // These types are excluded because one can't call // GetDefaultContentSetting() for them. continue; } ContentSetting default_setting = host_content_settings_map->GetDefaultContentSetting(content_type, NULL); default_settings[content_type] = default_setting; ContentSetting wildcard_setting = default_setting == CONTENT_SETTING_BLOCK ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; ContentSetting site_setting = default_setting == CONTENT_SETTING_ALLOW ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; if (info->IsSettingValid(wildcard_setting)) { host_content_settings_map->SetDefaultContentSetting(content_type, wildcard_setting); } if (info->IsSettingValid(site_setting)) { host_content_settings_map->SetContentSettingDefaultScope( url, url, content_type, std::string(), site_setting); ContentSettingsForOneType host_settings; host_content_settings_map->GetSettingsForOneType( content_type, std::string(), &host_settings); EXPECT_EQ(2U, host_settings.size()); } } ResetAndWait(ProfileResetter::CONTENT_SETTINGS); for (const content_settings::ContentSettingsInfo* info : *registry) { ContentSettingsType content_type = info->website_settings_info()->type(); if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT || content_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) continue; ContentSetting default_setting = host_content_settings_map->GetDefaultContentSetting(content_type, NULL); EXPECT_TRUE(default_settings.count(content_type)); EXPECT_EQ(default_settings[content_type], default_setting); ContentSetting site_setting = host_content_settings_map->GetContentSetting( GURL("example.org"), GURL(), content_type, std::string()); EXPECT_EQ(default_setting, site_setting); ContentSettingsForOneType host_settings; host_content_settings_map->GetSettingsForOneType( content_type, std::string(), &host_settings); EXPECT_EQ(1U, host_settings.size()); } } TEST_F(ProfileResetterTest, ResetExtensionsByDisabling) { service_->Init(); base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); scoped_refptr theme = CreateExtension(base::ASCIIToUTF16("example1"), temp_dir.path(), Manifest::INVALID_LOCATION, extensions::Manifest::TYPE_THEME, false); service_->FinishInstallationForTest(theme.get()); // Let ThemeService finish creating the theme pack. base::MessageLoop::current()->RunUntilIdle(); ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile()); EXPECT_FALSE(theme_service->UsingDefaultTheme()); scoped_refptr ext2 = CreateExtension( base::ASCIIToUTF16("example2"), base::FilePath(FILE_PATH_LITERAL("//nonexistent")), Manifest::INVALID_LOCATION, extensions::Manifest::TYPE_EXTENSION, false); service_->AddExtension(ext2.get()); // Component extensions and policy-managed extensions shouldn't be disabled. scoped_refptr ext3 = CreateExtension( base::ASCIIToUTF16("example3"), base::FilePath(FILE_PATH_LITERAL("//nonexistent2")), Manifest::COMPONENT, extensions::Manifest::TYPE_EXTENSION, false); service_->AddExtension(ext3.get()); scoped_refptr ext4 = CreateExtension(base::ASCIIToUTF16("example4"), base::FilePath(FILE_PATH_LITERAL("//nonexistent3")), Manifest::EXTERNAL_POLICY_DOWNLOAD, extensions::Manifest::TYPE_EXTENSION, false); service_->AddExtension(ext4.get()); scoped_refptr ext5 = CreateExtension( base::ASCIIToUTF16("example5"), base::FilePath(FILE_PATH_LITERAL("//nonexistent4")), Manifest::EXTERNAL_COMPONENT, extensions::Manifest::TYPE_EXTENSION, false); service_->AddExtension(ext5.get()); scoped_refptr ext6 = CreateExtension( base::ASCIIToUTF16("example6"), base::FilePath(FILE_PATH_LITERAL("//nonexistent5")), Manifest::EXTERNAL_POLICY, extensions::Manifest::TYPE_EXTENSION, false); service_->AddExtension(ext6.get()); EXPECT_EQ(6u, registry()->enabled_extensions().size()); ResetAndWait(ProfileResetter::EXTENSIONS); EXPECT_EQ(4u, registry()->enabled_extensions().size()); EXPECT_FALSE(registry()->enabled_extensions().Contains(theme->id())); EXPECT_FALSE(registry()->enabled_extensions().Contains(ext2->id())); EXPECT_TRUE(registry()->enabled_extensions().Contains(ext3->id())); EXPECT_TRUE(registry()->enabled_extensions().Contains(ext4->id())); EXPECT_TRUE(registry()->enabled_extensions().Contains(ext5->id())); EXPECT_TRUE(registry()->enabled_extensions().Contains(ext6->id())); EXPECT_TRUE(theme_service->UsingDefaultTheme()); } TEST_F(ProfileResetterTest, ResetExtensionsByDisablingNonOrganic) { scoped_refptr ext2 = CreateExtension( base::ASCIIToUTF16("example2"), base::FilePath(FILE_PATH_LITERAL("//nonexistent")), Manifest::INVALID_LOCATION, extensions::Manifest::TYPE_EXTENSION, false); service_->AddExtension(ext2.get()); // Components and external policy extensions shouldn't be deleted. scoped_refptr ext3 = CreateExtension( base::ASCIIToUTF16("example3"), base::FilePath(FILE_PATH_LITERAL("//nonexistent2")), Manifest::INVALID_LOCATION, extensions::Manifest::TYPE_EXTENSION, false); service_->AddExtension(ext3.get()); EXPECT_EQ(2u, registry()->enabled_extensions().size()); std::string master_prefs(kDistributionConfig); ReplaceString(&master_prefs, "placeholder_for_id", ext3->id()); ResetAndWait(ProfileResetter::EXTENSIONS, master_prefs); EXPECT_EQ(1u, registry()->enabled_extensions().size()); EXPECT_TRUE(registry()->enabled_extensions().Contains(ext3->id())); } TEST_F(ProfileResetterTest, ResetExtensionsAndDefaultApps) { service_->Init(); base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); scoped_refptr ext1 = CreateExtension(base::ASCIIToUTF16("example1"), temp_dir.path(), Manifest::INVALID_LOCATION, extensions::Manifest::TYPE_THEME, false); service_->FinishInstallationForTest(ext1.get()); // Let ThemeService finish creating the theme pack. base::MessageLoop::current()->RunUntilIdle(); ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile()); EXPECT_FALSE(theme_service->UsingDefaultTheme()); scoped_refptr ext2 = CreateExtension(base::ASCIIToUTF16("example2"), base::FilePath(FILE_PATH_LITERAL("//nonexistent2")), Manifest::INVALID_LOCATION, extensions::Manifest::TYPE_EXTENSION, false); service_->AddExtension(ext2.get()); scoped_refptr ext3 = CreateExtension(base::ASCIIToUTF16("example2"), base::FilePath(FILE_PATH_LITERAL("//nonexistent3")), Manifest::INVALID_LOCATION, extensions::Manifest::TYPE_HOSTED_APP, true); service_->AddExtension(ext3.get()); EXPECT_EQ(3u, registry()->enabled_extensions().size()); ResetAndWait(ProfileResetter::EXTENSIONS); EXPECT_EQ(1u, registry()->enabled_extensions().size()); EXPECT_FALSE(registry()->enabled_extensions().Contains(ext1->id())); EXPECT_FALSE(registry()->enabled_extensions().Contains(ext2->id())); EXPECT_TRUE(registry()->enabled_extensions().Contains(ext3->id())); EXPECT_TRUE(theme_service->UsingDefaultTheme()); } TEST_F(ProfileResetterTest, ResetStartPageNonOrganic) { PrefService* prefs = profile()->GetPrefs(); DCHECK(prefs); SessionStartupPref startup_pref(SessionStartupPref::LAST); SessionStartupPref::SetStartupPref(prefs, startup_pref); ResetAndWait(ProfileResetter::STARTUP_PAGES, kDistributionConfig); startup_pref = SessionStartupPref::GetStartupPref(prefs); EXPECT_EQ(SessionStartupPref::URLS, startup_pref.type); const GURL urls[] = {GURL("http://goo.gl"), GURL("http://foo.de")}; EXPECT_EQ(std::vector(urls, urls + arraysize(urls)), startup_pref.urls); } TEST_F(ProfileResetterTest, ResetStartPagePartially) { PrefService* prefs = profile()->GetPrefs(); DCHECK(prefs); const GURL urls[] = {GURL("http://foo"), GURL("http://bar")}; SessionStartupPref startup_pref(SessionStartupPref::URLS); startup_pref.urls.assign(urls, urls + arraysize(urls)); SessionStartupPref::SetStartupPref(prefs, startup_pref); ResetAndWait(ProfileResetter::STARTUP_PAGES, std::string()); startup_pref = SessionStartupPref::GetStartupPref(prefs); EXPECT_EQ(SessionStartupPref::GetDefaultStartupType(), startup_pref.type); EXPECT_EQ(std::vector(urls, urls + arraysize(urls)), startup_pref.urls); } TEST_F(PinnedTabsResetTest, ResetPinnedTabs) { scoped_ptr contents1(CreateWebContents()); scoped_ptr contents2(CreateWebContents()); scoped_ptr contents3(CreateWebContents()); scoped_ptr contents4(CreateWebContents()); TabStripModel* tab_strip_model = browser()->tab_strip_model(); tab_strip_model->AppendWebContents(contents4.get(), true); tab_strip_model->AppendWebContents(contents3.get(), true); tab_strip_model->AppendWebContents(contents2.get(), true); tab_strip_model->SetTabPinned(2, true); tab_strip_model->AppendWebContents(contents1.get(), true); tab_strip_model->SetTabPinned(3, true); EXPECT_EQ(contents2.get(), tab_strip_model->GetWebContentsAt(0)); EXPECT_EQ(contents1.get(), tab_strip_model->GetWebContentsAt(1)); EXPECT_EQ(contents4.get(), tab_strip_model->GetWebContentsAt(2)); EXPECT_EQ(contents3.get(), tab_strip_model->GetWebContentsAt(3)); EXPECT_EQ(2, tab_strip_model->IndexOfFirstNonPinnedTab()); ResetAndWait(ProfileResetter::PINNED_TABS); EXPECT_EQ(contents2.get(), tab_strip_model->GetWebContentsAt(0)); EXPECT_EQ(contents1.get(), tab_strip_model->GetWebContentsAt(1)); EXPECT_EQ(contents4.get(), tab_strip_model->GetWebContentsAt(2)); EXPECT_EQ(contents3.get(), tab_strip_model->GetWebContentsAt(3)); EXPECT_EQ(0, tab_strip_model->IndexOfFirstNonPinnedTab()); } TEST_F(ProfileResetterTest, ResetShortcuts) { ShortcutHandler shortcut; ShortcutCommand command_line = shortcut.CreateWithArguments( base::ASCIIToUTF16("chrome.lnk"), base::ASCIIToUTF16("--profile-directory=Default foo.com")); shortcut.CheckShortcutHasArguments(base::ASCIIToUTF16( "--profile-directory=Default foo.com")); ResetAndWait(ProfileResetter::SHORTCUTS); shortcut.CheckShortcutHasArguments(base::ASCIIToUTF16( "--profile-directory=Default")); } TEST_F(ProfileResetterTest, ResetFewFlags) { // mock_object_ is a StrictMock, so we verify that it is called only once. ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE | ProfileResetter::HOMEPAGE | ProfileResetter::CONTENT_SETTINGS); } // Tries to load unavailable config file. TEST_F(ConfigParserTest, NoConnectivity) { const GURL url("http://test"); factory().SetFakeResponse(url, "", net::HTTP_INTERNAL_SERVER_ERROR, net::URLRequestStatus::FAILED); scoped_ptr fetcher = WaitForRequest(GURL(url)); EXPECT_FALSE(fetcher->GetSettings()); } // Tries to load available config file. TEST_F(ConfigParserTest, ParseConfig) { const GURL url("http://test"); std::string xml_config(kXmlConfig); ReplaceString(&xml_config, "placeholder_for_data", kDistributionConfig); ReplaceString(&xml_config, "placeholder_for_id", "abbaabbaabbaabbaabbaabbaabbaabba"); factory().SetFakeResponse(url, xml_config, net::HTTP_OK, net::URLRequestStatus::SUCCESS); scoped_ptr fetcher = WaitForRequest(GURL(url)); scoped_ptr settings = fetcher->GetSettings(); ASSERT_TRUE(settings); std::vector extension_ids; EXPECT_TRUE(settings->GetExtensions(&extension_ids)); EXPECT_EQ(1u, extension_ids.size()); EXPECT_EQ("abbaabbaabbaabbaabbaabbaabbaabba", extension_ids[0]); std::string homepage; EXPECT_TRUE(settings->GetHomepage(&homepage)); EXPECT_EQ("http://www.foo.com", homepage); scoped_ptr startup_list( settings->GetUrlsToRestoreOnStartup()); EXPECT_TRUE(startup_list); std::vector startup_pages; for (base::ListValue::iterator i = startup_list->begin(); i != startup_list->end(); ++i) { std::string url; EXPECT_TRUE((*i)->GetAsString(&url)); startup_pages.push_back(url); } ASSERT_EQ(2u, startup_pages.size()); EXPECT_EQ("http://goo.gl", startup_pages[0]); EXPECT_EQ("http://foo.de", startup_pages[1]); } TEST_F(ProfileResetterTest, CheckSnapshots) { ResettableSettingsSnapshot empty_snap(profile()); EXPECT_EQ(0, empty_snap.FindDifferentFields(empty_snap)); scoped_refptr ext = CreateExtension( base::ASCIIToUTF16("example"), base::FilePath(FILE_PATH_LITERAL("//nonexistent")), Manifest::INVALID_LOCATION, extensions::Manifest::TYPE_EXTENSION, false); ASSERT_TRUE(ext.get()); service_->AddExtension(ext.get()); std::string master_prefs(kDistributionConfig); std::string ext_id = ext->id(); ReplaceString(&master_prefs, "placeholder_for_id", ext_id); // Reset to non organic defaults. ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE | ProfileResetter::HOMEPAGE | ProfileResetter::STARTUP_PAGES, master_prefs); ShortcutHandler shortcut_hijacked; ShortcutCommand command_line = shortcut_hijacked.CreateWithArguments( base::ASCIIToUTF16("chrome1.lnk"), base::ASCIIToUTF16("--profile-directory=Default foo.com")); shortcut_hijacked.CheckShortcutHasArguments( base::ASCIIToUTF16("--profile-directory=Default foo.com")); ShortcutHandler shortcut_ok; shortcut_ok.CreateWithArguments( base::ASCIIToUTF16("chrome2.lnk"), base::ASCIIToUTF16("--profile-directory=Default1")); ResettableSettingsSnapshot nonorganic_snap(profile()); nonorganic_snap.RequestShortcuts(base::Closure()); // Let it enumerate shortcuts on the FILE thread. base::MessageLoop::current()->RunUntilIdle(); int diff_fields = ResettableSettingsSnapshot::ALL_FIELDS; if (!ShortcutHandler::IsSupported()) diff_fields &= ~ResettableSettingsSnapshot::SHORTCUTS; EXPECT_EQ(diff_fields, empty_snap.FindDifferentFields(nonorganic_snap)); empty_snap.Subtract(nonorganic_snap); EXPECT_TRUE(empty_snap.startup_urls().empty()); EXPECT_EQ(SessionStartupPref::GetDefaultStartupType(), empty_snap.startup_type()); EXPECT_TRUE(empty_snap.homepage().empty()); EXPECT_TRUE(empty_snap.homepage_is_ntp()); EXPECT_FALSE(empty_snap.show_home_button()); EXPECT_NE(std::string::npos, empty_snap.dse_url().find("{google:baseURL}")); EXPECT_EQ(ResettableSettingsSnapshot::ExtensionList(), empty_snap.enabled_extensions()); EXPECT_EQ(std::vector(), empty_snap.shortcuts()); // Reset to organic defaults. ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE | ProfileResetter::HOMEPAGE | ProfileResetter::STARTUP_PAGES | ProfileResetter::EXTENSIONS | ProfileResetter::SHORTCUTS); ResettableSettingsSnapshot organic_snap(profile()); organic_snap.RequestShortcuts(base::Closure()); // Let it enumerate shortcuts on the FILE thread. base::MessageLoop::current()->RunUntilIdle(); EXPECT_EQ(diff_fields, nonorganic_snap.FindDifferentFields(organic_snap)); nonorganic_snap.Subtract(organic_snap); const GURL urls[] = {GURL("http://foo.de"), GURL("http://goo.gl")}; EXPECT_EQ(std::vector(urls, urls + arraysize(urls)), nonorganic_snap.startup_urls()); EXPECT_EQ(SessionStartupPref::URLS, nonorganic_snap.startup_type()); EXPECT_EQ("http://www.foo.com", nonorganic_snap.homepage()); EXPECT_FALSE(nonorganic_snap.homepage_is_ntp()); EXPECT_TRUE(nonorganic_snap.show_home_button()); EXPECT_EQ("http://www.foo.com/s?q={searchTerms}", nonorganic_snap.dse_url()); EXPECT_EQ(ResettableSettingsSnapshot::ExtensionList( 1, std::make_pair(ext_id, "example")), nonorganic_snap.enabled_extensions()); if (ShortcutHandler::IsSupported()) { std::vector shortcuts = nonorganic_snap.shortcuts(); ASSERT_EQ(1u, shortcuts.size()); EXPECT_EQ(command_line.first.value(), shortcuts[0].first.value()); EXPECT_EQ(command_line.second, shortcuts[0].second); } } TEST_F(ProfileResetterTest, FeedbackSerializationAsProtoTest) { // Reset to non organic defaults. ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE | ProfileResetter::HOMEPAGE | ProfileResetter::STARTUP_PAGES, kDistributionConfig); scoped_refptr ext = CreateExtension( base::ASCIIToUTF16("example"), base::FilePath(FILE_PATH_LITERAL("//nonexistent")), Manifest::INVALID_LOCATION, extensions::Manifest::TYPE_EXTENSION, false); ASSERT_TRUE(ext.get()); service_->AddExtension(ext.get()); ShortcutHandler shortcut; ShortcutCommand command_line = shortcut.CreateWithArguments( base::ASCIIToUTF16("chrome.lnk"), base::ASCIIToUTF16("--profile-directory=Default foo.com")); ResettableSettingsSnapshot nonorganic_snap(profile()); nonorganic_snap.RequestShortcuts(base::Closure()); // Let it enumerate shortcuts on the FILE thread. base::MessageLoop::current()->RunUntilIdle(); static_assert(ResettableSettingsSnapshot::ALL_FIELDS == 31, "this test needs to be expanded"); for (int field_mask = 0; field_mask <= ResettableSettingsSnapshot::ALL_FIELDS; ++field_mask) { scoped_ptr report = SerializeSettingsReportToProto(nonorganic_snap, field_mask); EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::STARTUP_MODE), report->startup_url_path_size() > 0); EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::STARTUP_MODE), report->has_startup_type()); EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::HOMEPAGE), report->has_homepage_path()); EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::HOMEPAGE), report->has_homepage_is_new_tab_page()); EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::HOMEPAGE), report->has_show_home_button()); EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::DSE_URL), report->has_default_search_engine_path()); EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::EXTENSIONS), report->enabled_extensions_size() > 0); EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::SHORTCUTS) && ShortcutHandler::IsSupported(), report->shortcuts_size() > 0); } } struct FeedbackCapture { void SetFeedback(Profile* profile, const ResettableSettingsSnapshot& snapshot) { list_ = GetReadableFeedbackForSnapshot(profile, snapshot); OnUpdatedList(); } void Fail() { ADD_FAILURE() << "This method shouldn't be called."; } MOCK_METHOD0(OnUpdatedList, void(void)); scoped_ptr list_; }; // Make sure GetReadableFeedback handles non-ascii letters. TEST_F(ProfileResetterTest, GetReadableFeedback) { scoped_refptr ext = CreateExtension( base::WideToUTF16(L"Tiësto"), base::FilePath(FILE_PATH_LITERAL("//nonexistent")), Manifest::INVALID_LOCATION, extensions::Manifest::TYPE_EXTENSION, false); ASSERT_TRUE(ext.get()); service_->AddExtension(ext.get()); PrefService* prefs = profile()->GetPrefs(); DCHECK(prefs); // The URL is "http://россия.рф". std::wstring url(L"http://" L"\u0440\u043e\u0441\u0441\u0438\u044f.\u0440\u0444"); prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false); prefs->SetString(prefs::kHomePage, base::WideToUTF8(url)); SessionStartupPref startup_pref(SessionStartupPref::URLS); startup_pref.urls.push_back(GURL(base::WideToUTF8(url))); SessionStartupPref::SetStartupPref(prefs, startup_pref); ShortcutHandler shortcut; ShortcutCommand command_line = shortcut.CreateWithArguments( base::ASCIIToUTF16("chrome.lnk"), base::ASCIIToUTF16("--profile-directory=Default foo.com")); FeedbackCapture capture; EXPECT_CALL(capture, OnUpdatedList()); ResettableSettingsSnapshot snapshot(profile()); snapshot.RequestShortcuts(base::Bind(&FeedbackCapture::SetFeedback, base::Unretained(&capture), profile(), base::ConstRef(snapshot))); // Let it enumerate shortcuts on the FILE thread. base::MessageLoop::current()->RunUntilIdle(); ::testing::Mock::VerifyAndClearExpectations(&capture); // The homepage and the startup page are in punycode. They are unreadable. // Trying to find the extension name. scoped_ptr list = std::move(capture.list_); ASSERT_TRUE(list); bool checked_extensions = false; bool checked_shortcuts = false; for (size_t i = 0; i < list->GetSize(); ++i) { base::DictionaryValue* dict = NULL; ASSERT_TRUE(list->GetDictionary(i, &dict)); std::string value; ASSERT_TRUE(dict->GetString("key", &value)); if (value == "Extensions") { base::string16 extensions; EXPECT_TRUE(dict->GetString("value", &extensions)); EXPECT_EQ(base::WideToUTF16(L"Tiësto"), extensions); checked_extensions = true; } else if (value == "Shortcut targets") { base::string16 targets; EXPECT_TRUE(dict->GetString("value", &targets)); EXPECT_NE(base::string16::npos, targets.find(base::ASCIIToUTF16("foo.com"))) << targets; checked_shortcuts = true; } } EXPECT_TRUE(checked_extensions); EXPECT_EQ(ShortcutHandler::IsSupported(), checked_shortcuts); } TEST_F(ProfileResetterTest, DestroySnapshotFast) { FeedbackCapture capture; scoped_ptr deleted_snapshot( new ResettableSettingsSnapshot(profile())); deleted_snapshot->RequestShortcuts(base::Bind(&FeedbackCapture::Fail, base::Unretained(&capture))); deleted_snapshot.reset(); // Running remaining tasks shouldn't trigger the callback to be called as // |deleted_snapshot| was deleted before it could run. base::MessageLoop::current()->RunUntilIdle(); } } // namespace