Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / app_mode / kiosk_app_manager_browsertest.cc
blob8fe5ca4c27b12e0ad4293205089e505b6929a04f
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.
5 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
7 #include "base/command_line.h"
8 #include "base/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/path_service.h"
12 #include "base/prefs/scoped_user_pref_update.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
17 #include "chrome/browser/chromeos/policy/device_local_account.h"
18 #include "chrome/browser/chromeos/settings/cros_settings.h"
19 #include "chrome/browser/policy/browser_policy_connector.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/common/chrome_paths.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/test/base/in_process_browser_test.h"
24 #include "chromeos/settings/cros_settings_names.h"
25 #include "content/public/test/test_utils.h"
26 #include "extensions/common/extension.h"
27 #include "net/base/host_port_pair.h"
28 #include "net/dns/mock_host_resolver.h"
29 #include "net/test/embedded_test_server/embedded_test_server.h"
31 namespace chromeos {
33 namespace {
35 const char kWebstoreDomain[] = "cws.com";
37 // Helper KioskAppManager::GetConsumerKioskModeStatusCallback implementation.
38 void ConsumerKioskModeStatusCheck(
39 KioskAppManager::ConsumerKioskModeStatus* out_status,
40 const base::Closure& runner_quit_task,
41 KioskAppManager::ConsumerKioskModeStatus in_status) {
42 LOG(INFO) << "ConsumerKioskModeStatus = " << in_status;
43 *out_status = in_status;
44 runner_quit_task.Run();
47 // Helper KioskAppManager::EnableKioskModeCallback implementation.
48 void ConsumerKioskModeLockCheck(
49 bool* out_locked,
50 const base::Closure& runner_quit_task,
51 bool in_locked) {
52 LOG(INFO) << "kioks locked = " << in_locked;
53 *out_locked = in_locked;
54 runner_quit_task.Run();
57 // Helper EnterpriseInstallAttributes::LockResultCallback implementation.
58 void OnEnterpriseDeviceLock(
59 policy::EnterpriseInstallAttributes::LockResult* out_locked,
60 const base::Closure& runner_quit_task,
61 policy::EnterpriseInstallAttributes::LockResult in_locked) {
62 LOG(INFO) << "Enterprise lock = " << in_locked;
63 *out_locked = in_locked;
64 runner_quit_task.Run();
67 scoped_refptr<extensions::Extension> MakeApp(const std::string& name,
68 const std::string& version,
69 const std::string& url,
70 const std::string& id) {
71 std::string err;
72 base::DictionaryValue value;
73 value.SetString("name", name);
74 value.SetString("version", version);
75 value.SetString("app.launch.web_url", url);
76 scoped_refptr<extensions::Extension> app =
77 extensions::Extension::Create(
78 base::FilePath(),
79 extensions::Manifest::INTERNAL,
80 value,
81 extensions::Extension::WAS_INSTALLED_BY_DEFAULT,
82 id,
83 &err);
84 EXPECT_EQ(err, "");
85 return app;
88 class TestKioskAppManagerObserver : public KioskAppManagerObserver {
89 public:
90 explicit TestKioskAppManagerObserver(KioskAppManager* manager)
91 : manager_(manager),
92 data_changed_count_(0),
93 load_failure_count_(0) {
94 manager_->AddObserver(this);
96 virtual ~TestKioskAppManagerObserver() {
97 manager_->RemoveObserver(this);
100 void Reset() {
101 data_changed_count_ = 0;
102 load_failure_count_ = 0;
105 int data_changed_count() const { return data_changed_count_; }
106 int load_failure_count() const { return load_failure_count_; }
108 private:
109 // KioskAppManagerObserver overrides:
110 virtual void OnKioskAppDataChanged(const std::string& app_id) OVERRIDE {
111 ++data_changed_count_;
113 virtual void OnKioskAppDataLoadFailure(const std::string& app_id) OVERRIDE {
114 ++load_failure_count_;
117 KioskAppManager* manager_;
118 int data_changed_count_;
119 int load_failure_count_;
121 DISALLOW_COPY_AND_ASSIGN(TestKioskAppManagerObserver);
124 class AppDataLoadWaiter : public KioskAppManagerObserver {
125 public:
126 explicit AppDataLoadWaiter(KioskAppManager* manager)
127 : manager_(manager),
128 loaded_(false) {
131 virtual ~AppDataLoadWaiter() {
134 void Wait() {
135 manager_->AddObserver(this);
136 runner_ = new content::MessageLoopRunner;
137 runner_->Run();
138 manager_->RemoveObserver(this);
141 bool loaded() const { return loaded_; }
143 private:
144 // KioskAppManagerObserver overrides:
145 virtual void OnKioskAppDataChanged(const std::string& app_id) OVERRIDE {
146 loaded_ = true;
147 runner_->Quit();
150 virtual void OnKioskAppDataLoadFailure(const std::string& app_id) OVERRIDE {
151 loaded_ = false;
152 runner_->Quit();
155 scoped_refptr<content::MessageLoopRunner> runner_;
156 KioskAppManager* manager_;
157 bool loaded_;
159 DISALLOW_COPY_AND_ASSIGN(AppDataLoadWaiter);
162 } // namespace
164 class KioskAppManagerTest : public InProcessBrowserTest {
165 public:
166 KioskAppManagerTest() {}
167 virtual ~KioskAppManagerTest() {}
169 // InProcessBrowserTest overrides:
170 virtual void SetUp() OVERRIDE {
171 base::FilePath test_data_dir;
172 PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
173 base::FilePath webstore_dir =
174 test_data_dir.Append(FILE_PATH_LITERAL("chromeos/app_mode/"));
175 embedded_test_server()->ServeFilesFromDirectory(webstore_dir);
176 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
177 // Stop IO thread here because no threads are allowed while
178 // spawning sandbox host process. See crbug.com/322732.
179 embedded_test_server()->StopThread();
181 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
183 InProcessBrowserTest::SetUp();
186 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
187 InProcessBrowserTest::SetUpCommandLine(command_line);
189 // Get fake webstore gallery URL. At the end, it should look something like
190 // http://cws.com:<test_server_port>/webstore.
191 const GURL& server_url = embedded_test_server()->base_url();
192 std::string google_host(kWebstoreDomain);
193 GURL::Replacements replace_google_host;
194 replace_google_host.SetHostStr(google_host);
195 GURL google_url = server_url.ReplaceComponents(replace_google_host);
196 GURL fake_store_url = google_url.Resolve("/webstore");
197 command_line->AppendSwitchASCII(switches::kAppsGalleryURL,
198 fake_store_url.spec());
201 virtual void SetUpOnMainThread() OVERRIDE {
202 InProcessBrowserTest::SetUpOnMainThread();
204 // Restart the thread as the sandbox host process has already been spawned.
205 embedded_test_server()->RestartThreadAndListen();
208 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
209 InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
211 host_resolver()->AddRule(kWebstoreDomain, "127.0.0.1");
214 std::string GetAppIds() const {
215 KioskAppManager::Apps apps;
216 manager()->GetApps(&apps);
218 std::string str;
219 for (size_t i = 0; i < apps.size(); ++i) {
220 if (i > 0)
221 str += ',';
222 str += apps[i].app_id;
225 return str;
228 // Locks device for enterprise.
229 policy::EnterpriseInstallAttributes::LockResult LockDeviceForEnterprise() {
230 scoped_ptr<policy::EnterpriseInstallAttributes::LockResult> lock_result(
231 new policy::EnterpriseInstallAttributes::LockResult(
232 policy::EnterpriseInstallAttributes::LOCK_NOT_READY));
233 scoped_refptr<content::MessageLoopRunner> runner =
234 new content::MessageLoopRunner;
235 g_browser_process->browser_policy_connector()->GetInstallAttributes()->
236 LockDevice(
237 "user@domain.com",
238 policy::DEVICE_MODE_ENTERPRISE,
239 "device-id",
240 base::Bind(&OnEnterpriseDeviceLock,
241 lock_result.get(),
242 runner->QuitClosure()));
243 runner->Run();
244 return *lock_result.get();
247 void SetExistingApp(const std::string& app_id,
248 const std::string& app_name,
249 const std::string& icon_file_name) {
250 base::FilePath test_dir;
251 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
252 base::FilePath data_dir = test_dir.AppendASCII("chromeos/app_mode/");
254 // Copy the icon file to temp dir for using because ClearAppData test
255 // deletes it.
256 base::FilePath icon_path = temp_dir_.path().AppendASCII(icon_file_name);
257 base::CopyFile(data_dir.AppendASCII(icon_file_name), icon_path);
259 scoped_ptr<base::DictionaryValue> apps_dict(new base::DictionaryValue);
260 apps_dict->SetString(app_id + ".name", app_name);
261 apps_dict->SetString(app_id + ".icon", icon_path.MaybeAsASCII());
263 PrefService* local_state = g_browser_process->local_state();
264 DictionaryPrefUpdate dict_update(local_state,
265 KioskAppManager::kKioskDictionaryName);
266 dict_update->Set(KioskAppManager::kKeyApps, apps_dict.release());
268 // Make the app appear in device settings.
269 base::ListValue device_local_accounts;
270 scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue);
271 entry->SetStringWithoutPathExpansion(
272 kAccountsPrefDeviceLocalAccountsKeyId,
273 app_id + "_id");
274 entry->SetIntegerWithoutPathExpansion(
275 kAccountsPrefDeviceLocalAccountsKeyType,
276 policy::DeviceLocalAccount::TYPE_KIOSK_APP);
277 entry->SetStringWithoutPathExpansion(
278 kAccountsPrefDeviceLocalAccountsKeyKioskAppId,
279 app_id);
280 device_local_accounts.Append(entry.release());
281 CrosSettings::Get()->Set(kAccountsPrefDeviceLocalAccounts,
282 device_local_accounts);
285 KioskAppManager* manager() const { return KioskAppManager::Get(); }
287 private:
288 base::ScopedTempDir temp_dir_;
290 DISALLOW_COPY_AND_ASSIGN(KioskAppManagerTest);
293 IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, Basic) {
294 // Add a couple of apps. Use "fake_app_x" that do not have data on the test
295 // server to avoid pending data loads that could be lingering on tear down and
296 // cause DCHECK failure in utility_process_host_impl.cc.
297 manager()->AddApp("fake_app_1");
298 manager()->AddApp("fake_app_2");
299 EXPECT_EQ("fake_app_1,fake_app_2", GetAppIds());
301 // Set an auto launch app.
302 manager()->SetAutoLaunchApp("fake_app_1");
303 EXPECT_EQ("fake_app_1", manager()->GetAutoLaunchApp());
305 // Clear the auto launch app.
306 manager()->SetAutoLaunchApp("");
307 EXPECT_EQ("", manager()->GetAutoLaunchApp());
308 EXPECT_FALSE(manager()->IsAutoLaunchEnabled());
310 // Set another auto launch app.
311 manager()->SetAutoLaunchApp("fake_app_2");
312 EXPECT_EQ("fake_app_2", manager()->GetAutoLaunchApp());
314 // Check auto launch permissions.
315 EXPECT_FALSE(manager()->IsAutoLaunchEnabled());
316 manager()->SetEnableAutoLaunch(true);
317 EXPECT_TRUE(manager()->IsAutoLaunchEnabled());
319 // Remove the auto launch app.
320 manager()->RemoveApp("fake_app_2");
321 EXPECT_EQ("fake_app_1", GetAppIds());
322 EXPECT_EQ("", manager()->GetAutoLaunchApp());
324 // Add the just removed auto launch app again and it should no longer be
325 // the auto launch app.
326 manager()->AddApp("fake_app_2");
327 EXPECT_EQ("", manager()->GetAutoLaunchApp());
328 manager()->RemoveApp("fake_app_2");
329 EXPECT_EQ("fake_app_1", GetAppIds());
331 // Set a none exist app as auto launch.
332 manager()->SetAutoLaunchApp("none_exist_app");
333 EXPECT_EQ("", manager()->GetAutoLaunchApp());
334 EXPECT_FALSE(manager()->IsAutoLaunchEnabled());
336 // Add an existing app again.
337 manager()->AddApp("fake_app_1");
338 EXPECT_EQ("fake_app_1", GetAppIds());
341 IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, LoadCached) {
342 SetExistingApp("app_1", "Cached App1 Name", "red16x16.png");
344 AppDataLoadWaiter waiter(manager());
345 waiter.Wait();
346 EXPECT_TRUE(waiter.loaded());
348 KioskAppManager::Apps apps;
349 manager()->GetApps(&apps);
350 EXPECT_EQ(1u, apps.size());
351 EXPECT_EQ("app_1", apps[0].app_id);
352 EXPECT_EQ("Cached App1 Name", apps[0].name);
353 EXPECT_EQ(gfx::Size(16, 16), apps[0].icon.size());
356 IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, ClearAppData) {
357 SetExistingApp("app_1", "Cached App1 Name", "red16x16.png");
359 PrefService* local_state = g_browser_process->local_state();
360 const base::DictionaryValue* dict =
361 local_state->GetDictionary(KioskAppManager::kKioskDictionaryName);
362 const base::DictionaryValue* apps_dict;
363 EXPECT_TRUE(dict->GetDictionary(KioskAppManager::kKeyApps, &apps_dict));
364 EXPECT_TRUE(apps_dict->HasKey("app_1"));
366 manager()->ClearAppData("app_1");
368 EXPECT_FALSE(apps_dict->HasKey("app_1"));
371 IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, UpdateAppDataFromProfile) {
372 SetExistingApp("app_1", "Cached App1 Name", "red16x16.png");
374 AppDataLoadWaiter waiter(manager());
375 waiter.Wait();
376 EXPECT_TRUE(waiter.loaded());
378 KioskAppManager::Apps apps;
379 manager()->GetApps(&apps);
380 EXPECT_EQ(1u, apps.size());
381 EXPECT_EQ("app_1", apps[0].app_id);
382 EXPECT_EQ("Cached App1 Name", apps[0].name);
384 scoped_refptr<extensions::Extension> updated_app =
385 MakeApp("Updated App1 Name", "2.0", "http://localhost/", "app_1");
386 manager()->UpdateAppDataFromProfile(
387 "app_1", browser()->profile(), updated_app.get());
389 waiter.Wait();
390 EXPECT_TRUE(waiter.loaded());
392 manager()->GetApps(&apps);
393 EXPECT_EQ(1u, apps.size());
394 EXPECT_EQ("app_1", apps[0].app_id);
395 EXPECT_EQ("Updated App1 Name", apps[0].name);
398 IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, BadApp) {
399 manager()->AddApp("unknown_app");
401 TestKioskAppManagerObserver observer(manager());
403 AppDataLoadWaiter waiter(manager());
404 waiter.Wait();
405 EXPECT_FALSE(waiter.loaded());
407 EXPECT_EQ("", GetAppIds());
408 EXPECT_EQ(1, observer.load_failure_count());
411 IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, GoodApp) {
412 // Webstore data json is in
413 // chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/app_1
414 manager()->AddApp("app_1");
416 AppDataLoadWaiter waiter(manager());
417 waiter.Wait();
418 EXPECT_TRUE(waiter.loaded());
420 // Check data is correct.
421 KioskAppManager::Apps apps;
422 manager()->GetApps(&apps);
423 ASSERT_EQ(1u, apps.size());
424 EXPECT_EQ("app_1", apps[0].app_id);
425 EXPECT_EQ("Name of App 1", apps[0].name);
426 EXPECT_EQ(gfx::Size(16, 16), apps[0].icon.size());
428 // Check data is cached in local state.
429 PrefService* local_state = g_browser_process->local_state();
430 const base::DictionaryValue* dict =
431 local_state->GetDictionary(KioskAppManager::kKioskDictionaryName);
433 std::string name;
434 EXPECT_TRUE(dict->GetString("apps.app_1.name", &name));
435 EXPECT_EQ(apps[0].name, name);
437 std::string icon_path_string;
438 EXPECT_TRUE(dict->GetString("apps.app_1.icon", &icon_path_string));
440 base::FilePath expected_icon_path;
441 ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &expected_icon_path));
442 expected_icon_path = expected_icon_path.
443 AppendASCII(KioskAppManager::kIconCacheDir).
444 AppendASCII(apps[0].app_id).AddExtension(".png");
445 EXPECT_EQ(expected_icon_path.value(), icon_path_string);
448 IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, EnableConsumerKiosk) {
449 scoped_ptr<KioskAppManager::ConsumerKioskModeStatus> status(
450 new KioskAppManager::ConsumerKioskModeStatus(
451 KioskAppManager::CONSUMER_KIOSK_MODE_DISABLED));
452 scoped_ptr<bool> locked(new bool(false));
454 scoped_refptr<content::MessageLoopRunner> runner =
455 new content::MessageLoopRunner;
456 manager()->GetConsumerKioskModeStatus(
457 base::Bind(&ConsumerKioskModeStatusCheck,
458 status.get(),
459 runner->QuitClosure()));
460 runner->Run();
461 EXPECT_EQ(*status.get(), KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE);
463 scoped_refptr<content::MessageLoopRunner> runner2 =
464 new content::MessageLoopRunner;
465 manager()->EnableConsumerModeKiosk(
466 base::Bind(&ConsumerKioskModeLockCheck,
467 locked.get(),
468 runner2->QuitClosure()));
469 runner2->Run();
470 EXPECT_TRUE(*locked.get());
472 scoped_refptr<content::MessageLoopRunner> runner3 =
473 new content::MessageLoopRunner;
474 manager()->GetConsumerKioskModeStatus(
475 base::Bind(&ConsumerKioskModeStatusCheck,
476 status.get(),
477 runner3->QuitClosure()));
478 runner3->Run();
479 EXPECT_EQ(*status.get(), KioskAppManager::CONSUMER_KIOSK_MODE_ENABLED);
482 IN_PROC_BROWSER_TEST_F(KioskAppManagerTest,
483 PreventEnableConsumerKioskForEnterprise) {
484 // First, lock the device as enterprise.
485 EXPECT_EQ(LockDeviceForEnterprise(),
486 policy::EnterpriseInstallAttributes::LOCK_SUCCESS);
488 scoped_ptr<KioskAppManager::ConsumerKioskModeStatus> status(
489 new KioskAppManager::ConsumerKioskModeStatus(
490 KioskAppManager::CONSUMER_KIOSK_MODE_DISABLED));
491 scoped_ptr<bool> locked(new bool(true));
493 scoped_refptr<content::MessageLoopRunner> runner =
494 new content::MessageLoopRunner;
495 manager()->GetConsumerKioskModeStatus(
496 base::Bind(&ConsumerKioskModeStatusCheck,
497 status.get(),
498 runner->QuitClosure()));
499 runner->Run();
500 EXPECT_EQ(*status.get(), KioskAppManager::CONSUMER_KIOSK_MODE_DISABLED);
502 scoped_refptr<content::MessageLoopRunner> runner2 =
503 new content::MessageLoopRunner;
504 manager()->EnableConsumerModeKiosk(
505 base::Bind(&ConsumerKioskModeLockCheck,
506 locked.get(),
507 runner2->QuitClosure()));
508 runner2->Run();
509 EXPECT_FALSE(*locked.get());
511 scoped_refptr<content::MessageLoopRunner> runner3 =
512 new content::MessageLoopRunner;
513 manager()->GetConsumerKioskModeStatus(
514 base::Bind(&ConsumerKioskModeStatusCheck,
515 status.get(),
516 runner3->QuitClosure()));
517 runner3->Run();
518 EXPECT_EQ(*status.get(), KioskAppManager::CONSUMER_KIOSK_MODE_DISABLED);
521 } // namespace chromeos