1// Copyright (c) 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.
4
5#include <map>
6#include <set>
7#include <string>
8#include <vector>
9
10#include "ash/shell.h"
11#include "ash/system/chromeos/session/logout_confirmation_controller.h"
12#include "ash/system/chromeos/session/logout_confirmation_dialog.h"
13#include "base/basictypes.h"
14#include "base/bind.h"
15#include "base/bind_helpers.h"
16#include "base/callback.h"
17#include "base/command_line.h"
18#include "base/files/file_path.h"
19#include "base/files/file_util.h"
20#include "base/json/json_reader.h"
21#include "base/json/json_writer.h"
22#include "base/location.h"
23#include "base/macros.h"
24#include "base/memory/ref_counted.h"
25#include "base/memory/scoped_ptr.h"
26#include "base/message_loop/message_loop.h"
27#include "base/message_loop/message_loop_proxy.h"
28#include "base/path_service.h"
29#include "base/prefs/pref_change_registrar.h"
30#include "base/prefs/pref_service.h"
31#include "base/run_loop.h"
32#include "base/sequenced_task_runner.h"
33#include "base/strings/string_number_conversions.h"
34#include "base/strings/string_util.h"
35#include "base/strings/stringprintf.h"
36#include "base/strings/utf_string_conversions.h"
37#include "base/threading/sequenced_worker_pool.h"
38#include "base/values.h"
39#include "chrome/browser/browser_process.h"
40#include "chrome/browser/chrome_notification_types.h"
41#include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h"
42#include "chrome/browser/chromeos/extensions/external_cache.h"
43#include "chrome/browser/chromeos/input_method/input_method_util.h"
44#include "chrome/browser/chromeos/login/existing_user_controller.h"
45#include "chrome/browser/chromeos/login/screens/wizard_screen.h"
46#include "chrome/browser/chromeos/login/ui/login_display_host.h"
47#include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
48#include "chrome/browser/chromeos/login/ui/webui_login_view.h"
49#include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h"
50#include "chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.h"
51#include "chrome/browser/chromeos/login/users/avatar/user_image_manager_test_util.h"
52#include "chrome/browser/chromeos/login/users/chrome_user_manager_impl.h"
53#include "chrome/browser/chromeos/login/wizard_controller.h"
54#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
55#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
56#include "chrome/browser/chromeos/policy/device_local_account.h"
57#include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
58#include "chrome/browser/chromeos/policy/device_policy_builder.h"
59#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
60#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
61#include "chrome/browser/extensions/crx_installer.h"
62#include "chrome/browser/extensions/extension_service.h"
63#include "chrome/browser/lifetime/application_lifetime.h"
64#include "chrome/browser/policy/profile_policy_connector.h"
65#include "chrome/browser/policy/profile_policy_connector_factory.h"
66#include "chrome/browser/policy/test/local_policy_test_server.h"
67#include "chrome/browser/prefs/session_startup_pref.h"
68#include "chrome/browser/profiles/profile.h"
69#include "chrome/browser/profiles/profile_manager.h"
70#include "chrome/browser/ui/browser.h"
71#include "chrome/browser/ui/browser_commands.h"
72#include "chrome/browser/ui/browser_finder.h"
73#include "chrome/browser/ui/browser_list.h"
74#include "chrome/browser/ui/browser_list_observer.h"
75#include "chrome/browser/ui/browser_window.h"
76#include "chrome/browser/ui/extensions/application_launch.h"
77#include "chrome/browser/ui/host_desktop.h"
78#include "chrome/browser/ui/tabs/tab_strip_model.h"
79#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
80#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
81#include "chrome/common/chrome_paths.h"
82#include "chrome/common/extensions/extension_constants.h"
83#include "chrome/grit/chromium_strings.h"
84#include "chrome/grit/generated_resources.h"
85#include "chromeos/chromeos_paths.h"
86#include "chromeos/chromeos_switches.h"
87#include "chromeos/dbus/fake_session_manager_client.h"
88#include "chromeos/ime/extension_ime_util.h"
89#include "chromeos/ime/input_method_descriptor.h"
90#include "chromeos/ime/input_method_manager.h"
91#include "chromeos/login/auth/mock_auth_status_consumer.h"
92#include "chromeos/login/auth/user_context.h"
93#include "components/policy/core/common/cloud/cloud_policy_constants.h"
94#include "components/policy/core/common/cloud/cloud_policy_core.h"
95#include "components/policy/core/common/cloud/cloud_policy_store.h"
96#include "components/policy/core/common/cloud/policy_builder.h"
97#include "components/policy/core/common/external_data_fetcher.h"
98#include "components/policy/core/common/policy_map.h"
99#include "components/policy/core/common/policy_namespace.h"
100#include "components/policy/core/common/policy_service.h"
101#include "components/policy/core/common/policy_switches.h"
102#include "components/signin/core/common/signin_pref_names.h"
103#include "components/user_manager/user.h"
104#include "components/user_manager/user_manager.h"
105#include "components/user_manager/user_type.h"
106#include "content/public/browser/browser_thread.h"
107#include "content/public/browser/notification_details.h"
108#include "content/public/browser/notification_service.h"
109#include "content/public/browser/notification_source.h"
110#include "content/public/browser/web_contents.h"
111#include "content/public/browser/web_ui.h"
112#include "content/public/test/browser_test_utils.h"
113#include "content/public/test/test_utils.h"
114#include "crypto/rsa_private_key.h"
115#include "extensions/browser/app_window/app_window.h"
116#include "extensions/browser/app_window/app_window_registry.h"
117#include "extensions/browser/app_window/native_app_window.h"
118#include "extensions/browser/extension_system.h"
119#include "extensions/browser/management_policy.h"
120#include "extensions/browser/notification_types.h"
121#include "extensions/common/extension.h"
122#include "net/base/url_util.h"
123#include "net/http/http_status_code.h"
124#include "net/test/embedded_test_server/embedded_test_server.h"
125#include "net/test/embedded_test_server/http_request.h"
126#include "net/test/embedded_test_server/http_response.h"
127#include "net/url_request/test_url_fetcher_factory.h"
128#include "net/url_request/url_fetcher_delegate.h"
129#include "net/url_request/url_request_status.h"
130#include "policy/policy_constants.h"
131#include "testing/gmock/include/gmock/gmock.h"
132#include "third_party/icu/source/common/unicode/locid.h"
133#include "ui/base/l10n/l10n_util.h"
134#include "ui/base/window_open_disposition.h"
135#include "ui/gfx/image/image_skia.h"
136#include "ui/views/widget/widget.h"
137#include "url/gurl.h"
138
139namespace em = enterprise_management;
140
141using chromeos::LoginScreenContext;
142using testing::InvokeWithoutArgs;
143using testing::Return;
144using testing::_;
145
146namespace policy {
147
148namespace {
149
150const char kDomain[] = "example.com";
151const char kAccountId1[] = "dla1@example.com";
152const char kAccountId2[] = "dla2@example.com";
153const char kDisplayName1[] = "display name 1";
154const char kDisplayName2[] = "display name 2";
155const char* kStartupURLs[] = {
156  "chrome://policy",
157  "chrome://about",
158};
159const char kExistentTermsOfServicePath[] = "chromeos/enterprise/tos.txt";
160const char kNonexistentTermsOfServicePath[] = "chromeos/enterprise/tos404.txt";
161const char kRelativeUpdateURL[] = "/service/update2/crx";
162const char kUpdateManifestHeader[] =
163    "<?xml version='1.0' encoding='UTF-8'?>\n"
164    "<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>\n";
165const char kUpdateManifestTemplate[] =
166    "  <app appid='%s'>\n"
167    "    <updatecheck codebase='%s' version='%s' />\n"
168    "  </app>\n";
169const char kUpdateManifestFooter[] =
170    "</gupdate>\n";
171const char kHostedAppID[] = "kbmnembihfiondgfjekmnmcbddelicoi";
172const char kHostedAppCRXPath[] = "extensions/hosted_app.crx";
173const char kHostedAppVersion[] = "1.0.0.0";
174const char kGoodExtensionID[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
175const char kGoodExtensionCRXPath[] = "extensions/good.crx";
176const char kGoodExtensionVersion[] = "1.0";
177const char kPackagedAppCRXPath[] = "extensions/platform_apps/app_window_2.crx";
178
179const char kExternalData[] = "External data";
180const char kExternalDataURL[] = "http://localhost/external_data";
181
182const char* kSingleRecommendedLocale[] = {
183  "el",
184};
185const char* kRecommendedLocales1[] = {
186  "pl",
187  "et",
188  "en-US",
189};
190const char* kRecommendedLocales2[] = {
191  "fr",
192  "nl",
193};
194const char* kInvalidRecommendedLocale[] = {
195  "xx",
196};
197const char kPublicSessionLocale[] = "de";
198const char kPublicSessionInputMethodIDTemplate[] = "_comp_ime_%sxkb:de:neo:ger";
199
200// The sequence token used by GetKeyboardLayoutsForLocale() for its background
201// tasks.
202const char kSequenceToken[] = "chromeos_login_l10n_util";
203
204// Helper that serves extension update manifests to Chrome.
205class TestingUpdateManifestProvider {
206 public:
207  // Update manifests will be served at |relative_update_url|.
208  explicit TestingUpdateManifestProvider(
209      const std::string& relative_update_url);
210  ~TestingUpdateManifestProvider();
211
212  // When an update manifest is requested for the given extension |id|, indicate
213  // that |version| of the extension can be downloaded at |crx_url|.
214  void AddUpdate(const std::string& id,
215                 const std::string& version,
216                 const GURL& crx_url);
217
218  // This method must be registered with the test's EmbeddedTestServer to start
219  // serving update manifests.
220  scoped_ptr<net::test_server::HttpResponse> HandleRequest(
221      const net::test_server::HttpRequest& request);
222
223 private:
224  struct Update {
225   public:
226    Update(const std::string& version, const GURL& crx_url);
227    Update();
228
229    std::string version;
230    GURL crx_url;
231  };
232  typedef std::map<std::string, Update> UpdateMap;
233  UpdateMap updates_;
234
235  const std::string relative_update_url_;
236
237  DISALLOW_COPY_AND_ASSIGN(TestingUpdateManifestProvider);
238};
239
240// Helper that observes the dictionary |pref| in local state and waits until the
241// value stored for |key| matches |expected_value|.
242class DictionaryPrefValueWaiter {
243 public:
244  DictionaryPrefValueWaiter(const std::string& pref,
245                            const std::string& key,
246                            const std::string& expected_value);
247  ~DictionaryPrefValueWaiter();
248
249  void Wait();
250
251 private:
252  void QuitLoopIfExpectedValueFound();
253
254  const std::string pref_;
255  const std::string key_;
256  const std::string expected_value_;
257
258  base::RunLoop run_loop_;
259  PrefChangeRegistrar pref_change_registrar_;
260
261  DISALLOW_COPY_AND_ASSIGN(DictionaryPrefValueWaiter);
262};
263
264TestingUpdateManifestProvider::Update::Update(const std::string& version,
265                                              const GURL& crx_url)
266    : version(version),
267      crx_url(crx_url) {
268}
269
270TestingUpdateManifestProvider::Update::Update() {
271}
272
273TestingUpdateManifestProvider::TestingUpdateManifestProvider(
274    const std::string& relative_update_url)
275    : relative_update_url_(relative_update_url) {
276}
277
278TestingUpdateManifestProvider::~TestingUpdateManifestProvider() {
279}
280
281void TestingUpdateManifestProvider::AddUpdate(const std::string& id,
282                                              const std::string& version,
283                                              const GURL& crx_url) {
284  updates_[id] = Update(version, crx_url);
285}
286
287scoped_ptr<net::test_server::HttpResponse>
288    TestingUpdateManifestProvider::HandleRequest(
289        const net::test_server::HttpRequest& request) {
290  const GURL url("http://localhost" + request.relative_url);
291  if (url.path() != relative_update_url_)
292    return scoped_ptr<net::test_server::HttpResponse>();
293
294  std::string content = kUpdateManifestHeader;
295  for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
296    if (it.GetKey() != "x")
297      continue;
298    // Extract the extension id from the subquery. Since GetValueForKeyInQuery()
299    // expects a complete URL, dummy scheme and host must be prepended.
300    std::string id;
301    net::GetValueForKeyInQuery(GURL("http://dummy?" + it.GetUnescapedValue()),
302                               "id", &id);
303    UpdateMap::const_iterator entry = updates_.find(id);
304    if (entry != updates_.end()) {
305      content += base::StringPrintf(kUpdateManifestTemplate,
306                                    id.c_str(),
307                                    entry->second.crx_url.spec().c_str(),
308                                    entry->second.version.c_str());
309    }
310  }
311  content += kUpdateManifestFooter;
312  scoped_ptr<net::test_server::BasicHttpResponse>
313      http_response(new net::test_server::BasicHttpResponse);
314  http_response->set_code(net::HTTP_OK);
315  http_response->set_content(content);
316  http_response->set_content_type("text/xml");
317  return http_response.PassAs<net::test_server::HttpResponse>();
318}
319
320DictionaryPrefValueWaiter::DictionaryPrefValueWaiter(
321    const std::string& pref,
322    const std::string& key,
323    const std::string& expected_value)
324    : pref_(pref),
325      key_(key),
326      expected_value_(expected_value) {
327  pref_change_registrar_.Init(g_browser_process->local_state());
328}
329
330DictionaryPrefValueWaiter::~DictionaryPrefValueWaiter() {
331}
332
333void DictionaryPrefValueWaiter::Wait() {
334  pref_change_registrar_.Add(
335      pref_.c_str(),
336      base::Bind(&DictionaryPrefValueWaiter::QuitLoopIfExpectedValueFound,
337                 base::Unretained(this)));
338  QuitLoopIfExpectedValueFound();
339  run_loop_.Run();
340}
341
342void DictionaryPrefValueWaiter::QuitLoopIfExpectedValueFound() {
343  const base::DictionaryValue* pref =
344      pref_change_registrar_.prefs()->GetDictionary(pref_.c_str());
345  ASSERT_TRUE(pref);
346  std::string actual_value;
347  if (pref->GetStringWithoutPathExpansion(key_, &actual_value) &&
348      actual_value == expected_value_) {
349    run_loop_.Quit();
350  }
351}
352
353bool DoesInstallSuccessReferToId(const std::string& id,
354                                 const content::NotificationSource& source,
355                                 const content::NotificationDetails& details) {
356  return content::Details<const extensions::InstalledExtensionInfo>(details)->
357      extension->id() == id;
358}
359
360bool DoesInstallFailureReferToId(const std::string& id,
361                                 const content::NotificationSource& source,
362                                 const content::NotificationDetails& details) {
363  return content::Details<const base::string16>(details)->
364      find(base::UTF8ToUTF16(id)) != base::string16::npos;
365}
366
367scoped_ptr<net::FakeURLFetcher> RunCallbackAndReturnFakeURLFetcher(
368    scoped_refptr<base::SequencedTaskRunner> task_runner,
369    const base::Closure& callback,
370    const GURL& url,
371    net::URLFetcherDelegate* delegate,
372    const std::string& response_data,
373    net::HttpStatusCode response_code,
374    net::URLRequestStatus::Status status) {
375  task_runner->PostTask(FROM_HERE, callback);
376  return make_scoped_ptr(new net::FakeURLFetcher(
377      url, delegate, response_data, response_code, status));
378}
379
380bool IsSessionStarted() {
381  return user_manager::UserManager::Get()->IsSessionStarted();
382}
383
384}  // namespace
385
386class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest,
387                               public user_manager::UserManager::Observer,
388                               public chrome::BrowserListObserver,
389                               public extensions::AppWindowRegistry::Observer {
390 protected:
391  DeviceLocalAccountTest()
392      : user_id_1_(GenerateDeviceLocalAccountUserId(
393            kAccountId1, DeviceLocalAccount::TYPE_PUBLIC_SESSION)),
394        user_id_2_(GenerateDeviceLocalAccountUserId(
395            kAccountId2, DeviceLocalAccount::TYPE_PUBLIC_SESSION)),
396        public_session_input_method_id_(base::StringPrintf(
397            kPublicSessionInputMethodIDTemplate,
398            chromeos::extension_ime_util::kXkbExtensionId)),
399        contents_(NULL) {
400    set_exit_when_last_browser_closes(false);
401  }
402
403  virtual ~DeviceLocalAccountTest() {}
404
405  virtual void SetUp() OVERRIDE {
406    // Configure and start the test server.
407    scoped_ptr<crypto::RSAPrivateKey> signing_key(
408        PolicyBuilder::CreateTestSigningKey());
409    ASSERT_TRUE(test_server_.SetSigningKeyAndSignature(
410        signing_key.get(), PolicyBuilder::GetTestSigningKeySignature()));
411    signing_key.reset();
412    test_server_.RegisterClient(PolicyBuilder::kFakeToken,
413                                PolicyBuilder::kFakeDeviceId);
414    ASSERT_TRUE(test_server_.Start());
415
416    BrowserList::AddObserver(this);
417
418    DevicePolicyCrosBrowserTest::SetUp();
419  }
420
421  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
422    DevicePolicyCrosBrowserTest::SetUpCommandLine(command_line);
423    command_line->AppendSwitch(chromeos::switches::kLoginManager);
424    command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
425    command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
426    command_line->AppendSwitchASCII(policy::switches::kDeviceManagementUrl,
427                                    test_server_.GetServiceURL().spec());
428  }
429
430  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
431    DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
432
433    // Clear command-line arguments (but keep command-line switches) so the
434    // startup pages policy takes effect.
435    CommandLine* command_line = CommandLine::ForCurrentProcess();
436    CommandLine::StringVector argv(command_line->argv());
437    argv.erase(argv.begin() + argv.size() - command_line->GetArgs().size(),
438               argv.end());
439    command_line->InitFromArgv(argv);
440
441    InstallOwnerKey();
442    MarkAsEnterpriseOwned();
443
444    InitializePolicy();
445  }
446
447  virtual void SetUpOnMainThread() OVERRIDE {
448    DevicePolicyCrosBrowserTest::SetUpOnMainThread();
449
450    initial_locale_ = g_browser_process->GetApplicationLocale();
451    initial_language_ = l10n_util::GetLanguage(initial_locale_);
452
453    content::WindowedNotificationObserver(
454        chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
455        content::NotificationService::AllSources()).Wait();
456
457    chromeos::LoginDisplayHostImpl* host =
458        reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
459            chromeos::LoginDisplayHostImpl::default_host());
460    ASSERT_TRUE(host);
461    chromeos::WebUILoginView* web_ui_login_view = host->GetWebUILoginView();
462    ASSERT_TRUE(web_ui_login_view);
463    content::WebUI* web_ui = web_ui_login_view->GetWebUI();
464    ASSERT_TRUE(web_ui);
465    contents_ = web_ui->GetWebContents();
466    ASSERT_TRUE(contents_);
467
468    // Wait for the login UI to be ready.
469    chromeos::OobeUI* oobe_ui = host->GetOobeUI();
470    ASSERT_TRUE(oobe_ui);
471    base::RunLoop run_loop;
472    const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
473    if (!oobe_ui_ready)
474      run_loop.Run();
475
476    // The network selection screen changes the application locale on load and
477    // once again on blur. Wait for the screen to load and blur it so that any
478    // locale changes caused by this screen happen now and do not affect any
479    // subsequent parts of the test.
480    bool done = false;
481    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
482        contents_,
483        "var languageSelect = document.getElementById('language-select');"
484        "var blurAndReportSuccess = function() {"
485        "  languageSelect.blur();"
486        "  domAutomationController.send(true);"
487        "};"
488        "var screenLoading = document.getElementById('outer-container')"
489        "    .classList.contains('down');"
490        "if (document.activeElement == languageSelect || !screenLoading)"
491        "  blurAndReportSuccess();"
492        "else"
493        "  languageSelect.addEventListener('focus', blurAndReportSuccess);",
494        &done));
495
496    // Skip to the login screen.
497    chromeos::WizardController* wizard_controller =
498        chromeos::WizardController::default_controller();
499    ASSERT_TRUE(wizard_controller);
500    wizard_controller->SkipToLoginForTesting(LoginScreenContext());
501  }
502
503  virtual void TearDownOnMainThread() OVERRIDE {
504    BrowserList::RemoveObserver(this);
505
506    // This shuts down the login UI.
507    base::MessageLoop::current()->PostTask(FROM_HERE,
508                                           base::Bind(&chrome::AttemptExit));
509    base::RunLoop().RunUntilIdle();
510  }
511
512  virtual void LocalStateChanged(
513      user_manager::UserManager* user_manager) OVERRIDE {
514    if (run_loop_)
515      run_loop_->Quit();
516  }
517
518  virtual void OnBrowserRemoved(Browser* browser) OVERRIDE {
519    if (run_loop_)
520      run_loop_->Quit();
521  }
522
523  virtual void OnAppWindowAdded(extensions::AppWindow* app_window) OVERRIDE {
524    if (run_loop_)
525      run_loop_->Quit();
526  }
527
528  virtual void OnAppWindowRemoved(extensions::AppWindow* app_window) OVERRIDE {
529    if (run_loop_)
530      run_loop_->Quit();
531  }
532
533  void InitializePolicy() {
534    device_policy()->policy_data().set_public_key_version(1);
535    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
536    proto.mutable_show_user_names()->set_show_user_names(true);
537
538    device_local_account_policy_.policy_data().set_policy_type(
539        dm_protocol::kChromePublicAccountPolicyType);
540    device_local_account_policy_.policy_data().set_username(kAccountId1);
541    device_local_account_policy_.policy_data().set_settings_entity_id(
542        kAccountId1);
543    device_local_account_policy_.policy_data().set_public_key_version(1);
544    device_local_account_policy_.payload().mutable_userdisplayname()->set_value(
545        kDisplayName1);
546  }
547
548  void BuildDeviceLocalAccountPolicy() {
549    device_local_account_policy_.SetDefaultSigningKey();
550    device_local_account_policy_.Build();
551  }
552
553  void UploadDeviceLocalAccountPolicy() {
554    BuildDeviceLocalAccountPolicy();
555    test_server_.UpdatePolicy(
556        dm_protocol::kChromePublicAccountPolicyType, kAccountId1,
557        device_local_account_policy_.payload().SerializeAsString());
558  }
559
560  void UploadAndInstallDeviceLocalAccountPolicy() {
561    UploadDeviceLocalAccountPolicy();
562    session_manager_client()->set_device_local_account_policy(
563        kAccountId1, device_local_account_policy_.GetBlob());
564  }
565
566  void SetRecommendedLocales(const char* recommended_locales[],
567                             size_t array_size) {
568    em::StringListPolicyProto* session_locales_proto =
569        device_local_account_policy_.payload().mutable_sessionlocales();
570     session_locales_proto->mutable_policy_options()->set_mode(
571        em::PolicyOptions_PolicyMode_RECOMMENDED);
572    session_locales_proto->mutable_value()->Clear();
573    for (size_t i = 0; i < array_size; ++i) {
574      session_locales_proto->mutable_value()->add_entries(
575          recommended_locales[i]);
576    }
577  }
578
579  void AddPublicSessionToDevicePolicy(const std::string& username) {
580    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
581    em::DeviceLocalAccountInfoProto* account =
582        proto.mutable_device_local_accounts()->add_account();
583    account->set_account_id(username);
584    account->set_type(
585        em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
586    RefreshDevicePolicy();
587    test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType,
588                              std::string(), proto.SerializeAsString());
589  }
590
591  void EnableAutoLogin() {
592    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
593    em::DeviceLocalAccountsProto* device_local_accounts =
594        proto.mutable_device_local_accounts();
595    device_local_accounts->set_auto_login_id(kAccountId1);
596    device_local_accounts->set_auto_login_delay(0);
597    RefreshDevicePolicy();
598    test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType,
599                              std::string(), proto.SerializeAsString());
600  }
601
602  void CheckPublicSessionPresent(const std::string& id) {
603    const user_manager::User* user =
604        user_manager::UserManager::Get()->FindUser(id);
605    ASSERT_TRUE(user);
606    EXPECT_EQ(id, user->email());
607    EXPECT_EQ(user_manager::USER_TYPE_PUBLIC_ACCOUNT, user->GetType());
608  }
609
610  base::FilePath GetExtensionCacheDirectoryForAccountID(
611      const std::string& account_id) {
612    base::FilePath extension_cache_root_dir;
613    if (!PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
614                          &extension_cache_root_dir)) {
615      ADD_FAILURE();
616    }
617    return extension_cache_root_dir.Append(
618        base::HexEncode(account_id.c_str(), account_id.size()));
619  }
620
621  base::FilePath GetCacheCRXFile(const std::string& account_id,
622                                 const std::string& id,
623                                 const std::string& version) {
624    return GetExtensionCacheDirectoryForAccountID(account_id)
625        .Append(base::StringPrintf("%s-%s.crx", id.c_str(), version.c_str()));
626  }
627
628  // Returns a profile which can be used for testing.
629  Profile* GetProfileForTest() {
630    // Any profile can be used here since this test does not test multi profile.
631    return ProfileManager::GetActiveUserProfile();
632  }
633
634  void WaitForDisplayName(const std::string& user_id,
635                          const std::string& expected_display_name) {
636    DictionaryPrefValueWaiter("UserDisplayName",
637                              user_id,
638                              expected_display_name).Wait();
639  }
640
641  void WaitForPolicy() {
642    // Wait for the display name becoming available as that indicates
643    // device-local account policy is fully loaded, which is a prerequisite for
644    // successful login.
645    WaitForDisplayName(user_id_1_, kDisplayName1);
646  }
647
648  void ExpandPublicSessionPod(bool expect_advanced) {
649    bool advanced = false;
650    // Click on the pod to expand it.
651    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
652        contents_,
653        base::StringPrintf(
654            "var pod ="
655            "    document.getElementById('pod-row').getPodWithUsername_('%s');"
656            "pod.click();"
657            "domAutomationController.send(pod.classList.contains('advanced'));",
658            user_id_1_.c_str()),
659        &advanced));
660    // Verify that the pod expanded to its basic/advanced form, as expected.
661    EXPECT_EQ(expect_advanced, advanced);
662
663    // Verify that the construction of the pod's language list did not affect
664    // the current ICU locale.
665    EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage());
666  }
667
668  // GetKeyboardLayoutsForLocale() posts a task to a background task runner.
669  // This method flushes that task runner and the current thread's message loop
670  // to ensure that GetKeyboardLayoutsForLocale() is finished.
671  void WaitForGetKeyboardLayoutsForLocaleToFinish() {
672    base::SequencedWorkerPool* worker_pool =
673        content::BrowserThread::GetBlockingPool();
674     scoped_refptr<base::SequencedTaskRunner> background_task_runner =
675         worker_pool->GetSequencedTaskRunner(
676             worker_pool->GetNamedSequenceToken(kSequenceToken));
677    base::RunLoop run_loop;
678    background_task_runner->PostTaskAndReply(FROM_HERE,
679                                             base::Bind(&base::DoNothing),
680                                             run_loop.QuitClosure());
681    run_loop.Run();
682    base::RunLoop().RunUntilIdle();
683
684    // Verify that the construction of the keyboard layout list did not affect
685    // the current ICU locale.
686    EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage());
687  }
688
689  void StartLogin(const std::string& locale,
690                  const std::string& input_method) {
691    // Start login into the device-local account.
692    chromeos::LoginDisplayHostImpl* host =
693        reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
694            chromeos::LoginDisplayHostImpl::default_host());
695    ASSERT_TRUE(host);
696    host->StartSignInScreen(LoginScreenContext());
697    chromeos::ExistingUserController* controller =
698        chromeos::ExistingUserController::current_controller();
699    ASSERT_TRUE(controller);
700
701    chromeos::UserContext user_context(user_manager::USER_TYPE_PUBLIC_ACCOUNT,
702                                       user_id_1_);
703    user_context.SetPublicSessionLocale(locale);
704    user_context.SetPublicSessionInputMethod(input_method);
705    controller->LoginAsPublicSession(user_context);
706  }
707
708  void WaitForSessionStart() {
709    if (IsSessionStarted())
710      return;
711    content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
712                                          base::Bind(IsSessionStarted)).Wait();
713  }
714
715  void VerifyKeyboardLayoutMatchesLocale() {
716    chromeos::input_method::InputMethodManager* input_method_manager =
717        chromeos::input_method::InputMethodManager::Get();
718    std::vector<std::string> layouts_from_locale;
719    input_method_manager->GetInputMethodUtil()->
720        GetInputMethodIdsFromLanguageCode(
721            g_browser_process->GetApplicationLocale(),
722            chromeos::input_method::kKeyboardLayoutsOnly,
723            &layouts_from_locale);
724    ASSERT_FALSE(layouts_from_locale.empty());
725    EXPECT_EQ(layouts_from_locale.front(),
726              input_method_manager->GetActiveIMEState()
727                  ->GetCurrentInputMethod()
728                  .id());
729  }
730
731  const std::string user_id_1_;
732  const std::string user_id_2_;
733  const std::string public_session_input_method_id_;
734
735  std::string initial_locale_;
736  std::string initial_language_;
737
738  scoped_ptr<base::RunLoop> run_loop_;
739
740  UserPolicyBuilder device_local_account_policy_;
741  LocalPolicyTestServer test_server_;
742
743  content::WebContents* contents_;
744
745 private:
746  DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountTest);
747};
748
749static bool IsKnownUser(const std::string& account_id) {
750  return user_manager::UserManager::Get()->IsKnownUser(account_id);
751}
752
753IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LoginScreen) {
754  AddPublicSessionToDevicePolicy(kAccountId1);
755  AddPublicSessionToDevicePolicy(kAccountId2);
756
757  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
758                                        base::Bind(&IsKnownUser, user_id_1_))
759      .Wait();
760  EXPECT_TRUE(IsKnownUser(user_id_2_));
761
762  CheckPublicSessionPresent(user_id_1_);
763  CheckPublicSessionPresent(user_id_2_);
764}
765
766IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) {
767  UploadAndInstallDeviceLocalAccountPolicy();
768  AddPublicSessionToDevicePolicy(kAccountId1);
769
770  WaitForPolicy();
771
772  // Verify that the display name is shown in the UI.
773  const std::string get_compact_pod_display_name = base::StringPrintf(
774      "domAutomationController.send(document.getElementById('pod-row')"
775      "    .getPodWithUsername_('%s').nameElement.textContent);",
776      user_id_1_.c_str());
777  std::string display_name;
778  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
779      contents_,
780      get_compact_pod_display_name,
781      &display_name));
782  EXPECT_EQ(kDisplayName1, display_name);
783  const std::string get_expanded_pod_display_name = base::StringPrintf(
784      "domAutomationController.send(document.getElementById('pod-row')"
785      "    .getPodWithUsername_('%s').querySelector('.expanded-pane-name')"
786      "        .textContent);",
787      user_id_1_.c_str());
788  display_name.clear();
789  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
790      contents_,
791      get_expanded_pod_display_name,
792      &display_name));
793  EXPECT_EQ(kDisplayName1, display_name);
794
795  // Click on the pod to expand it.
796  ASSERT_TRUE(content::ExecuteScript(
797      contents_,
798      base::StringPrintf(
799          "document.getElementById('pod-row').getPodWithUsername_('%s')"
800          "    .click();",
801      user_id_1_.c_str())));
802
803  // Change the display name.
804  device_local_account_policy_.payload().mutable_userdisplayname()->set_value(
805      kDisplayName2);
806  UploadAndInstallDeviceLocalAccountPolicy();
807  policy::BrowserPolicyConnectorChromeOS* connector =
808      g_browser_process->platform_part()->browser_policy_connector_chromeos();
809  DeviceLocalAccountPolicyBroker* broker =
810      connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser(
811          user_id_1_);
812  ASSERT_TRUE(broker);
813  broker->core()->store()->Load();
814  WaitForDisplayName(user_id_1_, kDisplayName2);
815
816  // Verify that the new display name is shown in the UI.
817  display_name.clear();
818  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
819      contents_,
820      get_compact_pod_display_name,
821      &display_name));
822  EXPECT_EQ(kDisplayName2, display_name);
823  display_name.clear();
824  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
825      contents_,
826      get_expanded_pod_display_name,
827      &display_name));
828  EXPECT_EQ(kDisplayName2, display_name);
829
830  // Verify that the pod is still expanded. This indicates that the UI updated
831  // without reloading and losing state.
832  bool expanded = false;
833  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
834      contents_,
835      base::StringPrintf(
836          "domAutomationController.send(document.getElementById('pod-row')"
837          "    .getPodWithUsername_('%s').expanded);",
838          user_id_1_.c_str()),
839      &expanded));
840  EXPECT_TRUE(expanded);
841}
842
843IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyDownload) {
844  UploadDeviceLocalAccountPolicy();
845  AddPublicSessionToDevicePolicy(kAccountId1);
846
847  WaitForPolicy();
848
849  // Sanity check: The policy should be present now.
850  ASSERT_FALSE(session_manager_client()->device_local_account_policy(
851      kAccountId1).empty());
852}
853
854static bool IsNotKnownUser(const std::string& account_id) {
855  return !IsKnownUser(account_id);
856}
857
858IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, AccountListChange) {
859  AddPublicSessionToDevicePolicy(kAccountId1);
860  AddPublicSessionToDevicePolicy(kAccountId2);
861
862  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
863                                        base::Bind(&IsKnownUser, user_id_1_))
864      .Wait();
865  EXPECT_TRUE(IsKnownUser(user_id_2_));
866
867  // Update policy to remove kAccountId2.
868  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
869  proto.mutable_device_local_accounts()->clear_account();
870  AddPublicSessionToDevicePolicy(kAccountId1);
871
872  em::ChromeDeviceSettingsProto policy;
873  policy.mutable_show_user_names()->set_show_user_names(true);
874  em::DeviceLocalAccountInfoProto* account1 =
875      policy.mutable_device_local_accounts()->add_account();
876  account1->set_account_id(kAccountId1);
877  account1->set_type(
878      em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
879
880  test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, std::string(),
881                            policy.SerializeAsString());
882  g_browser_process->policy_service()->RefreshPolicies(base::Closure());
883
884  // Make sure the second device-local account disappears.
885  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
886                                        base::Bind(&IsNotKnownUser, user_id_2_))
887      .Wait();
888}
889
890IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, StartSession) {
891  // Specify startup pages.
892  device_local_account_policy_.payload().mutable_restoreonstartup()->set_value(
893      SessionStartupPref::kPrefValueURLs);
894  em::StringListPolicyProto* startup_urls_proto =
895      device_local_account_policy_.payload().mutable_restoreonstartupurls();
896  for (size_t i = 0; i < arraysize(kStartupURLs); ++i)
897    startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]);
898  UploadAndInstallDeviceLocalAccountPolicy();
899  AddPublicSessionToDevicePolicy(kAccountId1);
900
901  WaitForPolicy();
902
903  ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string()));
904  WaitForSessionStart();
905
906  // Check that the startup pages specified in policy were opened.
907  BrowserList* browser_list =
908    BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
909  EXPECT_EQ(1U, browser_list->size());
910  Browser* browser = browser_list->get(0);
911  ASSERT_TRUE(browser);
912
913  TabStripModel* tabs = browser->tab_strip_model();
914  ASSERT_TRUE(tabs);
915  int expected_tab_count = static_cast<int>(arraysize(kStartupURLs));
916  EXPECT_EQ(expected_tab_count, tabs->count());
917  for (int i = 0; i < expected_tab_count && i < tabs->count(); ++i) {
918    EXPECT_EQ(GURL(kStartupURLs[i]),
919              tabs->GetWebContentsAt(i)->GetVisibleURL());
920  }
921
922  // Verify that the session is not considered to be logged in with a GAIA
923  // account.
924  Profile* profile = GetProfileForTest();
925  ASSERT_TRUE(profile);
926  EXPECT_FALSE(profile->GetPrefs()->HasPrefPath(
927      prefs::kGoogleServicesUsername));
928}
929
930IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, FullscreenDisallowed) {
931  UploadAndInstallDeviceLocalAccountPolicy();
932  AddPublicSessionToDevicePolicy(kAccountId1);
933
934  WaitForPolicy();
935
936  ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string()));
937  WaitForSessionStart();
938
939  BrowserList* browser_list =
940    BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
941  EXPECT_EQ(1U, browser_list->size());
942  Browser* browser = browser_list->get(0);
943  ASSERT_TRUE(browser);
944  BrowserWindow* browser_window = browser->window();
945  ASSERT_TRUE(browser_window);
946
947  // Verify that an attempt to enter fullscreen mode is denied.
948  EXPECT_FALSE(browser_window->IsFullscreen());
949  chrome::ToggleFullscreenMode(browser);
950  EXPECT_FALSE(browser_window->IsFullscreen());
951}
952
953IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsUncached) {
954  // Make it possible to force-install a hosted app and an extension.
955  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
956  TestingUpdateManifestProvider testing_update_manifest_provider(
957      kRelativeUpdateURL);
958  testing_update_manifest_provider.AddUpdate(
959      kHostedAppID,
960      kHostedAppVersion,
961      embedded_test_server()->GetURL(std::string("/") + kHostedAppCRXPath));
962  testing_update_manifest_provider.AddUpdate(
963      kGoodExtensionID,
964      kGoodExtensionVersion,
965      embedded_test_server()->GetURL(std::string("/") + kGoodExtensionCRXPath));
966  embedded_test_server()->RegisterRequestHandler(
967      base::Bind(&TestingUpdateManifestProvider::HandleRequest,
968                 base::Unretained(&testing_update_manifest_provider)));
969
970  // Specify policy to force-install the hosted app and the extension.
971  em::StringList* forcelist = device_local_account_policy_.payload()
972      .mutable_extensioninstallforcelist()->mutable_value();
973  forcelist->add_entries(base::StringPrintf(
974      "%s;%s",
975      kHostedAppID,
976      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
977  forcelist->add_entries(base::StringPrintf(
978      "%s;%s",
979      kGoodExtensionID,
980      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
981
982  UploadAndInstallDeviceLocalAccountPolicy();
983  AddPublicSessionToDevicePolicy(kAccountId1);
984
985  WaitForPolicy();
986
987  // Start listening for app/extension installation results.
988  content::WindowedNotificationObserver hosted_app_observer(
989      extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED,
990      base::Bind(DoesInstallSuccessReferToId, kHostedAppID));
991  content::WindowedNotificationObserver extension_observer(
992      extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR,
993      base::Bind(DoesInstallFailureReferToId, kGoodExtensionID));
994
995  ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string()));
996
997  // Wait for the hosted app installation to succeed and the extension
998  // installation to fail (because hosted apps are whitelisted for use in
999  // device-local accounts and extensions are not).
1000  hosted_app_observer.Wait();
1001  extension_observer.Wait();
1002
1003  // Verify that the hosted app was installed.
1004  Profile* profile = GetProfileForTest();
1005  ASSERT_TRUE(profile);
1006  ExtensionService* extension_service =
1007      extensions::ExtensionSystem::Get(profile)->extension_service();
1008  EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true));
1009
1010  // Verify that the extension was not installed.
1011  EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
1012
1013  // Verify that the app was downloaded to the account's extension cache.
1014  base::FilePath test_dir;
1015  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
1016  EXPECT_TRUE(ContentsEqual(
1017          GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion),
1018          test_dir.Append(kHostedAppCRXPath)));
1019
1020  // Verify that the extension was removed from the account's extension cache
1021  // after the installation failure.
1022  DeviceLocalAccountPolicyBroker* broker =
1023      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
1024          GetDeviceLocalAccountPolicyService()->GetBrokerForUser(user_id_1_);
1025  ASSERT_TRUE(broker);
1026  chromeos::ExternalCache* cache =
1027      broker->extension_loader()->GetExternalCacheForTesting();
1028  ASSERT_TRUE(cache);
1029  EXPECT_FALSE(cache->GetExtension(kGoodExtensionID, NULL, NULL));
1030}
1031
1032IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsCached) {
1033  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
1034
1035  // Pre-populate the device local account's extension cache with a hosted app
1036  // and an extension.
1037  EXPECT_TRUE(base::CreateDirectory(
1038      GetExtensionCacheDirectoryForAccountID(kAccountId1)));
1039  base::FilePath test_dir;
1040  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
1041  const base::FilePath cached_hosted_app =
1042      GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion);
1043  EXPECT_TRUE(CopyFile(test_dir.Append(kHostedAppCRXPath),
1044                       cached_hosted_app));
1045  EXPECT_TRUE(CopyFile(
1046      test_dir.Append(kGoodExtensionCRXPath),
1047      GetCacheCRXFile(kAccountId1, kGoodExtensionID, kGoodExtensionVersion)));
1048
1049  // Specify policy to force-install the hosted app.
1050  em::StringList* forcelist = device_local_account_policy_.payload()
1051      .mutable_extensioninstallforcelist()->mutable_value();
1052  forcelist->add_entries(base::StringPrintf(
1053      "%s;%s",
1054      kHostedAppID,
1055      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
1056  forcelist->add_entries(base::StringPrintf(
1057      "%s;%s",
1058      kGoodExtensionID,
1059      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
1060
1061  UploadAndInstallDeviceLocalAccountPolicy();
1062  AddPublicSessionToDevicePolicy(kAccountId1);
1063
1064  WaitForPolicy();
1065
1066  // Start listening for app/extension installation results.
1067  content::WindowedNotificationObserver hosted_app_observer(
1068      extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED,
1069      base::Bind(DoesInstallSuccessReferToId, kHostedAppID));
1070  content::WindowedNotificationObserver extension_observer(
1071      extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR,
1072      base::Bind(DoesInstallFailureReferToId, kGoodExtensionID));
1073
1074  ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string()));
1075
1076  // Wait for the hosted app installation to succeed and the extension
1077  // installation to fail.
1078  hosted_app_observer.Wait();
1079  extension_observer.Wait();
1080
1081  // Verify that the hosted app was installed.
1082  Profile* profile = GetProfileForTest();
1083  ASSERT_TRUE(profile);
1084  ExtensionService* extension_service =
1085      extensions::ExtensionSystem::Get(profile)->extension_service();
1086  EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true));
1087
1088  // Verify that the extension was not installed.
1089  EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
1090
1091  // Verify that the app is still in the account's extension cache.
1092  EXPECT_TRUE(PathExists(cached_hosted_app));
1093
1094  // Verify that the extension was removed from the account's extension cache.
1095  DeviceLocalAccountPolicyBroker* broker =
1096      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
1097          GetDeviceLocalAccountPolicyService()->GetBrokerForUser(user_id_1_);
1098  ASSERT_TRUE(broker);
1099  chromeos::ExternalCache* cache =
1100      broker->extension_loader()->GetExternalCacheForTesting();
1101  ASSERT_TRUE(cache);
1102  EXPECT_FALSE(cache->GetExtension(kGoodExtensionID, NULL, NULL));
1103}
1104
1105IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExternalData) {
1106  // user_manager::UserManager requests an external data fetch whenever
1107  // the key::kUserAvatarImage policy is set. Since this test wants to
1108  // verify that the underlying policy subsystem will start a fetch
1109  // without this request as well, the user_manager::UserManager must be
1110  // prevented from seeing the policy change.
1111  reinterpret_cast<chromeos::ChromeUserManagerImpl*>(
1112      user_manager::UserManager::Get())->StopPolicyObserverForTesting();
1113
1114  UploadDeviceLocalAccountPolicy();
1115  AddPublicSessionToDevicePolicy(kAccountId1);
1116
1117  WaitForPolicy();
1118
1119  // Start serving external data at |kExternalDataURL|.
1120  scoped_ptr<base::RunLoop> run_loop(new base::RunLoop);
1121  scoped_ptr<net::FakeURLFetcherFactory> fetcher_factory(
1122      new net::FakeURLFetcherFactory(
1123          NULL,
1124          base::Bind(&RunCallbackAndReturnFakeURLFetcher,
1125                     base::MessageLoopProxy::current(),
1126                     run_loop->QuitClosure())));
1127  fetcher_factory->SetFakeResponse(GURL(kExternalDataURL),
1128                                   kExternalData,
1129                                   net::HTTP_OK,
1130                                   net::URLRequestStatus::SUCCESS);
1131
1132  // Specify an external data reference for the key::kUserAvatarImage policy.
1133  scoped_ptr<base::DictionaryValue> metadata =
1134      test::ConstructExternalDataReference(kExternalDataURL, kExternalData);
1135  std::string policy;
1136  base::JSONWriter::Write(metadata.get(), &policy);
1137  device_local_account_policy_.payload().mutable_useravatarimage()->set_value(
1138      policy);
1139  UploadAndInstallDeviceLocalAccountPolicy();
1140  policy::BrowserPolicyConnectorChromeOS* connector =
1141      g_browser_process->platform_part()->browser_policy_connector_chromeos();
1142  DeviceLocalAccountPolicyBroker* broker =
1143      connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser(
1144          user_id_1_);
1145  ASSERT_TRUE(broker);
1146  broker->core()->store()->Load();
1147
1148  // The external data should be fetched and cached automatically. Wait for this
1149  // fetch.
1150  run_loop->Run();
1151
1152  // Stop serving external data at |kExternalDataURL|.
1153  fetcher_factory.reset();
1154
1155  const PolicyMap::Entry* policy_entry =
1156      broker->core()->store()->policy_map().Get(key::kUserAvatarImage);
1157  ASSERT_TRUE(policy_entry);
1158  ASSERT_TRUE(policy_entry->external_data_fetcher);
1159
1160  // Retrieve the external data. Although the data is no longer being served at
1161  // |kExternalDataURL|, the retrieval should succeed because the data has been
1162  // cached.
1163  run_loop.reset(new base::RunLoop);
1164  scoped_ptr<std::string> fetched_external_data;
1165  policy_entry->external_data_fetcher->Fetch(base::Bind(
1166      &test::ExternalDataFetchCallback,
1167      &fetched_external_data,
1168      run_loop->QuitClosure()));
1169  run_loop->Run();
1170
1171  ASSERT_TRUE(fetched_external_data);
1172  EXPECT_EQ(kExternalData, *fetched_external_data);
1173
1174  ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string()));
1175  WaitForSessionStart();
1176
1177  // Verify that the external data reference has propagated to the device-local
1178  // account's ProfilePolicyConnector.
1179  ProfilePolicyConnector* policy_connector =
1180      ProfilePolicyConnectorFactory::GetForProfile(GetProfileForTest());
1181  ASSERT_TRUE(policy_connector);
1182  const PolicyMap& policies = policy_connector->policy_service()->GetPolicies(
1183      PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
1184  policy_entry = policies.Get(key::kUserAvatarImage);
1185  ASSERT_TRUE(policy_entry);
1186  EXPECT_TRUE(base::Value::Equals(metadata.get(), policy_entry->value));
1187  ASSERT_TRUE(policy_entry->external_data_fetcher);
1188
1189  // Retrieve the external data via the ProfilePolicyConnector. The retrieval
1190  // should succeed because the data has been cached.
1191  run_loop.reset(new base::RunLoop);
1192  fetched_external_data.reset();
1193  policy_entry->external_data_fetcher->Fetch(base::Bind(
1194      &test::ExternalDataFetchCallback,
1195      &fetched_external_data,
1196      run_loop->QuitClosure()));
1197  run_loop->Run();
1198
1199  ASSERT_TRUE(fetched_external_data);
1200  EXPECT_EQ(kExternalData, *fetched_external_data);
1201}
1202
1203IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, UserAvatarImage) {
1204  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
1205
1206  UploadDeviceLocalAccountPolicy();
1207  AddPublicSessionToDevicePolicy(kAccountId1);
1208
1209  WaitForPolicy();
1210
1211  base::FilePath test_dir;
1212  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
1213  std::string image_data;
1214  ASSERT_TRUE(base::ReadFileToString(
1215      test_dir.Append(chromeos::test::kUserAvatarImage1RelativePath),
1216      &image_data));
1217
1218  std::string policy;
1219  base::JSONWriter::Write(test::ConstructExternalDataReference(
1220      embedded_test_server()->GetURL(std::string("/") +
1221          chromeos::test::kUserAvatarImage1RelativePath).spec(),
1222      image_data).get(),
1223      &policy);
1224  device_local_account_policy_.payload().mutable_useravatarimage()->set_value(
1225      policy);
1226  UploadAndInstallDeviceLocalAccountPolicy();
1227  policy::BrowserPolicyConnectorChromeOS* connector =
1228      g_browser_process->platform_part()->browser_policy_connector_chromeos();
1229  DeviceLocalAccountPolicyBroker* broker =
1230      connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser(
1231          user_id_1_);
1232  ASSERT_TRUE(broker);
1233
1234  run_loop_.reset(new base::RunLoop);
1235  user_manager::UserManager::Get()->AddObserver(this);
1236  broker->core()->store()->Load();
1237  run_loop_->Run();
1238  user_manager::UserManager::Get()->RemoveObserver(this);
1239
1240  scoped_ptr<gfx::ImageSkia> policy_image = chromeos::test::ImageLoader(
1241      test_dir.Append(chromeos::test::kUserAvatarImage1RelativePath)).Load();
1242  ASSERT_TRUE(policy_image);
1243
1244  const user_manager::User* user =
1245      user_manager::UserManager::Get()->FindUser(user_id_1_);
1246  ASSERT_TRUE(user);
1247
1248  base::FilePath user_data_dir;
1249  ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
1250  const base::FilePath saved_image_path =
1251      user_data_dir.Append(user_id_1_).AddExtension("jpg");
1252
1253  EXPECT_FALSE(user->HasDefaultImage());
1254  EXPECT_EQ(user_manager::User::USER_IMAGE_EXTERNAL, user->image_index());
1255  EXPECT_TRUE(chromeos::test::AreImagesEqual(*policy_image, user->GetImage()));
1256  const base::DictionaryValue* images_pref =
1257      g_browser_process->local_state()->GetDictionary("user_image_info");
1258  ASSERT_TRUE(images_pref);
1259  const base::DictionaryValue* image_properties;
1260  ASSERT_TRUE(images_pref->GetDictionaryWithoutPathExpansion(
1261      user_id_1_,
1262      &image_properties));
1263  int image_index;
1264  std::string image_path;
1265  ASSERT_TRUE(image_properties->GetInteger("index", &image_index));
1266  ASSERT_TRUE(image_properties->GetString("path", &image_path));
1267  EXPECT_EQ(user_manager::User::USER_IMAGE_EXTERNAL, image_index);
1268  EXPECT_EQ(saved_image_path.value(), image_path);
1269
1270  scoped_ptr<gfx::ImageSkia> saved_image =
1271      chromeos::test::ImageLoader(saved_image_path).Load();
1272  ASSERT_TRUE(saved_image);
1273
1274  // Check image dimensions. Images can't be compared since JPEG is lossy.
1275  EXPECT_EQ(policy_image->width(), saved_image->width());
1276  EXPECT_EQ(policy_image->height(), saved_image->height());
1277}
1278
1279IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LastWindowClosedLogoutReminder) {
1280  UploadAndInstallDeviceLocalAccountPolicy();
1281  AddPublicSessionToDevicePolicy(kAccountId1);
1282
1283  WaitForPolicy();
1284
1285  ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string()));
1286  WaitForSessionStart();
1287
1288  Profile* profile = GetProfileForTest();
1289  ASSERT_TRUE(profile);
1290  extensions::AppWindowRegistry* app_window_registry =
1291      extensions::AppWindowRegistry::Get(profile);
1292  app_window_registry->AddObserver(this);
1293
1294  // Verify that the logout confirmation dialog is not showing.
1295  ash::LogoutConfirmationController* logout_confirmation_controller =
1296      ash::Shell::GetInstance()->logout_confirmation_controller();
1297  ASSERT_TRUE(logout_confirmation_controller);
1298  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
1299
1300  // Remove policy that allows only explicitly whitelisted apps to be installed
1301  // in a public session.
1302  extensions::ExtensionSystem* extension_system =
1303      extensions::ExtensionSystem::Get(profile);
1304  ASSERT_TRUE(extension_system);
1305  extension_system->management_policy()->UnregisterAllProviders();
1306
1307  // Install and a platform app.
1308  scoped_refptr<extensions::CrxInstaller> installer =
1309      extensions::CrxInstaller::CreateSilent(
1310          extension_system->extension_service());
1311  installer->set_allow_silent_install(true);
1312  installer->set_install_cause(extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
1313  installer->set_creation_flags(extensions::Extension::FROM_WEBSTORE);
1314  content::WindowedNotificationObserver app_install_observer(
1315      extensions::NOTIFICATION_CRX_INSTALLER_DONE,
1316      content::NotificationService::AllSources());
1317  base::FilePath test_dir;
1318  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
1319  installer->InstallCrx(test_dir.Append(kPackagedAppCRXPath));
1320  app_install_observer.Wait();
1321  const extensions::Extension* app =
1322      content::Details<const extensions::Extension>(
1323          app_install_observer.details()).ptr();
1324
1325  // Start the platform app, causing it to open a window.
1326  run_loop_.reset(new base::RunLoop);
1327  OpenApplication(AppLaunchParams(
1328      profile, app, extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW));
1329  run_loop_->Run();
1330  EXPECT_EQ(1U, app_window_registry->app_windows().size());
1331
1332  // Close the only open browser window.
1333  BrowserList* browser_list =
1334      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
1335  EXPECT_EQ(1U, browser_list->size());
1336  Browser* browser = browser_list->get(0);
1337  ASSERT_TRUE(browser);
1338  BrowserWindow* browser_window = browser->window();
1339  ASSERT_TRUE(browser_window);
1340  run_loop_.reset(new base::RunLoop);
1341  browser_window->Close();
1342  browser_window = NULL;
1343  run_loop_->Run();
1344  browser = NULL;
1345  EXPECT_TRUE(browser_list->empty());
1346
1347  // Verify that the logout confirmation dialog is not showing because an app
1348  // window is still open.
1349  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
1350
1351  // Open a browser window.
1352  Browser* first_browser = CreateBrowser(profile);
1353  EXPECT_EQ(1U, browser_list->size());
1354
1355  // Close the app window.
1356  run_loop_.reset(new base::RunLoop);
1357  ASSERT_EQ(1U, app_window_registry->app_windows().size());
1358  app_window_registry->app_windows().front()->GetBaseWindow()->Close();
1359  run_loop_->Run();
1360  EXPECT_TRUE(app_window_registry->app_windows().empty());
1361
1362  // Verify that the logout confirmation dialog is not showing because a browser
1363  // window is still open.
1364  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
1365
1366  // Open a second browser window.
1367  Browser* second_browser = CreateBrowser(profile);
1368  EXPECT_EQ(2U, browser_list->size());
1369
1370  // Close the first browser window.
1371  browser_window = first_browser->window();
1372  ASSERT_TRUE(browser_window);
1373  run_loop_.reset(new base::RunLoop);
1374  browser_window->Close();
1375  browser_window = NULL;
1376  run_loop_->Run();
1377  first_browser = NULL;
1378  EXPECT_EQ(1U, browser_list->size());
1379
1380  // Verify that the logout confirmation dialog is not showing because a browser
1381  // window is still open.
1382  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
1383
1384  // Close the second browser window.
1385  browser_window = second_browser->window();
1386  ASSERT_TRUE(browser_window);
1387  run_loop_.reset(new base::RunLoop);
1388  browser_window->Close();
1389  browser_window = NULL;
1390  run_loop_->Run();
1391  second_browser = NULL;
1392  EXPECT_TRUE(browser_list->empty());
1393
1394  // Verify that the logout confirmation dialog is showing.
1395  ash::LogoutConfirmationDialog* dialog =
1396      logout_confirmation_controller->dialog_for_testing();
1397  ASSERT_TRUE(dialog);
1398
1399  // Deny the logout.
1400  dialog->GetWidget()->Close();
1401  dialog = NULL;
1402  base::RunLoop().RunUntilIdle();
1403
1404  // Verify that the logout confirmation dialog is no longer showing.
1405  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
1406
1407  // Open a browser window.
1408  browser = CreateBrowser(profile);
1409  EXPECT_EQ(1U, browser_list->size());
1410
1411  // Close the browser window.
1412  browser_window = browser->window();
1413  ASSERT_TRUE(browser_window);
1414  run_loop_.reset(new base::RunLoop);
1415  browser_window->Close();
1416  browser_window = NULL;
1417  run_loop_->Run();
1418  browser = NULL;
1419  EXPECT_TRUE(browser_list->empty());
1420
1421  // Verify that the logout confirmation dialog is showing again.
1422  dialog = logout_confirmation_controller->dialog_for_testing();
1423  ASSERT_TRUE(dialog);
1424
1425  // Deny the logout.
1426  dialog->GetWidget()->Close();
1427  dialog = NULL;
1428  base::RunLoop().RunUntilIdle();
1429
1430  app_window_registry->RemoveObserver(this);
1431};
1432
1433IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, NoRecommendedLocaleNoSwitch) {
1434  UploadAndInstallDeviceLocalAccountPolicy();
1435  AddPublicSessionToDevicePolicy(kAccountId1);
1436
1437  WaitForPolicy();
1438
1439  ExpandPublicSessionPod(false);
1440
1441  // Click the enter button to start the session.
1442  ASSERT_TRUE(content::ExecuteScript(
1443      contents_,
1444      base::StringPrintf(
1445          "document.getElementById('pod-row').getPodWithUsername_('%s')"
1446          "    .querySelector('.enter-button').click();",
1447          user_id_1_.c_str())));
1448
1449  WaitForSessionStart();
1450
1451  // Verify that the locale has not changed and the first keyboard layout
1452  // applicable to the locale was chosen.
1453  EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale());
1454  EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage());
1455  VerifyKeyboardLayoutMatchesLocale();
1456}
1457
1458IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, NoRecommendedLocaleSwitch) {
1459  UploadAndInstallDeviceLocalAccountPolicy();
1460  AddPublicSessionToDevicePolicy(kAccountId1);
1461
1462  WaitForPolicy();
1463
1464  ExpandPublicSessionPod(false);
1465
1466  // Click the link that switches the pod to its advanced form. Verify that the
1467  // pod switches from basic to advanced.
1468  bool advanced = false;
1469  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
1470      contents_,
1471      base::StringPrintf(
1472          "var pod ="
1473          "    document.getElementById('pod-row').getPodWithUsername_('%s');"
1474          "pod.querySelector('.language-and-input').click();"
1475          "domAutomationController.send(pod.classList.contains('advanced'));",
1476          user_id_1_.c_str()),
1477      &advanced));
1478  EXPECT_FALSE(advanced);
1479
1480  // Manually select a different locale.
1481  ASSERT_TRUE(content::ExecuteScript(
1482      contents_,
1483      base::StringPrintf(
1484          "var languageSelect = document.getElementById('pod-row')"
1485          "    .getPodWithUsername_('%s').querySelector('.language-select');"
1486          "languageSelect.value = '%s';"
1487          "var event = document.createEvent('HTMLEvents');"
1488          "event.initEvent('change', false, true);"
1489          "languageSelect.dispatchEvent(event);",
1490          user_id_1_.c_str(),
1491          kPublicSessionLocale)));
1492
1493  // The UI will have requested an updated list of keyboard layouts at this
1494  // point. Wait for the constructions of this list to finish.
1495  WaitForGetKeyboardLayoutsForLocaleToFinish();
1496
1497  // Manually select a different keyboard layout and click the enter button to
1498  // start the session.
1499  ASSERT_TRUE(content::ExecuteScript(
1500      contents_,
1501      base::StringPrintf(
1502          "var pod ="
1503          "    document.getElementById('pod-row').getPodWithUsername_('%s');"
1504          "pod.querySelector('.keyboard-select').value = '%s';"
1505          "pod.querySelector('.enter-button').click();",
1506          user_id_1_.c_str(),
1507          public_session_input_method_id_.c_str())));
1508
1509  WaitForSessionStart();
1510
1511  // Verify that the locale and keyboard layout have been applied.
1512  EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale());
1513  EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale),
1514            icu::Locale::getDefault().getLanguage());
1515  EXPECT_EQ(public_session_input_method_id_,
1516            chromeos::input_method::InputMethodManager::Get()
1517                ->GetActiveIMEState()
1518                ->GetCurrentInputMethod()
1519                .id());
1520}
1521
1522IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, OneRecommendedLocale) {
1523  // Specify a recommended locale.
1524  SetRecommendedLocales(kSingleRecommendedLocale,
1525                        arraysize(kSingleRecommendedLocale));
1526  UploadAndInstallDeviceLocalAccountPolicy();
1527  AddPublicSessionToDevicePolicy(kAccountId1);
1528
1529  WaitForPolicy();
1530
1531  ExpandPublicSessionPod(false);
1532
1533  // Click the enter button to start the session.
1534  ASSERT_TRUE(content::ExecuteScript(
1535      contents_,
1536      base::StringPrintf(
1537          "document.getElementById('pod-row').getPodWithUsername_('%s')"
1538          "    .querySelector('.enter-button').click();",
1539          user_id_1_.c_str())));
1540
1541  WaitForSessionStart();
1542
1543  // Verify that the recommended locale has been applied and the first keyboard
1544  // layout applicable to the locale was chosen.
1545  EXPECT_EQ(kSingleRecommendedLocale[0],
1546            g_browser_process->GetApplicationLocale());
1547  EXPECT_EQ(l10n_util::GetLanguage(kSingleRecommendedLocale[0]),
1548            icu::Locale::getDefault().getLanguage());
1549  VerifyKeyboardLayoutMatchesLocale();
1550}
1551
1552IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, MultipleRecommendedLocales) {
1553  // Specify recommended locales.
1554  SetRecommendedLocales(kRecommendedLocales1, arraysize(kRecommendedLocales1));
1555  UploadAndInstallDeviceLocalAccountPolicy();
1556  AddPublicSessionToDevicePolicy(kAccountId1);
1557  AddPublicSessionToDevicePolicy(kAccountId2);
1558
1559  WaitForPolicy();
1560
1561  ExpandPublicSessionPod(true);
1562
1563  // Verify that the pod shows a list of locales beginning with the recommended
1564  // ones, followed by others.
1565  const std::string get_locale_list = base::StringPrintf(
1566      "var languageSelect = document.getElementById('pod-row')"
1567      "    .getPodWithUsername_('%s').querySelector('.language-select');"
1568      "var locales = [];"
1569      "for (var i = 0; i < languageSelect.length; ++i)"
1570      "  locales.push(languageSelect.options[i].value);"
1571      "domAutomationController.send(JSON.stringify(locales));",
1572      user_id_1_.c_str());
1573  std::string json;
1574  ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_,
1575                                                     get_locale_list,
1576                                                     &json));
1577  scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json));
1578  const base::ListValue* locales = NULL;
1579  ASSERT_TRUE(value_ptr);
1580  ASSERT_TRUE(value_ptr->GetAsList(&locales));
1581  EXPECT_LT(arraysize(kRecommendedLocales1), locales->GetSize());
1582
1583  // Verify that the list starts with the recommended locales, in correct order.
1584  for (size_t i = 0; i < arraysize(kRecommendedLocales1); ++i) {
1585    std::string locale;
1586    EXPECT_TRUE(locales->GetString(i, &locale));
1587    EXPECT_EQ(kRecommendedLocales1[i], locale);
1588  }
1589
1590  // Verify that the recommended locales do not appear again in the remainder of
1591  // the list.
1592  std::set<std::string> recommended_locales;
1593  for (size_t i = 0; i < arraysize(kRecommendedLocales1); ++i)
1594    recommended_locales.insert(kRecommendedLocales1[i]);
1595  for (size_t i = arraysize(kRecommendedLocales1); i < locales->GetSize();
1596       ++i) {
1597    std::string locale;
1598    EXPECT_TRUE(locales->GetString(i, &locale));
1599    EXPECT_EQ(recommended_locales.end(), recommended_locales.find(locale));
1600  }
1601
1602  // Verify that the first recommended locale is selected.
1603  const std::string get_selected_locale =
1604      base::StringPrintf(
1605          "domAutomationController.send(document.getElementById('pod-row')"
1606          "    .getPodWithUsername_('%s').querySelector('.language-select')"
1607          "        .value);",
1608          user_id_1_.c_str());
1609  std::string selected_locale;
1610  ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_,
1611                                                     get_selected_locale,
1612                                                     &selected_locale));
1613  EXPECT_EQ(kRecommendedLocales1[0], selected_locale);
1614
1615  // Change the list of recommended locales.
1616  SetRecommendedLocales(kRecommendedLocales2, arraysize(kRecommendedLocales2));
1617
1618  // Also change the display name as it is easy to ensure that policy has been
1619  // updated by waiting for a display name change.
1620  device_local_account_policy_.payload().mutable_userdisplayname()->set_value(
1621      kDisplayName2);
1622  UploadAndInstallDeviceLocalAccountPolicy();
1623  policy::BrowserPolicyConnectorChromeOS* connector =
1624      g_browser_process->platform_part()->browser_policy_connector_chromeos();
1625  DeviceLocalAccountPolicyBroker* broker =
1626      connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser(
1627          user_id_1_);
1628  ASSERT_TRUE(broker);
1629  broker->core()->store()->Load();
1630  WaitForDisplayName(user_id_1_, kDisplayName2);
1631
1632  // Verify that the new list of locales is shown in the UI.
1633  ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_,
1634                                                     get_locale_list,
1635                                                     &json));
1636  value_ptr.reset(base::JSONReader::Read(json));
1637  locales = NULL;
1638  ASSERT_TRUE(value_ptr);
1639  ASSERT_TRUE(value_ptr->GetAsList(&locales));
1640  EXPECT_LT(arraysize(kRecommendedLocales2), locales->GetSize());
1641  for (size_t i = 0; i < arraysize(kRecommendedLocales2); ++i) {
1642    std::string locale;
1643    EXPECT_TRUE(locales->GetString(i, &locale));
1644    EXPECT_EQ(kRecommendedLocales2[i], locale);
1645  }
1646
1647  // Verify that the first new recommended locale is selected.
1648  ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_,
1649                                                     get_selected_locale,
1650                                                     &selected_locale));
1651  EXPECT_EQ(kRecommendedLocales2[0], selected_locale);
1652
1653  // Manually select a different locale.
1654  ASSERT_TRUE(content::ExecuteScript(
1655      contents_,
1656      base::StringPrintf(
1657          "var languageSelect = document.getElementById('pod-row')"
1658          "    .getPodWithUsername_('%s').querySelector('.language-select');"
1659          "languageSelect.value = '%s';"
1660          "var event = document.createEvent('HTMLEvents');"
1661          "event.initEvent('change', false, true);"
1662          "languageSelect.dispatchEvent(event);",
1663          user_id_1_.c_str(),
1664          kPublicSessionLocale)));
1665
1666  // Change the list of recommended locales.
1667  SetRecommendedLocales(kRecommendedLocales2, arraysize(kRecommendedLocales2));
1668  device_local_account_policy_.payload().mutable_userdisplayname()->set_value(
1669      kDisplayName1);
1670  UploadAndInstallDeviceLocalAccountPolicy();
1671  broker->core()->store()->Load();
1672  WaitForDisplayName(user_id_1_, kDisplayName1);
1673
1674  // Verify that the manually selected locale is still selected.
1675  ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_,
1676                                                     get_selected_locale,
1677                                                     &selected_locale));
1678  EXPECT_EQ(kPublicSessionLocale, selected_locale);
1679
1680  // The UI will request an updated list of keyboard layouts at this point. Wait
1681  // for the constructions of this list to finish.
1682  WaitForGetKeyboardLayoutsForLocaleToFinish();
1683
1684  // Manually select a different keyboard layout.
1685  ASSERT_TRUE(content::ExecuteScript(
1686      contents_,
1687      base::StringPrintf(
1688          "document.getElementById('pod-row').getPodWithUsername_('%s')"
1689          "    .querySelector('.keyboard-select').value = '%s';",
1690          user_id_1_.c_str(),
1691          public_session_input_method_id_.c_str())));
1692
1693  // Click on a different pod, causing focus to shift away and the pod to
1694  // contract.
1695  ASSERT_TRUE(content::ExecuteScript(
1696      contents_,
1697      base::StringPrintf(
1698          "document.getElementById('pod-row').getPodWithUsername_('%s')"
1699          "    .click();",
1700          user_id_2_.c_str())));
1701
1702  // Click on the pod again, causing it to expand again. Verify that the pod has
1703  // kept all its state (the advanced form is being shown, the manually selected
1704  // locale and keyboard layout are selected).
1705  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1706      contents_,
1707      base::StringPrintf(
1708          "var pod ="
1709          "    document.getElementById('pod-row').getPodWithUsername_('%s');"
1710          "pod.click();"
1711          "var state = {};"
1712          "state.advanced = pod.classList.contains('advanced');"
1713          "state.locale = pod.querySelector('.language-select').value;"
1714          "state.keyboardLayout = pod.querySelector('.keyboard-select').value;"
1715          "console.log(JSON.stringify(state));"
1716          "domAutomationController.send(JSON.stringify(state));",
1717          user_id_1_.c_str()),
1718      &json));
1719  LOG(ERROR) << json;
1720  value_ptr.reset(base::JSONReader::Read(json));
1721  const base::DictionaryValue* state = NULL;
1722  ASSERT_TRUE(value_ptr);
1723  ASSERT_TRUE(value_ptr->GetAsDictionary(&state));
1724  bool advanced = false;
1725  EXPECT_TRUE(state->GetBoolean("advanced", &advanced));
1726  EXPECT_TRUE(advanced);
1727  EXPECT_TRUE(state->GetString("locale", &selected_locale));
1728  EXPECT_EQ(kPublicSessionLocale, selected_locale);
1729  std::string selected_keyboard_layout;
1730  EXPECT_TRUE(state->GetString("keyboardLayout", &selected_keyboard_layout));
1731  EXPECT_EQ(public_session_input_method_id_, selected_keyboard_layout);
1732
1733  // Click the enter button to start the session.
1734  ASSERT_TRUE(content::ExecuteScript(
1735      contents_,
1736      base::StringPrintf(
1737          "document.getElementById('pod-row').getPodWithUsername_('%s')"
1738          "    .querySelector('.enter-button').click();",
1739          user_id_1_.c_str())));
1740
1741  WaitForSessionStart();
1742
1743  // Verify that the locale and keyboard layout have been applied.
1744  EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale());
1745  EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale),
1746            icu::Locale::getDefault().getLanguage());
1747  EXPECT_EQ(public_session_input_method_id_,
1748            chromeos::input_method::InputMethodManager::Get()
1749                ->GetActiveIMEState()
1750                ->GetCurrentInputMethod()
1751                .id());
1752}
1753
1754IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, InvalidRecommendedLocale) {
1755  // Specify an invalid recommended locale.
1756  SetRecommendedLocales(kInvalidRecommendedLocale,
1757                        arraysize(kInvalidRecommendedLocale));
1758  UploadAndInstallDeviceLocalAccountPolicy();
1759  AddPublicSessionToDevicePolicy(kAccountId1);
1760
1761  WaitForPolicy();
1762
1763  // Click on the pod to expand it. Verify that the pod expands to its basic
1764  // form as there is only one recommended locale.
1765  bool advanced = false;
1766  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
1767      contents_,
1768      base::StringPrintf(
1769          "var pod ="
1770          "    document.getElementById('pod-row').getPodWithUsername_('%s');"
1771          "pod.click();"
1772          "domAutomationController.send(pod.classList.contains('advanced'));",
1773          user_id_1_.c_str()),
1774      &advanced));
1775  EXPECT_FALSE(advanced);
1776  EXPECT_EQ(l10n_util::GetLanguage(initial_locale_),
1777            icu::Locale::getDefault().getLanguage());
1778
1779  // Click the enter button to start the session.
1780  ASSERT_TRUE(content::ExecuteScript(
1781      contents_,
1782      base::StringPrintf(
1783          "document.getElementById('pod-row').getPodWithUsername_('%s')"
1784          "    .querySelector('.enter-button').click();",
1785          user_id_1_.c_str())));
1786
1787  WaitForSessionStart();
1788
1789  // Verify that since the recommended locale was invalid, the locale has not
1790  // changed and the first keyboard layout applicable to the locale was chosen.
1791  EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale());
1792  EXPECT_EQ(l10n_util::GetLanguage(initial_locale_),
1793            icu::Locale::getDefault().getLanguage());
1794  VerifyKeyboardLayoutMatchesLocale();
1795}
1796
1797IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest,
1798                       AutoLoginWithoutRecommendedLocales) {
1799  UploadAndInstallDeviceLocalAccountPolicy();
1800  AddPublicSessionToDevicePolicy(kAccountId1);
1801  EnableAutoLogin();
1802
1803  WaitForPolicy();
1804
1805  WaitForSessionStart();
1806
1807  // Verify that the locale has not changed and the first keyboard layout
1808  // applicable to the locale was chosen.
1809  EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale());
1810  EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage());
1811  VerifyKeyboardLayoutMatchesLocale();
1812}
1813
1814IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest,
1815                       AutoLoginWithRecommendedLocales) {
1816  // Specify recommended locales.
1817  SetRecommendedLocales(kRecommendedLocales1, arraysize(kRecommendedLocales1));
1818  UploadAndInstallDeviceLocalAccountPolicy();
1819  AddPublicSessionToDevicePolicy(kAccountId1);
1820  EnableAutoLogin();
1821
1822  WaitForPolicy();
1823
1824  WaitForSessionStart();
1825
1826  // Verify that the first recommended locale has been applied and the first
1827  // keyboard layout applicable to the locale was chosen.
1828  EXPECT_EQ(kRecommendedLocales1[0], g_browser_process->GetApplicationLocale());
1829  EXPECT_EQ(l10n_util::GetLanguage(kRecommendedLocales1[0]),
1830            icu::Locale::getDefault().getLanguage());
1831  VerifyKeyboardLayoutMatchesLocale();
1832}
1833
1834IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, TermsOfServiceWithLocaleSwitch) {
1835  // Specify Terms of Service URL.
1836  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
1837  device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value(
1838      embedded_test_server()->GetURL(
1839          std::string("/") + kExistentTermsOfServicePath).spec());
1840  UploadAndInstallDeviceLocalAccountPolicy();
1841  AddPublicSessionToDevicePolicy(kAccountId1);
1842
1843  WaitForPolicy();
1844
1845  // Select a different locale.
1846  ASSERT_TRUE(content::ExecuteScript(
1847      contents_,
1848      base::StringPrintf(
1849          "var languageSelect = document.getElementById('pod-row')"
1850          "    .getPodWithUsername_('%s').querySelector('.language-select');"
1851          "languageSelect.value = '%s';"
1852          "var event = document.createEvent('HTMLEvents');"
1853          "event.initEvent('change', false, true);"
1854          "languageSelect.dispatchEvent(event);",
1855          user_id_1_.c_str(),
1856          kPublicSessionLocale)));
1857
1858  // The UI will have requested an updated list of keyboard layouts at this
1859  // point. Wait for the constructions of this list to finish.
1860  WaitForGetKeyboardLayoutsForLocaleToFinish();
1861
1862  // Set up an observer that will quit the message loop when login has succeeded
1863  // and the first wizard screen, if any, is being shown.
1864  base::RunLoop login_wait_run_loop;
1865  chromeos::MockAuthStatusConsumer login_status_consumer;
1866  EXPECT_CALL(login_status_consumer, OnAuthSuccess(_)).Times(1).WillOnce(
1867      InvokeWithoutArgs(&login_wait_run_loop, &base::RunLoop::Quit));
1868  chromeos::ExistingUserController* controller =
1869      chromeos::ExistingUserController::current_controller();
1870  ASSERT_TRUE(controller);
1871  controller->set_login_status_consumer(&login_status_consumer);
1872
1873  // Manually select a different keyboard layout and click the enter button to
1874  // start the session.
1875  ASSERT_TRUE(content::ExecuteScript(
1876      contents_,
1877      base::StringPrintf(
1878          "var pod ="
1879          "    document.getElementById('pod-row').getPodWithUsername_('%s');"
1880          "pod.querySelector('.keyboard-select').value = '%s';"
1881          "pod.querySelector('.enter-button').click();",
1882          user_id_1_.c_str(),
1883          public_session_input_method_id_.c_str())));
1884
1885  // Spin the loop until the login observer fires. Then, unregister the
1886  // observer.
1887  login_wait_run_loop.Run();
1888  controller->set_login_status_consumer(NULL);
1889
1890  // Verify that the Terms of Service screen is being shown.
1891  chromeos::WizardController* wizard_controller =
1892        chromeos::WizardController::default_controller();
1893  ASSERT_TRUE(wizard_controller);
1894  ASSERT_TRUE(wizard_controller->current_screen());
1895  EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName,
1896            wizard_controller->current_screen()->GetName());
1897
1898  // Wait for the Terms of Service to finish downloading.
1899  bool done = false;
1900  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(contents_,
1901      "var screenElement = document.getElementById('terms-of-service');"
1902      "function SendReplyIfDownloadDone() {"
1903      "  if (screenElement.classList.contains('tos-loading'))"
1904      "    return false;"
1905      "  domAutomationController.send(true);"
1906      "  observer.disconnect();"
1907      "  return true;"
1908      "}"
1909      "var observer = new MutationObserver(SendReplyIfDownloadDone);"
1910      "if (!SendReplyIfDownloadDone()) {"
1911      "  var options = { attributes: true, attributeFilter: [ 'class' ] };"
1912      "  observer.observe(screenElement, options);"
1913      "}",
1914      &done));
1915
1916  // Verify that the locale and keyboard layout have been applied.
1917  EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale());
1918  EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale),
1919            icu::Locale::getDefault().getLanguage());
1920  EXPECT_EQ(public_session_input_method_id_,
1921            chromeos::input_method::InputMethodManager::Get()
1922                ->GetActiveIMEState()
1923                ->GetCurrentInputMethod()
1924                .id());
1925
1926  // Click the accept button.
1927  ASSERT_TRUE(content::ExecuteScript(contents_,
1928                                     "$('tos-accept-button').click();"));
1929
1930  WaitForSessionStart();
1931
1932  // Verify that the locale and keyboard layout are still in force.
1933  EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale());
1934  EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale),
1935            icu::Locale::getDefault().getLanguage());
1936  EXPECT_EQ(public_session_input_method_id_,
1937            chromeos::input_method::InputMethodManager::Get()
1938                ->GetActiveIMEState()
1939                ->GetCurrentInputMethod()
1940                .id());
1941}
1942
1943class TermsOfServiceDownloadTest : public DeviceLocalAccountTest,
1944                                   public testing::WithParamInterface<bool> {
1945};
1946
1947IN_PROC_BROWSER_TEST_P(TermsOfServiceDownloadTest, TermsOfServiceScreen) {
1948  // Specify Terms of Service URL.
1949  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
1950  device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value(
1951      embedded_test_server()->GetURL(
1952            std::string("/") +
1953                (GetParam() ? kExistentTermsOfServicePath
1954                            : kNonexistentTermsOfServicePath)).spec());
1955  UploadAndInstallDeviceLocalAccountPolicy();
1956  AddPublicSessionToDevicePolicy(kAccountId1);
1957
1958  WaitForPolicy();
1959
1960  ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string()));
1961
1962  // Set up an observer that will quit the message loop when login has succeeded
1963  // and the first wizard screen, if any, is being shown.
1964  base::RunLoop login_wait_run_loop;
1965  chromeos::MockAuthStatusConsumer login_status_consumer;
1966  EXPECT_CALL(login_status_consumer, OnAuthSuccess(_)).Times(1).WillOnce(
1967      InvokeWithoutArgs(&login_wait_run_loop, &base::RunLoop::Quit));
1968
1969  // Spin the loop until the observer fires. Then, unregister the observer.
1970  chromeos::ExistingUserController* controller =
1971      chromeos::ExistingUserController::current_controller();
1972  ASSERT_TRUE(controller);
1973  controller->set_login_status_consumer(&login_status_consumer);
1974  login_wait_run_loop.Run();
1975  controller->set_login_status_consumer(NULL);
1976
1977  // Verify that the Terms of Service screen is being shown.
1978  chromeos::WizardController* wizard_controller =
1979        chromeos::WizardController::default_controller();
1980  ASSERT_TRUE(wizard_controller);
1981  ASSERT_TRUE(wizard_controller->current_screen());
1982  EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName,
1983            wizard_controller->current_screen()->GetName());
1984
1985  // Wait for the Terms of Service to finish downloading, then get the status of
1986  // the screen's UI elements.
1987  std::string json;
1988  ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_,
1989      "var screenElement = document.getElementById('terms-of-service');"
1990      "function SendReplyIfDownloadDone() {"
1991      "  if (screenElement.classList.contains('tos-loading'))"
1992      "    return false;"
1993      "  var status = {};"
1994      "  status.heading = document.getElementById('tos-heading').textContent;"
1995      "  status.subheading ="
1996      "      document.getElementById('tos-subheading').textContent;"
1997      "  status.contentHeading ="
1998      "      document.getElementById('tos-content-heading').textContent;"
1999      "  status.content ="
2000      "      document.getElementById('tos-content-main').textContent;"
2001      "  status.error = screenElement.classList.contains('error');"
2002      "  status.acceptEnabled ="
2003      "      !document.getElementById('tos-accept-button').disabled;"
2004      "  domAutomationController.send(JSON.stringify(status));"
2005      "  observer.disconnect();"
2006      "  return true;"
2007      "}"
2008      "var observer = new MutationObserver(SendReplyIfDownloadDone);"
2009      "if (!SendReplyIfDownloadDone()) {"
2010      "  var options = { attributes: true, attributeFilter: [ 'class' ] };"
2011      "  observer.observe(screenElement, options);"
2012      "}",
2013      &json));
2014  scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json));
2015  const base::DictionaryValue* status = NULL;
2016  ASSERT_TRUE(value_ptr);
2017  ASSERT_TRUE(value_ptr->GetAsDictionary(&status));
2018  std::string heading;
2019  EXPECT_TRUE(status->GetString("heading", &heading));
2020  std::string subheading;
2021  EXPECT_TRUE(status->GetString("subheading", &subheading));
2022  std::string content_heading;
2023  EXPECT_TRUE(status->GetString("contentHeading", &content_heading));
2024  std::string content;
2025  EXPECT_TRUE(status->GetString("content", &content));
2026  bool error;
2027  EXPECT_TRUE(status->GetBoolean("error", &error));
2028  bool accept_enabled;
2029  EXPECT_TRUE(status->GetBoolean("acceptEnabled", &accept_enabled));
2030
2031  // Verify that the screen's headings have been set correctly.
2032  EXPECT_EQ(
2033      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_HEADING,
2034                                base::UTF8ToUTF16(kDomain)),
2035      heading);
2036  EXPECT_EQ(
2037      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_SUBHEADING,
2038                                base::UTF8ToUTF16(kDomain)),
2039      subheading);
2040  EXPECT_EQ(
2041      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_CONTENT_HEADING,
2042                                base::UTF8ToUTF16(kDomain)),
2043      content_heading);
2044
2045  if (!GetParam()) {
2046    // The Terms of Service URL was invalid. Verify that the screen is showing
2047    // an error and the accept button is disabled.
2048    EXPECT_TRUE(error);
2049    EXPECT_FALSE(accept_enabled);
2050    return;
2051  }
2052
2053  // The Terms of Service URL was valid. Verify that the screen is showing the
2054  // downloaded Terms of Service and the accept button is enabled.
2055  base::FilePath test_dir;
2056  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
2057  std::string terms_of_service;
2058  ASSERT_TRUE(base::ReadFileToString(
2059      test_dir.Append(kExistentTermsOfServicePath), &terms_of_service));
2060  EXPECT_EQ(terms_of_service, content);
2061  EXPECT_FALSE(error);
2062  EXPECT_TRUE(accept_enabled);
2063
2064  // Click the accept button.
2065  ASSERT_TRUE(content::ExecuteScript(contents_,
2066                                     "$('tos-accept-button').click();"));
2067
2068  WaitForSessionStart();
2069}
2070
2071INSTANTIATE_TEST_CASE_P(TermsOfServiceDownloadTestInstance,
2072                        TermsOfServiceDownloadTest, testing::Bool());
2073
2074}  // namespace policy
2075