kiosk_app_manager_browsertest.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
1474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org// Copyright 2013 The Chromium Authors. All rights reserved. 2474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org// Use of this source code is governed by a BSD-style license that can be 3474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org// found in the LICENSE file. 4474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org 5474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" 6474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org 7474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "base/at_exit.h" 8474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "base/command_line.h" 9474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "base/message_loop/message_loop.h" 10474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "base/path_service.h" 11474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "base/strings/stringprintf.h" 12474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "base/values.h" 13474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "chrome/browser/browser_process.h" 14474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h" 15474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "chrome/browser/chromeos/policy/device_local_account.h" 16474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "chrome/browser/chromeos/settings/cros_settings.h" 17474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "chrome/browser/chromeos/settings/cros_settings_names.h" 18474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "chrome/browser/policy/browser_policy_connector.h" 19474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "chrome/browser/prefs/scoped_user_pref_update.h" 20474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "chrome/common/chrome_paths.h" 21474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "chrome/common/chrome_switches.h" 22474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "chrome/test/base/in_process_browser_test.h" 23474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "content/public/test/test_utils.h" 24474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "net/base/host_port_pair.h" 25474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org#include "net/dns/mock_host_resolver.h" 26474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org 27474eb7536515fb785e925cc9375d22817c416851hclam@chromium.orgnamespace chromeos { 28474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org 29474eb7536515fb785e925cc9375d22817c416851hclam@chromium.orgnamespace { 30474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org 31474eb7536515fb785e925cc9375d22817c416851hclam@chromium.orgconst char kWebstoreDomain[] = "cws.com"; 32474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org 33474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org// Helper KioskAppManager::GetConsumerKioskModeStatusCallback implementation. 34474eb7536515fb785e925cc9375d22817c416851hclam@chromium.orgvoid ConsumerKioskModeStatusCheck( 35474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org KioskAppManager::ConsumerKioskModeStatus* out_status, 36474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org const base::Closure& runner_quit_task, 37474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org KioskAppManager::ConsumerKioskModeStatus in_status) { 38474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org LOG(INFO) << "ConsumerKioskModeStatus = " << in_status; 39474eb7536515fb785e925cc9375d22817c416851hclam@chromium.org *out_status = in_status; 40 runner_quit_task.Run(); 41} 42 43// Helper KioskAppManager::EnableKioskModeCallback implementation. 44void ConsumerKioskModeLockCheck( 45 bool* out_locked, 46 const base::Closure& runner_quit_task, 47 bool in_locked) { 48 LOG(INFO) << "kioks locked = " << in_locked; 49 *out_locked = in_locked; 50 runner_quit_task.Run(); 51} 52 53// Helper EnterpriseInstallAttributes::LockResultCallback implementation. 54void OnEnterpriseDeviceLock( 55 policy::EnterpriseInstallAttributes::LockResult* out_locked, 56 const base::Closure& runner_quit_task, 57 policy::EnterpriseInstallAttributes::LockResult in_locked) { 58 LOG(INFO) << "Enterprise lock = " << in_locked; 59 *out_locked = in_locked; 60 runner_quit_task.Run(); 61} 62 63class TestKioskAppManagerObserver : public KioskAppManagerObserver { 64 public: 65 explicit TestKioskAppManagerObserver(KioskAppManager* manager) 66 : manager_(manager), 67 data_changed_count_(0), 68 load_failure_count_(0) { 69 manager_->AddObserver(this); 70 } 71 virtual ~TestKioskAppManagerObserver() { 72 manager_->RemoveObserver(this); 73 } 74 75 void Reset() { 76 data_changed_count_ = 0; 77 load_failure_count_ = 0; 78 } 79 80 int data_changed_count() const { return data_changed_count_; } 81 int load_failure_count() const { return load_failure_count_; } 82 83 private: 84 // KioskAppManagerObserver overrides: 85 virtual void OnKioskAppDataChanged(const std::string& app_id) OVERRIDE { 86 ++data_changed_count_; 87 } 88 virtual void OnKioskAppDataLoadFailure(const std::string& app_id) OVERRIDE { 89 ++load_failure_count_; 90 } 91 92 KioskAppManager* manager_; 93 int data_changed_count_; 94 int load_failure_count_; 95 96 DISALLOW_COPY_AND_ASSIGN(TestKioskAppManagerObserver); 97}; 98 99class AppDataLoadWaiter : public KioskAppManagerObserver { 100 public: 101 explicit AppDataLoadWaiter(KioskAppManager* manager) 102 : manager_(manager), 103 loaded_(false) { 104 manager_->AddObserver(this); 105 } 106 virtual ~AppDataLoadWaiter() { 107 manager_->RemoveObserver(this); 108 } 109 110 void Wait() { 111 base::MessageLoop::current()->Run(); 112 } 113 114 bool loaded() const { return loaded_; } 115 116 private: 117 // KioskAppManagerObserver overrides: 118 virtual void OnKioskAppDataChanged(const std::string& app_id) OVERRIDE { 119 loaded_ = true; 120 base::MessageLoop::current()->Quit(); 121 } 122 virtual void OnKioskAppDataLoadFailure(const std::string& app_id) OVERRIDE { 123 loaded_ = false; 124 base::MessageLoop::current()->Quit(); 125 } 126 127 KioskAppManager* manager_; 128 bool loaded_; 129 130 DISALLOW_COPY_AND_ASSIGN(AppDataLoadWaiter); 131}; 132 133} // namespace 134 135class KioskAppManagerTest : public InProcessBrowserTest { 136 public: 137 KioskAppManagerTest() {} 138 virtual ~KioskAppManagerTest() {} 139 140 // InProcessBrowserTest overrides: 141 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 142 // We start the test server now instead of in 143 // SetUpInProcessBrowserTestFixture so that we can get its port number. 144 ASSERT_TRUE(test_server()->Start()); 145 146 net::HostPortPair host_port = test_server()->host_port_pair(); 147 test_gallery_url_ = base::StringPrintf( 148 "http://%s:%d/files/chromeos/app_mode/webstore", 149 kWebstoreDomain, host_port.port()); 150 151 command_line->AppendSwitchASCII( 152 switches::kAppsGalleryURL, test_gallery_url_); 153 } 154 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 155 host_resolver()->AddRule(kWebstoreDomain, "127.0.0.1"); 156 } 157 158 std::string GetAppIds() const { 159 KioskAppManager::Apps apps; 160 manager()->GetApps(&apps); 161 162 std::string str; 163 for (size_t i = 0; i < apps.size(); ++i) { 164 if (i > 0) 165 str += ','; 166 str += apps[i].app_id; 167 } 168 169 return str; 170 } 171 172 KioskAppManager* manager() const { return KioskAppManager::Get(); } 173 174 // Locks device for enterprise. 175 policy::EnterpriseInstallAttributes::LockResult LockDeviceForEnterprise() { 176 scoped_ptr<policy::EnterpriseInstallAttributes::LockResult> lock_result( 177 new policy::EnterpriseInstallAttributes::LockResult( 178 policy::EnterpriseInstallAttributes::LOCK_NOT_READY)); 179 scoped_refptr<content::MessageLoopRunner> runner = 180 new content::MessageLoopRunner; 181 g_browser_process->browser_policy_connector()->GetInstallAttributes()-> 182 LockDevice( 183 "user@domain.com", 184 policy::DEVICE_MODE_ENTERPRISE, 185 "device-id", 186 base::Bind(&OnEnterpriseDeviceLock, 187 lock_result.get(), 188 runner->QuitClosure())); 189 runner->Run(); 190 return *lock_result.get(); 191 } 192 193 private: 194 std::string test_gallery_url_; 195 base::ShadowingAtExitManager exit_manager_; 196 197 DISALLOW_COPY_AND_ASSIGN(KioskAppManagerTest); 198}; 199 200IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, Basic) { 201 // Add a couple of apps. Use "fake_app_x" that do not have data on the test 202 // server to avoid pending data loads that could be lingering on tear down and 203 // cause DCHECK failure in utility_process_host_impl.cc. 204 manager()->AddApp("fake_app_1"); 205 manager()->AddApp("fake_app_2"); 206 EXPECT_EQ("fake_app_1,fake_app_2", GetAppIds()); 207 208 // Set an auto launch app. 209 manager()->SetAutoLaunchApp("fake_app_1"); 210 EXPECT_EQ("fake_app_1", manager()->GetAutoLaunchApp()); 211 212 // Clear the auto launch app. 213 manager()->SetAutoLaunchApp(""); 214 EXPECT_EQ("", manager()->GetAutoLaunchApp()); 215 EXPECT_FALSE(manager()->IsAutoLaunchEnabled()); 216 217 // Set another auto launch app. 218 manager()->SetAutoLaunchApp("fake_app_2"); 219 EXPECT_EQ("fake_app_2", manager()->GetAutoLaunchApp()); 220 221 // Check auto launch permissions. 222 EXPECT_FALSE(manager()->IsAutoLaunchEnabled()); 223 manager()->SetEnableAutoLaunch(true); 224 EXPECT_TRUE(manager()->IsAutoLaunchEnabled()); 225 226 // Remove the auto launch app. 227 manager()->RemoveApp("fake_app_2"); 228 EXPECT_EQ("fake_app_1", GetAppIds()); 229 EXPECT_EQ("", manager()->GetAutoLaunchApp()); 230 231 // Set a none exist app as auto launch. 232 manager()->SetAutoLaunchApp("none_exist_app"); 233 EXPECT_EQ("", manager()->GetAutoLaunchApp()); 234 EXPECT_FALSE(manager()->IsAutoLaunchEnabled()); 235 236 // Add an existing app again. 237 manager()->AddApp("fake_app_1"); 238 EXPECT_EQ("fake_app_1", GetAppIds()); 239} 240 241IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, LoadCached) { 242 base::FilePath test_dir; 243 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); 244 base::FilePath data_dir = test_dir.AppendASCII("chromeos/app_mode/"); 245 246 scoped_ptr<base::DictionaryValue> apps_dict(new base::DictionaryValue); 247 apps_dict->SetString("app_1.name", "App1 Name"); 248 std::string icon_path = 249 base::StringPrintf("%s/red16x16.png", data_dir.value().c_str()); 250 apps_dict->SetString("app_1.icon", icon_path); 251 252 PrefService* local_state = g_browser_process->local_state(); 253 DictionaryPrefUpdate dict_update(local_state, 254 KioskAppManager::kKioskDictionaryName); 255 dict_update->Set(KioskAppManager::kKeyApps, apps_dict.release()); 256 257 // Make the app appear in device settings. 258 base::ListValue device_local_accounts; 259 scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue); 260 entry->SetStringWithoutPathExpansion( 261 kAccountsPrefDeviceLocalAccountsKeyId, 262 "app_1_id"); 263 entry->SetIntegerWithoutPathExpansion( 264 kAccountsPrefDeviceLocalAccountsKeyType, 265 policy::DeviceLocalAccount::TYPE_KIOSK_APP); 266 entry->SetStringWithoutPathExpansion( 267 kAccountsPrefDeviceLocalAccountsKeyKioskAppId, 268 "app_1"); 269 device_local_accounts.Append(entry.release()); 270 CrosSettings::Get()->Set(kAccountsPrefDeviceLocalAccounts, 271 device_local_accounts); 272 273 AppDataLoadWaiter waiter(manager()); 274 waiter.Wait(); 275 EXPECT_TRUE(waiter.loaded()); 276 277 KioskAppManager::Apps apps; 278 manager()->GetApps(&apps); 279 EXPECT_EQ(1u, apps.size()); 280 EXPECT_EQ("app_1", apps[0].app_id); 281 EXPECT_EQ("App1 Name", apps[0].name); 282 EXPECT_EQ(gfx::Size(16, 16), apps[0].icon.size()); 283} 284 285IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, BadApp) { 286 manager()->AddApp("unknown_app"); 287 288 TestKioskAppManagerObserver observer(manager()); 289 290 AppDataLoadWaiter waiter(manager()); 291 waiter.Wait(); 292 EXPECT_FALSE(waiter.loaded()); 293 294 EXPECT_EQ("", GetAppIds()); 295 EXPECT_EQ(1, observer.load_failure_count()); 296} 297 298IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, GoodApp) { 299 // Webstore data json is in 300 // chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/app_1 301 manager()->AddApp("app_1"); 302 303 AppDataLoadWaiter waiter(manager()); 304 waiter.Wait(); 305 EXPECT_TRUE(waiter.loaded()); 306 307 // Check data is correct. 308 KioskAppManager::Apps apps; 309 manager()->GetApps(&apps); 310 EXPECT_EQ(1u, apps.size()); 311 EXPECT_EQ("app_1", apps[0].app_id); 312 EXPECT_EQ("Name of App 1", apps[0].name); 313 EXPECT_EQ(gfx::Size(16, 16), apps[0].icon.size()); 314 315 // Check data is cached in local state. 316 PrefService* local_state = g_browser_process->local_state(); 317 const base::DictionaryValue* dict = 318 local_state->GetDictionary(KioskAppManager::kKioskDictionaryName); 319 320 std::string name; 321 EXPECT_TRUE(dict->GetString("apps.app_1.name", &name)); 322 EXPECT_EQ(apps[0].name, name); 323 324 std::string icon_path_string; 325 EXPECT_TRUE(dict->GetString("apps.app_1.icon", &icon_path_string)); 326 327 base::FilePath expected_icon_path; 328 ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &expected_icon_path)); 329 expected_icon_path = expected_icon_path. 330 AppendASCII(KioskAppManager::kIconCacheDir). 331 AppendASCII(apps[0].app_id).AddExtension(".png"); 332 EXPECT_EQ(expected_icon_path.value(), icon_path_string); 333} 334 335IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, EnableConsumerKiosk) { 336 scoped_ptr<KioskAppManager::ConsumerKioskModeStatus> status( 337 new KioskAppManager::ConsumerKioskModeStatus( 338 KioskAppManager::CONSUMER_KIOSK_MODE_DISABLED)); 339 scoped_ptr<bool> locked(new bool(false)); 340 341 scoped_refptr<content::MessageLoopRunner> runner = 342 new content::MessageLoopRunner; 343 manager()->GetConsumerKioskModeStatus( 344 base::Bind(&ConsumerKioskModeStatusCheck, 345 status.get(), 346 runner->QuitClosure())); 347 runner->Run(); 348 EXPECT_EQ(*status.get(), KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE); 349 350 scoped_refptr<content::MessageLoopRunner> runner2 = 351 new content::MessageLoopRunner; 352 manager()->EnableConsumerModeKiosk( 353 base::Bind(&ConsumerKioskModeLockCheck, 354 locked.get(), 355 runner2->QuitClosure())); 356 runner2->Run(); 357 EXPECT_TRUE(*locked.get()); 358 359 scoped_refptr<content::MessageLoopRunner> runner3 = 360 new content::MessageLoopRunner; 361 manager()->GetConsumerKioskModeStatus( 362 base::Bind(&ConsumerKioskModeStatusCheck, 363 status.get(), 364 runner3->QuitClosure())); 365 runner3->Run(); 366 EXPECT_EQ(*status.get(), KioskAppManager::CONSUMER_KIOSK_MODE_ENABLED); 367} 368 369IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, 370 PreventEnableConsumerKioskForEnterprise) { 371 // First, lock the device as enterprise. 372 EXPECT_EQ(LockDeviceForEnterprise(), 373 policy::EnterpriseInstallAttributes::LOCK_SUCCESS); 374 375 scoped_ptr<KioskAppManager::ConsumerKioskModeStatus> status( 376 new KioskAppManager::ConsumerKioskModeStatus( 377 KioskAppManager::CONSUMER_KIOSK_MODE_DISABLED)); 378 scoped_ptr<bool> locked(new bool(true)); 379 380 scoped_refptr<content::MessageLoopRunner> runner = 381 new content::MessageLoopRunner; 382 manager()->GetConsumerKioskModeStatus( 383 base::Bind(&ConsumerKioskModeStatusCheck, 384 status.get(), 385 runner->QuitClosure())); 386 runner->Run(); 387 EXPECT_EQ(*status.get(), KioskAppManager::CONSUMER_KIOSK_MODE_DISABLED); 388 389 scoped_refptr<content::MessageLoopRunner> runner2 = 390 new content::MessageLoopRunner; 391 manager()->EnableConsumerModeKiosk( 392 base::Bind(&ConsumerKioskModeLockCheck, 393 locked.get(), 394 runner2->QuitClosure())); 395 runner2->Run(); 396 EXPECT_FALSE(*locked.get()); 397 398 scoped_refptr<content::MessageLoopRunner> runner3 = 399 new content::MessageLoopRunner; 400 manager()->GetConsumerKioskModeStatus( 401 base::Bind(&ConsumerKioskModeStatusCheck, 402 status.get(), 403 runner3->QuitClosure())); 404 runner3->Run(); 405 EXPECT_EQ(*status.get(), KioskAppManager::CONSUMER_KIOSK_MODE_DISABLED); 406} 407 408} // namespace chromeos 409