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 "chrome/browser/themes/theme_service.h" 6 7#include "base/files/file_util.h" 8#include "base/path_service.h" 9#include "chrome/browser/chrome_notification_types.h" 10#include "chrome/browser/extensions/extension_service.h" 11#include "chrome/browser/extensions/extension_service_test_base.h" 12#include "chrome/browser/extensions/unpacked_installer.h" 13#include "chrome/browser/supervised_user/supervised_user_service.h" 14#include "chrome/browser/supervised_user/supervised_user_service_factory.h" 15#include "chrome/browser/themes/custom_theme_supplier.h" 16#include "chrome/browser/themes/theme_service_factory.h" 17#include "chrome/common/chrome_paths.h" 18#include "chrome/common/pref_names.h" 19#include "chrome/test/base/testing_browser_process.h" 20#include "chrome/test/base/testing_profile.h" 21#include "chrome/test/base/testing_profile_manager.h" 22#include "content/public/test/test_utils.h" 23#include "extensions/browser/extension_registry.h" 24#include "extensions/browser/uninstall_reason.h" 25#include "extensions/common/extension.h" 26#include "testing/gtest/include/gtest/gtest.h" 27 28using extensions::ExtensionRegistry; 29 30namespace theme_service_internal { 31 32class ThemeServiceTest : public extensions::ExtensionServiceTestBase { 33 public: 34 ThemeServiceTest() : is_supervised_(false), 35 registry_(NULL) {} 36 virtual ~ThemeServiceTest() {} 37 38 // Moves a minimal theme to |temp_dir_path| and unpacks it from that 39 // directory. 40 std::string LoadUnpackedThemeAt(const base::FilePath& temp_dir) { 41 base::FilePath dst_manifest_path = temp_dir.AppendASCII("manifest.json"); 42 base::FilePath test_data_dir; 43 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir)); 44 base::FilePath src_manifest_path = 45 test_data_dir.AppendASCII("extensions/theme_minimal/manifest.json"); 46 EXPECT_TRUE(base::CopyFile(src_manifest_path, dst_manifest_path)); 47 48 scoped_refptr<extensions::UnpackedInstaller> installer( 49 extensions::UnpackedInstaller::Create(service_)); 50 content::WindowedNotificationObserver observer( 51 extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, 52 content::Source<Profile>(profile_.get())); 53 installer->Load(temp_dir); 54 observer.Wait(); 55 56 std::string extension_id = 57 content::Details<extensions::Extension>(observer.details())->id(); 58 59 // Let the ThemeService finish creating the theme pack. 60 base::MessageLoop::current()->RunUntilIdle(); 61 62 return extension_id; 63 } 64 65 // Update the theme with |extension_id|. 66 void UpdateUnpackedTheme(const std::string& extension_id) { 67 int updated_notification = 68 service_->IsExtensionEnabled(extension_id) 69 ? extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED 70 : extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED; 71 72 const base::FilePath& path = 73 service_->GetInstalledExtension(extension_id)->path(); 74 75 scoped_refptr<extensions::UnpackedInstaller> installer( 76 extensions::UnpackedInstaller::Create(service_)); 77 content::WindowedNotificationObserver observer(updated_notification, 78 content::Source<Profile>(profile_.get())); 79 installer->Load(path); 80 observer.Wait(); 81 82 // Let the ThemeService finish creating the theme pack. 83 base::MessageLoop::current()->RunUntilIdle(); 84 } 85 86 virtual void SetUp() { 87 extensions::ExtensionServiceTestBase::SetUp(); 88 extensions::ExtensionServiceTestBase::ExtensionServiceInitParams params = 89 CreateDefaultInitParams(); 90 params.profile_is_supervised = is_supervised_; 91 InitializeExtensionService(params); 92 service_->Init(); 93 registry_ = ExtensionRegistry::Get(profile_.get()); 94 ASSERT_TRUE(registry_); 95 } 96 97 const CustomThemeSupplier* get_theme_supplier(ThemeService* theme_service) { 98 return theme_service->get_theme_supplier(); 99 } 100 101 protected: 102 bool is_supervised_; 103 ExtensionRegistry* registry_; 104 105}; 106 107// Installs then uninstalls a theme and makes sure that the ThemeService 108// reverts to the default theme after the uninstall. 109TEST_F(ThemeServiceTest, ThemeInstallUninstall) { 110 ThemeService* theme_service = 111 ThemeServiceFactory::GetForProfile(profile_.get()); 112 theme_service->UseDefaultTheme(); 113 // Let the ThemeService uninstall unused themes. 114 base::MessageLoop::current()->RunUntilIdle(); 115 116 base::ScopedTempDir temp_dir; 117 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 118 const std::string& extension_id = LoadUnpackedThemeAt(temp_dir.path()); 119 EXPECT_FALSE(theme_service->UsingDefaultTheme()); 120 EXPECT_EQ(extension_id, theme_service->GetThemeID()); 121 122 // Now uninstall the extension, should revert to the default theme. 123 service_->UninstallExtension(extension_id, 124 extensions::UNINSTALL_REASON_FOR_TESTING, 125 base::Bind(&base::DoNothing), 126 NULL); 127 EXPECT_TRUE(theme_service->UsingDefaultTheme()); 128} 129 130// Test that a theme extension is disabled when not in use. A theme may be 131// installed but not in use if it there is an infobar to revert to the previous 132// theme. 133TEST_F(ThemeServiceTest, DisableUnusedTheme) { 134 ThemeService* theme_service = 135 ThemeServiceFactory::GetForProfile(profile_.get()); 136 theme_service->UseDefaultTheme(); 137 // Let the ThemeService uninstall unused themes. 138 base::MessageLoop::current()->RunUntilIdle(); 139 140 base::ScopedTempDir temp_dir1; 141 ASSERT_TRUE(temp_dir1.CreateUniqueTempDir()); 142 base::ScopedTempDir temp_dir2; 143 ASSERT_TRUE(temp_dir2.CreateUniqueTempDir()); 144 145 // 1) Installing a theme should disable the previously active theme. 146 const std::string& extension1_id = LoadUnpackedThemeAt(temp_dir1.path()); 147 EXPECT_FALSE(theme_service->UsingDefaultTheme()); 148 EXPECT_EQ(extension1_id, theme_service->GetThemeID()); 149 EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id)); 150 151 // Show an infobar to prevent the current theme from being uninstalled. 152 theme_service->OnInfobarDisplayed(); 153 154 const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.path()); 155 EXPECT_EQ(extension2_id, theme_service->GetThemeID()); 156 EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id)); 157 EXPECT_TRUE(registry_->GetExtensionById(extension1_id, 158 ExtensionRegistry::DISABLED)); 159 160 // 2) Enabling a disabled theme extension should swap the current theme. 161 service_->EnableExtension(extension1_id); 162 base::MessageLoop::current()->RunUntilIdle(); 163 EXPECT_EQ(extension1_id, theme_service->GetThemeID()); 164 EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id)); 165 EXPECT_TRUE(registry_->GetExtensionById(extension2_id, 166 ExtensionRegistry::DISABLED)); 167 168 // 3) Using SetTheme() with a disabled theme should enable and set the 169 // theme. This is the case when the user reverts to the previous theme 170 // via an infobar. 171 const extensions::Extension* extension2 = 172 service_->GetInstalledExtension(extension2_id); 173 theme_service->SetTheme(extension2); 174 base::MessageLoop::current()->RunUntilIdle(); 175 EXPECT_EQ(extension2_id, theme_service->GetThemeID()); 176 EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id)); 177 EXPECT_TRUE(registry_->GetExtensionById(extension1_id, 178 ExtensionRegistry::DISABLED)); 179 180 // 4) Disabling the current theme extension should revert to the default theme 181 // and uninstall any installed theme extensions. 182 theme_service->OnInfobarDestroyed(); 183 EXPECT_FALSE(theme_service->UsingDefaultTheme()); 184 service_->DisableExtension(extension2_id, 185 extensions::Extension::DISABLE_USER_ACTION); 186 base::MessageLoop::current()->RunUntilIdle(); 187 EXPECT_TRUE(theme_service->UsingDefaultTheme()); 188 EXPECT_FALSE(service_->GetInstalledExtension(extension1_id)); 189 EXPECT_FALSE(service_->GetInstalledExtension(extension2_id)); 190} 191 192// Test the ThemeService's behavior when a theme is upgraded. 193TEST_F(ThemeServiceTest, ThemeUpgrade) { 194 // Setup. 195 ThemeService* theme_service = 196 ThemeServiceFactory::GetForProfile(profile_.get()); 197 theme_service->UseDefaultTheme(); 198 // Let the ThemeService uninstall unused themes. 199 base::MessageLoop::current()->RunUntilIdle(); 200 201 theme_service->OnInfobarDisplayed(); 202 203 base::ScopedTempDir temp_dir1; 204 ASSERT_TRUE(temp_dir1.CreateUniqueTempDir()); 205 base::ScopedTempDir temp_dir2; 206 ASSERT_TRUE(temp_dir2.CreateUniqueTempDir()); 207 208 const std::string& extension1_id = LoadUnpackedThemeAt(temp_dir1.path()); 209 const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.path()); 210 211 // Test the initial state. 212 EXPECT_TRUE(registry_->GetExtensionById(extension1_id, 213 ExtensionRegistry::DISABLED)); 214 EXPECT_EQ(extension2_id, theme_service->GetThemeID()); 215 216 // 1) Upgrading the current theme should not revert to the default theme. 217 content::WindowedNotificationObserver theme_change_observer( 218 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, 219 content::Source<ThemeService>(theme_service)); 220 UpdateUnpackedTheme(extension2_id); 221 222 // The ThemeService should have sent an theme change notification even though 223 // the id of the current theme did not change. 224 theme_change_observer.Wait(); 225 226 EXPECT_EQ(extension2_id, theme_service->GetThemeID()); 227 EXPECT_TRUE(registry_->GetExtensionById(extension1_id, 228 ExtensionRegistry::DISABLED)); 229 230 // 2) Upgrading a disabled theme should not change the current theme. 231 UpdateUnpackedTheme(extension1_id); 232 EXPECT_EQ(extension2_id, theme_service->GetThemeID()); 233 EXPECT_TRUE(registry_->GetExtensionById(extension1_id, 234 ExtensionRegistry::DISABLED)); 235} 236 237class ThemeServiceSupervisedUserTest : public ThemeServiceTest { 238 public: 239 ThemeServiceSupervisedUserTest() {} 240 virtual ~ThemeServiceSupervisedUserTest() {} 241 242 virtual void SetUp() OVERRIDE { 243 is_supervised_ = true; 244 ThemeServiceTest::SetUp(); 245 } 246}; 247 248// Checks that supervised users have their own default theme. 249TEST_F(ThemeServiceSupervisedUserTest, 250 SupervisedUserThemeReplacesDefaultTheme) { 251 ThemeService* theme_service = 252 ThemeServiceFactory::GetForProfile(profile_.get()); 253 theme_service->UseDefaultTheme(); 254 EXPECT_TRUE(theme_service->UsingDefaultTheme()); 255 EXPECT_TRUE(get_theme_supplier(theme_service)); 256 EXPECT_EQ(get_theme_supplier(theme_service)->get_theme_type(), 257 CustomThemeSupplier::SUPERVISED_USER_THEME); 258} 259 260#if defined(OS_LINUX) && !defined(OS_CHROMEOS) 261// Checks that supervised users don't use the system theme even if it is the 262// default. The system theme is only available on Linux. 263TEST_F(ThemeServiceSupervisedUserTest, SupervisedUserThemeReplacesNativeTheme) { 264 profile_->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, true); 265 ThemeService* theme_service = 266 ThemeServiceFactory::GetForProfile(profile_.get()); 267 theme_service->UseDefaultTheme(); 268 EXPECT_TRUE(theme_service->UsingDefaultTheme()); 269 EXPECT_TRUE(get_theme_supplier(theme_service)); 270 EXPECT_EQ(get_theme_supplier(theme_service)->get_theme_type(), 271 CustomThemeSupplier::SUPERVISED_USER_THEME); 272} 273#endif 274 275}; // namespace theme_service_internal 276