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