device_local_account_browsertest.cc revision f2477e01787aa58f445919b809d89e252beef54f
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 <string>
7
8#include "base/basictypes.h"
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/callback.h"
12#include "base/command_line.h"
13#include "base/file_util.h"
14#include "base/files/file_path.h"
15#include "base/files/scoped_temp_dir.h"
16#include "base/json/json_reader.h"
17#include "base/location.h"
18#include "base/memory/ref_counted.h"
19#include "base/memory/scoped_ptr.h"
20#include "base/message_loop/message_loop.h"
21#include "base/message_loop/message_loop_proxy.h"
22#include "base/path_service.h"
23#include "base/run_loop.h"
24#include "base/sequenced_task_runner.h"
25#include "base/strings/string_number_conversions.h"
26#include "base/strings/string_util.h"
27#include "base/strings/stringprintf.h"
28#include "base/strings/utf_string_conversions.h"
29#include "base/test/scoped_path_override.h"
30#include "base/values.h"
31#include "chrome/browser/browser_process.h"
32#include "chrome/browser/chrome_notification_types.h"
33#include "chrome/browser/chromeos/login/existing_user_controller.h"
34#include "chrome/browser/chromeos/login/login_display_host.h"
35#include "chrome/browser/chromeos/login/login_display_host_impl.h"
36#include "chrome/browser/chromeos/login/mock_login_status_consumer.h"
37#include "chrome/browser/chromeos/login/screens/wizard_screen.h"
38#include "chrome/browser/chromeos/login/user.h"
39#include "chrome/browser/chromeos/login/user_manager.h"
40#include "chrome/browser/chromeos/login/webui_login_view.h"
41#include "chrome/browser/chromeos/login/wizard_controller.h"
42#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base.h"
43#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
44#include "chrome/browser/chromeos/policy/device_local_account.h"
45#include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
46#include "chrome/browser/chromeos/policy/device_policy_builder.h"
47#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
48#include "chrome/browser/extensions/extension_service.h"
49#include "chrome/browser/extensions/extension_system.h"
50#include "chrome/browser/lifetime/application_lifetime.h"
51#include "chrome/browser/policy/browser_policy_connector.h"
52#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
53#include "chrome/browser/policy/cloud/cloud_policy_core.h"
54#include "chrome/browser/policy/cloud/cloud_policy_store.h"
55#include "chrome/browser/policy/cloud/policy_builder.h"
56#include "chrome/browser/policy/policy_service.h"
57#include "chrome/browser/policy/profile_policy_connector.h"
58#include "chrome/browser/policy/profile_policy_connector_factory.h"
59#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
60#include "chrome/browser/policy/test/local_policy_test_server.h"
61#include "chrome/browser/prefs/session_startup_pref.h"
62#include "chrome/browser/profiles/profile.h"
63#include "chrome/browser/profiles/profile_manager.h"
64#include "chrome/browser/ui/browser.h"
65#include "chrome/browser/ui/browser_commands.h"
66#include "chrome/browser/ui/browser_finder.h"
67#include "chrome/browser/ui/browser_list.h"
68#include "chrome/browser/ui/browser_window.h"
69#include "chrome/browser/ui/host_desktop.h"
70#include "chrome/browser/ui/tabs/tab_strip_model.h"
71#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
72#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
73#include "chrome/common/chrome_paths.h"
74#include "chrome/common/chrome_switches.h"
75#include "chromeos/chromeos_paths.h"
76#include "chromeos/chromeos_switches.h"
77#include "chromeos/dbus/cryptohome_client.h"
78#include "chromeos/dbus/dbus_method_call_status.h"
79#include "chromeos/dbus/fake_session_manager_client.h"
80#include "chromeos/dbus/session_manager_client.h"
81#include "components/policy/core/common/external_data_fetcher.h"
82#include "components/policy/core/common/policy_map.h"
83#include "components/policy/core/common/policy_namespace.h"
84#include "content/public/browser/notification_details.h"
85#include "content/public/browser/notification_source.h"
86#include "content/public/browser/web_contents.h"
87#include "content/public/browser/web_ui.h"
88#include "content/public/test/browser_test_utils.h"
89#include "content/public/test/test_utils.h"
90#include "crypto/rsa_private_key.h"
91#include "extensions/common/extension.h"
92#include "grit/chromium_strings.h"
93#include "grit/generated_resources.h"
94#include "net/base/url_util.h"
95#include "net/http/http_status_code.h"
96#include "net/test/embedded_test_server/embedded_test_server.h"
97#include "net/test/embedded_test_server/http_request.h"
98#include "net/test/embedded_test_server/http_response.h"
99#include "net/url_request/test_url_fetcher_factory.h"
100#include "net/url_request/url_fetcher_delegate.h"
101#include "net/url_request/url_request_status.h"
102#include "policy/policy_constants.h"
103#include "testing/gmock/include/gmock/gmock.h"
104#include "third_party/cros_system_api/dbus/service_constants.h"
105#include "ui/base/l10n/l10n_util.h"
106#include "url/gurl.h"
107
108namespace em = enterprise_management;
109
110using chromeos::LoginScreenContext;
111using testing::InvokeWithoutArgs;
112using testing::Return;
113using testing::_;
114
115namespace policy {
116
117namespace {
118
119const char kDomain[] = "example.com";
120const char kAccountId1[] = "dla1@example.com";
121const char kAccountId2[] = "dla2@example.com";
122const char kDisplayName[] = "display name";
123const char* kStartupURLs[] = {
124  "chrome://policy",
125  "chrome://about",
126};
127const char kExistentTermsOfServicePath[] = "chromeos/enterprise/tos.txt";
128const char kNonexistentTermsOfServicePath[] = "chromeos/enterprise/tos404.txt";
129const char kRelativeUpdateURL[] = "/service/update2/crx";
130const char kUpdateManifestHeader[] =
131    "<?xml version='1.0' encoding='UTF-8'?>\n"
132    "<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>\n";
133const char kUpdateManifestTemplate[] =
134    "  <app appid='%s'>\n"
135    "    <updatecheck codebase='%s' version='%s' />\n"
136    "  </app>\n";
137const char kUpdateManifestFooter[] =
138    "</gupdate>\n";
139const char kHostedAppID[] = "kbmnembihfiondgfjekmnmcbddelicoi";
140const char kHostedAppCRXPath[] = "extensions/hosted_app.crx";
141const char kHostedAppVersion[] = "1.0.0.0";
142const char kGoodExtensionID[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
143const char kGoodExtensionCRXPath[] = "extensions/good.crx";
144const char kGoodExtensionVersion[] = "1.0";
145
146const char kExternalData[] = "External data";
147const char kExternalDataURL[] = "http://localhost/external_data";
148
149// Helper that serves extension update manifests to Chrome.
150class TestingUpdateManifestProvider {
151 public:
152
153  // Update manifests will be served at |relative_update_url|.
154  explicit TestingUpdateManifestProvider(
155      const std::string& relative_update_url);
156  ~TestingUpdateManifestProvider();
157
158  // When an update manifest is requested for the given extension |id|, indicate
159  // that |version| of the extension can be downloaded at |crx_url|.
160  void AddUpdate(const std::string& id,
161                 const std::string& version,
162                 const GURL& crx_url);
163
164  // This method must be registered with the test's EmbeddedTestServer to start
165  // serving update manifests.
166  scoped_ptr<net::test_server::HttpResponse> HandleRequest(
167      const net::test_server::HttpRequest& request);
168
169 private:
170  struct Update {
171   public:
172    Update(const std::string& version, const GURL& crx_url);
173    Update();
174
175    std::string version;
176    GURL crx_url;
177  };
178  typedef std::map<std::string, Update> UpdateMap;
179  UpdateMap updates_;
180
181  const std::string relative_update_url_;
182
183  DISALLOW_COPY_AND_ASSIGN(TestingUpdateManifestProvider);
184};
185
186TestingUpdateManifestProvider::Update::Update(const std::string& version,
187                                              const GURL& crx_url)
188    : version(version),
189      crx_url(crx_url) {
190}
191
192TestingUpdateManifestProvider::Update::Update() {
193}
194
195TestingUpdateManifestProvider::TestingUpdateManifestProvider(
196    const std::string& relative_update_url)
197    : relative_update_url_(relative_update_url) {
198}
199
200TestingUpdateManifestProvider::~TestingUpdateManifestProvider() {
201}
202
203void TestingUpdateManifestProvider::AddUpdate(const std::string& id,
204                                              const std::string& version,
205                                              const GURL& crx_url) {
206  updates_[id] = Update(version, crx_url);
207}
208
209scoped_ptr<net::test_server::HttpResponse>
210    TestingUpdateManifestProvider::HandleRequest(
211        const net::test_server::HttpRequest& request) {
212  const GURL url("http://localhost" + request.relative_url);
213  if (url.path() != relative_update_url_)
214    return scoped_ptr<net::test_server::HttpResponse>();
215
216  std::string content = kUpdateManifestHeader;
217  for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
218    if (it.GetKey() != "x")
219      continue;
220    // Extract the extension id from the subquery. Since GetValueForKeyInQuery()
221    // expects a complete URL, dummy scheme and host must be prepended.
222    std::string id;
223    net::GetValueForKeyInQuery(GURL("http://dummy?" + it.GetUnescapedValue()),
224                               "id", &id);
225    UpdateMap::const_iterator entry = updates_.find(id);
226    if (entry != updates_.end()) {
227      content += base::StringPrintf(kUpdateManifestTemplate,
228                                    id.c_str(),
229                                    entry->second.crx_url.spec().c_str(),
230                                    entry->second.version.c_str());
231    }
232  }
233  content += kUpdateManifestFooter;
234  scoped_ptr<net::test_server::BasicHttpResponse>
235      http_response(new net::test_server::BasicHttpResponse);
236  http_response->set_code(net::HTTP_OK);
237  http_response->set_content(content);
238  http_response->set_content_type("text/xml");
239  return http_response.PassAs<net::test_server::HttpResponse>();
240}
241
242bool DoesInstallSuccessReferToId(const std::string& id,
243                                 const content::NotificationSource& source,
244                                 const content::NotificationDetails& details) {
245  return content::Details<const extensions::InstalledExtensionInfo>(details)->
246      extension->id() == id;
247}
248
249bool DoesInstallFailureReferToId(const std::string& id,
250                                 const content::NotificationSource& source,
251                                 const content::NotificationDetails& details) {
252  return content::Details<const string16>(details)->find(UTF8ToUTF16(id)) !=
253      string16::npos;
254}
255
256scoped_ptr<net::FakeURLFetcher> RunCallbackAndReturnFakeURLFetcher(
257    scoped_refptr<base::SequencedTaskRunner> task_runner,
258    const base::Closure& callback,
259    const GURL& url,
260    net::URLFetcherDelegate* delegate,
261    const std::string& response_data,
262    net::HttpStatusCode response_code,
263    net::URLRequestStatus::Status status) {
264  task_runner->PostTask(FROM_HERE, callback);
265  return make_scoped_ptr(new net::FakeURLFetcher(
266      url, delegate, response_data, response_code, status));
267}
268
269}  // namespace
270
271class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest {
272 protected:
273  DeviceLocalAccountTest()
274      : user_id_1_(GenerateDeviceLocalAccountUserId(
275            kAccountId1, DeviceLocalAccount::TYPE_PUBLIC_SESSION)),
276        user_id_2_(GenerateDeviceLocalAccountUserId(
277            kAccountId2, DeviceLocalAccount::TYPE_PUBLIC_SESSION)) {}
278
279  virtual ~DeviceLocalAccountTest() {}
280
281  virtual void SetUp() OVERRIDE {
282    // Configure and start the test server.
283    scoped_ptr<crypto::RSAPrivateKey> signing_key(
284        PolicyBuilder::CreateTestSigningKey());
285    ASSERT_TRUE(test_server_.SetSigningKey(signing_key.get()));
286    signing_key.reset();
287    test_server_.RegisterClient(PolicyBuilder::kFakeToken,
288                                PolicyBuilder::kFakeDeviceId);
289    ASSERT_TRUE(test_server_.Start());
290
291    ASSERT_TRUE(extension_cache_root_dir_.CreateUniqueTempDir());
292    extension_cache_root_dir_override_.reset(new base::ScopedPathOverride(
293        chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
294        extension_cache_root_dir_.path()));
295    ASSERT_TRUE(external_data_cache_dir_.CreateUniqueTempDir());
296    external_data_cache_dir_override_.reset(new base::ScopedPathOverride(
297        chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA,
298        external_data_cache_dir_.path()));
299
300    DevicePolicyCrosBrowserTest::SetUp();
301  }
302
303  void SetUpCommandLineExceptDeviceManagementURL(CommandLine* command_line) {
304    command_line->AppendSwitch(chromeos::switches::kLoginManager);
305    command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
306    command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
307  }
308
309  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
310    SetUpCommandLineExceptDeviceManagementURL(command_line);
311    command_line->AppendSwitchASCII(
312        switches::kDeviceManagementUrl, test_server_.GetServiceURL().spec());
313  }
314
315  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
316    DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
317
318    // Clear command-line arguments (but keep command-line switches) so the
319    // startup pages policy takes effect.
320    CommandLine* command_line = CommandLine::ForCurrentProcess();
321    CommandLine::StringVector argv(command_line->argv());
322    argv.erase(argv.begin() + argv.size() - command_line->GetArgs().size(),
323               argv.end());
324    command_line->InitFromArgv(argv);
325
326    InstallOwnerKey();
327    MarkAsEnterpriseOwned();
328
329    InitializePolicy();
330  }
331
332  virtual void CleanUpOnMainThread() OVERRIDE {
333    // This shuts down the login UI.
334    base::MessageLoop::current()->PostTask(FROM_HERE,
335                                           base::Bind(&chrome::AttemptExit));
336    base::RunLoop().RunUntilIdle();
337  }
338
339  void InitializePolicy() {
340    device_policy()->policy_data().set_public_key_version(1);
341    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
342    proto.mutable_show_user_names()->set_show_user_names(true);
343
344    device_local_account_policy_.policy_data().set_policy_type(
345        dm_protocol::kChromePublicAccountPolicyType);
346    device_local_account_policy_.policy_data().set_username(kAccountId1);
347    device_local_account_policy_.policy_data().set_settings_entity_id(
348        kAccountId1);
349    device_local_account_policy_.policy_data().set_public_key_version(1);
350    device_local_account_policy_.payload().mutable_userdisplayname()->set_value(
351        kDisplayName);
352  }
353
354  void BuildDeviceLocalAccountPolicy() {
355    device_local_account_policy_.SetDefaultSigningKey();
356    device_local_account_policy_.Build();
357  }
358
359  void UploadDeviceLocalAccountPolicy() {
360    BuildDeviceLocalAccountPolicy();
361    ASSERT_TRUE(session_manager_client()->device_local_account_policy(
362        kAccountId1).empty());
363    test_server_.UpdatePolicy(
364        dm_protocol::kChromePublicAccountPolicyType, kAccountId1,
365        device_local_account_policy_.payload().SerializeAsString());
366  }
367
368  void UploadAndInstallDeviceLocalAccountPolicy() {
369    UploadDeviceLocalAccountPolicy();
370    session_manager_client()->set_device_local_account_policy(
371        kAccountId1, device_local_account_policy_.GetBlob());
372  }
373
374  void AddPublicSessionToDevicePolicy(const std::string& username) {
375    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
376    em::DeviceLocalAccountInfoProto* account =
377        proto.mutable_device_local_accounts()->add_account();
378    account->set_account_id(username);
379    account->set_type(
380        em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
381    RefreshDevicePolicy();
382    test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType,
383                              std::string(), proto.SerializeAsString());
384  }
385
386  void CheckPublicSessionPresent(const std::string& id) {
387    const chromeos::User* user = chromeos::UserManager::Get()->FindUser(id);
388    ASSERT_TRUE(user);
389    EXPECT_EQ(id, user->email());
390    EXPECT_EQ(chromeos::User::USER_TYPE_PUBLIC_ACCOUNT, user->GetType());
391  }
392
393  base::FilePath GetCacheDirectoryForAccountID(const std::string& account_id) {
394    return extension_cache_root_dir_.path()
395        .Append(base::HexEncode(account_id.c_str(), account_id.size()));
396  }
397
398  base::FilePath GetCacheCRXFile(const std::string& account_id,
399                                 const std::string& id,
400                                 const std::string& version) {
401    return GetCacheDirectoryForAccountID(account_id)
402        .Append(base::StringPrintf("%s-%s.crx", id.c_str(), version.c_str()));
403  }
404
405  const std::string user_id_1_;
406  const std::string user_id_2_;
407
408  base::ScopedTempDir extension_cache_root_dir_;
409  base::ScopedTempDir external_data_cache_dir_;
410  scoped_ptr<base::ScopedPathOverride> extension_cache_root_dir_override_;
411  scoped_ptr<base::ScopedPathOverride> external_data_cache_dir_override_;
412
413  UserPolicyBuilder device_local_account_policy_;
414  LocalPolicyTestServer test_server_;
415};
416
417static bool IsKnownUser(const std::string& account_id) {
418  return chromeos::UserManager::Get()->IsKnownUser(account_id);
419}
420
421IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LoginScreen) {
422  AddPublicSessionToDevicePolicy(kAccountId1);
423  AddPublicSessionToDevicePolicy(kAccountId2);
424
425  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
426                                        base::Bind(&IsKnownUser, user_id_1_))
427      .Wait();
428  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
429                                        base::Bind(&IsKnownUser, user_id_2_))
430      .Wait();
431
432  CheckPublicSessionPresent(user_id_1_);
433  CheckPublicSessionPresent(user_id_2_);
434}
435
436static bool DisplayNameMatches(const std::string& account_id,
437                               const std::string& display_name) {
438  const chromeos::User* user =
439      chromeos::UserManager::Get()->FindUser(account_id);
440  if (!user || user->display_name().empty())
441    return false;
442  EXPECT_EQ(UTF8ToUTF16(display_name), user->display_name());
443  return true;
444}
445
446IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) {
447  UploadAndInstallDeviceLocalAccountPolicy();
448  AddPublicSessionToDevicePolicy(kAccountId1);
449
450  content::WindowedNotificationObserver(
451      chrome::NOTIFICATION_USER_LIST_CHANGED,
452      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
453}
454
455IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyDownload) {
456  UploadDeviceLocalAccountPolicy();
457  AddPublicSessionToDevicePolicy(kAccountId1);
458
459  // Policy for the account is not installed in session_manager_client. Because
460  // of this, the presence of the display name (which comes from policy) can be
461  // used as a signal that indicates successful policy download.
462  content::WindowedNotificationObserver(
463      chrome::NOTIFICATION_USER_LIST_CHANGED,
464      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
465
466  // Sanity check: The policy should be present now.
467  ASSERT_FALSE(session_manager_client()->device_local_account_policy(
468      kAccountId1).empty());
469}
470
471static bool IsNotKnownUser(const std::string& account_id) {
472  return !IsKnownUser(account_id);
473}
474
475IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DevicePolicyChange) {
476  AddPublicSessionToDevicePolicy(kAccountId1);
477  AddPublicSessionToDevicePolicy(kAccountId2);
478
479  // Wait until the login screen is up.
480  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
481                                        base::Bind(&IsKnownUser, user_id_1_))
482      .Wait();
483  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
484                                        base::Bind(&IsKnownUser, user_id_2_))
485      .Wait();
486
487  // Update policy to remove kAccountId2.
488  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
489  proto.mutable_device_local_accounts()->clear_account();
490  AddPublicSessionToDevicePolicy(kAccountId1);
491
492  em::ChromeDeviceSettingsProto policy;
493  policy.mutable_show_user_names()->set_show_user_names(true);
494  em::DeviceLocalAccountInfoProto* account1 =
495      policy.mutable_device_local_accounts()->add_account();
496  account1->set_account_id(kAccountId1);
497  account1->set_type(
498      em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
499
500  test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, std::string(),
501                            policy.SerializeAsString());
502  g_browser_process->policy_service()->RefreshPolicies(base::Closure());
503
504  // Make sure the second device-local account disappears.
505  content::WindowedNotificationObserver(
506      chrome::NOTIFICATION_USER_LIST_CHANGED,
507      base::Bind(&IsNotKnownUser, user_id_2_)).Wait();
508}
509
510static bool IsSessionStarted() {
511  return chromeos::UserManager::Get()->IsSessionStarted();
512}
513
514IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, StartSession) {
515  // Specify startup pages.
516  device_local_account_policy_.payload().mutable_restoreonstartup()->set_value(
517      SessionStartupPref::kPrefValueURLs);
518  em::StringListPolicyProto* startup_urls_proto =
519      device_local_account_policy_.payload().mutable_restoreonstartupurls();
520  for (size_t i = 0; i < arraysize(kStartupURLs); ++i)
521    startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]);
522  UploadAndInstallDeviceLocalAccountPolicy();
523  AddPublicSessionToDevicePolicy(kAccountId1);
524
525  // This observes the display name becoming available as this indicates
526  // device-local account policy is fully loaded, which is a prerequisite for
527  // successful login.
528  content::WindowedNotificationObserver(
529      chrome::NOTIFICATION_USER_LIST_CHANGED,
530      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
531
532  // Wait for the login UI to be ready.
533  chromeos::LoginDisplayHostImpl* host =
534      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
535          chromeos::LoginDisplayHostImpl::default_host());
536  ASSERT_TRUE(host);
537  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
538  ASSERT_TRUE(oobe_ui);
539  base::RunLoop run_loop;
540  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
541  if (!oobe_ui_ready)
542    run_loop.Run();
543
544  // Start login into the device-local account.
545  host->StartSignInScreen(LoginScreenContext());
546  chromeos::ExistingUserController* controller =
547      chromeos::ExistingUserController::current_controller();
548  ASSERT_TRUE(controller);
549  controller->LoginAsPublicAccount(user_id_1_);
550
551  // Wait for the session to start.
552  content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
553                                        base::Bind(IsSessionStarted)).Wait();
554
555  // Check that the startup pages specified in policy were opened.
556  BrowserList* browser_list =
557    BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
558  EXPECT_EQ(1U, browser_list->size());
559  Browser* browser = browser_list->get(0);
560  ASSERT_TRUE(browser);
561
562  TabStripModel* tabs = browser->tab_strip_model();
563  ASSERT_TRUE(tabs);
564  int expected_tab_count = static_cast<int>(arraysize(kStartupURLs));
565  EXPECT_EQ(expected_tab_count, tabs->count());
566  for (int i = 0; i < expected_tab_count && i < tabs->count(); ++i) {
567    EXPECT_EQ(GURL(kStartupURLs[i]),
568              tabs->GetWebContentsAt(i)->GetVisibleURL());
569  }
570}
571
572IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, FullscreenDisallowed) {
573  UploadAndInstallDeviceLocalAccountPolicy();
574  AddPublicSessionToDevicePolicy(kAccountId1);
575
576  // This observes the display name becoming available as this indicates
577  // device-local account policy is fully loaded, which is a prerequisite for
578  // successful login.
579  content::WindowedNotificationObserver(
580      chrome::NOTIFICATION_USER_LIST_CHANGED,
581      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
582
583  // Wait for the login UI to be ready.
584  chromeos::LoginDisplayHostImpl* host =
585      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
586          chromeos::LoginDisplayHostImpl::default_host());
587  ASSERT_TRUE(host);
588  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
589  ASSERT_TRUE(oobe_ui);
590  base::RunLoop run_loop;
591  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
592  if (!oobe_ui_ready)
593    run_loop.Run();
594
595  // Ensure that the browser stays alive, even though no windows are opened
596  // during session start.
597  chrome::StartKeepAlive();
598
599  // Start login into the device-local account.
600  host->StartSignInScreen(LoginScreenContext());
601  chromeos::ExistingUserController* controller =
602      chromeos::ExistingUserController::current_controller();
603  ASSERT_TRUE(controller);
604  controller->LoginAsPublicAccount(user_id_1_);
605
606  // Wait for the session to start.
607  content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
608                                        base::Bind(IsSessionStarted)).Wait();
609
610  // Open a browser window.
611  chrome::NewEmptyWindow(ProfileManager::GetDefaultProfile(),
612                         chrome::HOST_DESKTOP_TYPE_ASH);
613  BrowserList* browser_list =
614    BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
615  EXPECT_EQ(1U, browser_list->size());
616  Browser* browser = browser_list->get(0);
617  ASSERT_TRUE(browser);
618  BrowserWindow* browser_window = browser->window();
619  ASSERT_TRUE(browser_window);
620  chrome::EndKeepAlive();
621
622  // Verify that an attempt to enter fullscreen mode is denied.
623  EXPECT_FALSE(browser_window->IsFullscreen());
624  chrome::ToggleFullscreenMode(browser);
625  EXPECT_FALSE(browser_window->IsFullscreen());
626}
627
628IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsUncached) {
629  // Make it possible to force-install a hosted app and an extension.
630  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
631  TestingUpdateManifestProvider testing_update_manifest_provider(
632      kRelativeUpdateURL);
633  testing_update_manifest_provider.AddUpdate(
634      kHostedAppID,
635      kHostedAppVersion,
636      embedded_test_server()->GetURL(std::string("/") + kHostedAppCRXPath));
637  testing_update_manifest_provider.AddUpdate(
638      kGoodExtensionID,
639      kGoodExtensionVersion,
640      embedded_test_server()->GetURL(std::string("/") + kGoodExtensionCRXPath));
641  embedded_test_server()->RegisterRequestHandler(
642      base::Bind(&TestingUpdateManifestProvider::HandleRequest,
643                 base::Unretained(&testing_update_manifest_provider)));
644
645  // Specify policy to force-install the hosted app and the extension.
646  em::StringList* forcelist = device_local_account_policy_.payload()
647      .mutable_extensioninstallforcelist()->mutable_value();
648  forcelist->add_entries(base::StringPrintf(
649      "%s;%s",
650      kHostedAppID,
651      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
652  forcelist->add_entries(base::StringPrintf(
653      "%s;%s",
654      kGoodExtensionID,
655      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
656
657  UploadAndInstallDeviceLocalAccountPolicy();
658  AddPublicSessionToDevicePolicy(kAccountId1);
659
660  // This observes the display name becoming available as this indicates
661  // device-local account policy is fully loaded, which is a prerequisite for
662  // successful login.
663  content::WindowedNotificationObserver(
664      chrome::NOTIFICATION_USER_LIST_CHANGED,
665      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
666
667  // Wait for the login UI to be ready.
668  chromeos::LoginDisplayHostImpl* host =
669      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
670          chromeos::LoginDisplayHostImpl::default_host());
671  ASSERT_TRUE(host);
672  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
673  ASSERT_TRUE(oobe_ui);
674  base::RunLoop run_loop;
675  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
676  if (!oobe_ui_ready)
677    run_loop.Run();
678
679  // Ensure that the browser stays alive, even though no windows are opened
680  // during session start.
681  chrome::StartKeepAlive();
682
683  // Start listening for app/extension installation results.
684  content::WindowedNotificationObserver hosted_app_observer(
685      chrome::NOTIFICATION_EXTENSION_INSTALLED,
686      base::Bind(DoesInstallSuccessReferToId, kHostedAppID));
687  content::WindowedNotificationObserver extension_observer(
688      chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
689      base::Bind(DoesInstallFailureReferToId, kGoodExtensionID));
690
691  // Start login into the device-local account.
692  host->StartSignInScreen(LoginScreenContext());
693  chromeos::ExistingUserController* controller =
694      chromeos::ExistingUserController::current_controller();
695  ASSERT_TRUE(controller);
696  controller->LoginAsPublicAccount(user_id_1_);
697
698  // Wait for the hosted app installation to succeed and the extension
699  // installation to fail (because hosted apps are whitelisted for use in
700  // device-local accounts and extensions are not).
701  hosted_app_observer.Wait();
702  extension_observer.Wait();
703
704  // Verify that the hosted app was installed.
705  Profile* profile = ProfileManager::GetDefaultProfile();
706  ASSERT_TRUE(profile);
707  ExtensionService* extension_service =
708      extensions::ExtensionSystem::Get(profile)->extension_service();
709  EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true));
710
711  // Verify that the extension was not installed.
712  EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
713
714  // Verify that the app was copied to the account's extension cache.
715  base::FilePath test_dir;
716  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
717  EXPECT_TRUE(ContentsEqual(
718          GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion),
719          test_dir.Append(kHostedAppCRXPath)));
720
721  // Verify that the extension was not copied to the account's extension cache.
722  EXPECT_FALSE(PathExists(GetCacheCRXFile(
723      kAccountId1, kGoodExtensionID, kGoodExtensionVersion)));
724}
725
726IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsCached) {
727  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
728
729  // Pre-populate the device local account's extension cache with a hosted app
730  // and an extension.
731  EXPECT_TRUE(file_util::CreateDirectory(
732      GetCacheDirectoryForAccountID(kAccountId1)));
733  base::FilePath test_dir;
734  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
735  const base::FilePath cached_hosted_app =
736      GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion);
737  EXPECT_TRUE(CopyFile(test_dir.Append(kHostedAppCRXPath),
738                       cached_hosted_app));
739  const base::FilePath cached_extension =
740      GetCacheCRXFile(kAccountId1, kGoodExtensionID, kGoodExtensionVersion);
741  EXPECT_TRUE(CopyFile(test_dir.Append(kGoodExtensionCRXPath),
742                       cached_extension));
743
744  // Specify policy to force-install the hosted app.
745  em::StringList* forcelist = device_local_account_policy_.payload()
746      .mutable_extensioninstallforcelist()->mutable_value();
747  forcelist->add_entries(base::StringPrintf(
748      "%s;%s",
749      kHostedAppID,
750      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
751  forcelist->add_entries(base::StringPrintf(
752      "%s;%s",
753      kGoodExtensionID,
754      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
755
756  UploadAndInstallDeviceLocalAccountPolicy();
757  AddPublicSessionToDevicePolicy(kAccountId1);
758
759  // This observes the display name becoming available as this indicates
760  // device-local account policy is fully loaded, which is a prerequisite for
761  // successful login.
762  content::WindowedNotificationObserver(
763      chrome::NOTIFICATION_USER_LIST_CHANGED,
764      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
765
766  // Wait for the login UI to be ready.
767  chromeos::LoginDisplayHostImpl* host =
768      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
769          chromeos::LoginDisplayHostImpl::default_host());
770  ASSERT_TRUE(host);
771  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
772  ASSERT_TRUE(oobe_ui);
773  base::RunLoop run_loop;
774  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
775  if (!oobe_ui_ready)
776    run_loop.Run();
777
778  // Ensure that the browser stays alive, even though no windows are opened
779  // during session start.
780  chrome::StartKeepAlive();
781
782  // Start listening for app/extension installation results.
783  content::WindowedNotificationObserver hosted_app_observer(
784      chrome::NOTIFICATION_EXTENSION_INSTALLED,
785      base::Bind(DoesInstallSuccessReferToId, kHostedAppID));
786  content::WindowedNotificationObserver extension_observer(
787      chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
788      base::Bind(DoesInstallFailureReferToId, kGoodExtensionID));
789
790  // Start login into the device-local account.
791  host->StartSignInScreen(LoginScreenContext());
792  chromeos::ExistingUserController* controller =
793      chromeos::ExistingUserController::current_controller();
794  ASSERT_TRUE(controller);
795  controller->LoginAsPublicAccount(user_id_1_);
796
797  // Wait for the hosted app installation to succeed and the extension
798  // installation to fail.
799  hosted_app_observer.Wait();
800  extension_observer.Wait();
801
802  // Verify that the hosted app was installed.
803  Profile* profile = ProfileManager::GetDefaultProfile();
804  ASSERT_TRUE(profile);
805  ExtensionService* extension_service =
806      extensions::ExtensionSystem::Get(profile)->extension_service();
807  EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true));
808
809  // Verify that the extension was not installed.
810  EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
811
812  // Verify that the app is still in the account's extension cache.
813  EXPECT_TRUE(PathExists(cached_hosted_app));
814
815  // Verify that the extension was removed from the account's extension cache.
816  EXPECT_FALSE(PathExists(cached_extension));
817}
818
819class DeviceLocalAccountExternalDataTest : public DeviceLocalAccountTest {
820 protected:
821  DeviceLocalAccountExternalDataTest();
822  virtual ~DeviceLocalAccountExternalDataTest();
823
824  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
825};
826
827DeviceLocalAccountExternalDataTest::DeviceLocalAccountExternalDataTest() {
828}
829
830DeviceLocalAccountExternalDataTest::~DeviceLocalAccountExternalDataTest() {
831}
832
833void DeviceLocalAccountExternalDataTest::SetUpCommandLine(
834    CommandLine* command_line) {
835  // This test modifies policy in memory by injecting an ExternalDataFetcher. Do
836  // not point the browser at the test_server_ so that no policy can be received
837  // from it and the modification does not get undone while the test is running.
838  // TODO(bartfab): Remove this and the whole DeviceLocalAccountExternalDataTest
839  // class once the first policy referencing external data is added and it is no
840  // longer necessary to inject an ExternalDataFetcher.
841  SetUpCommandLineExceptDeviceManagementURL(command_line);
842}
843
844IN_PROC_BROWSER_TEST_F(DeviceLocalAccountExternalDataTest, ExternalData) {
845  CloudExternalDataManagerBase::SetMaxExternalDataSizeForTesting(1000);
846
847  UploadAndInstallDeviceLocalAccountPolicy();
848  AddPublicSessionToDevicePolicy(kAccountId1);
849
850  // This observes the display name becoming available as this indicates
851  // device-local account policy is fully loaded.
852  content::WindowedNotificationObserver(
853      chrome::NOTIFICATION_USER_LIST_CHANGED,
854      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
855
856  scoped_ptr<base::DictionaryValue> metadata =
857      test::ConstructExternalDataReference(kExternalDataURL, kExternalData);
858  DeviceLocalAccountPolicyBroker* broker =
859      g_browser_process->browser_policy_connector()->
860          GetDeviceLocalAccountPolicyService()->GetBrokerForUser(user_id_1_);
861  ASSERT_TRUE(broker);
862
863  // Start serving external data at |kExternalDataURL|.
864  scoped_ptr<base::RunLoop> run_loop(new base::RunLoop);
865  scoped_ptr<net::FakeURLFetcherFactory> fetcher_factory(
866      new net::FakeURLFetcherFactory(
867          NULL,
868          base::Bind(&RunCallbackAndReturnFakeURLFetcher,
869                     base::MessageLoopProxy::current(),
870                     run_loop->QuitClosure())));
871  fetcher_factory->SetFakeResponse(GURL(kExternalDataURL),
872                                   kExternalData,
873                                   net::HTTP_OK,
874                                   net::URLRequestStatus::SUCCESS);
875
876  // TODO(bartfab): The test injects an ExternalDataFetcher for an arbitrary
877  // policy. This is only done because there are no policies that reference
878  // external data yet. Once the first such policy is added, switch the test to
879  // that policy and stop injecting a manually instantiated ExternalDataFetcher.
880  test::SetExternalDataReference(broker->core(),
881                                 key::kHomepageLocation,
882                                 make_scoped_ptr(metadata->DeepCopy()));
883
884  // The external data should be fetched and cached automatically. Wait for this
885  // fetch.
886  run_loop->Run();
887
888  // Stop serving external data at |kExternalDataURL|.
889  fetcher_factory.reset();
890
891  const PolicyMap::Entry* policy_entry =
892      broker->core()->store()->policy_map().Get(key::kHomepageLocation);
893  ASSERT_TRUE(policy_entry);
894  ASSERT_TRUE(policy_entry->external_data_fetcher);
895
896  // Retrieve the external data. Although the data is no longer being served at
897  // |kExternalDataURL|, the retrieval should succeed because the data has been
898  // cached.
899  run_loop.reset(new base::RunLoop);
900  scoped_ptr<std::string> fetched_external_data;
901  policy_entry->external_data_fetcher->Fetch(base::Bind(
902      &test::ExternalDataFetchCallback,
903      &fetched_external_data,
904      run_loop->QuitClosure()));
905  run_loop->Run();
906
907  ASSERT_TRUE(fetched_external_data);
908  EXPECT_EQ(kExternalData, *fetched_external_data);
909
910  // Wait for the login UI to be ready.
911  chromeos::LoginDisplayHostImpl* host =
912      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
913          chromeos::LoginDisplayHostImpl::default_host());
914  ASSERT_TRUE(host);
915  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
916  ASSERT_TRUE(oobe_ui);
917  run_loop.reset(new base::RunLoop);
918  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop->QuitClosure());
919  if (!oobe_ui_ready)
920    run_loop->Run();
921
922  // Ensure that the browser stays alive, even though no windows are opened
923  // during session start.
924  chrome::StartKeepAlive();
925
926  // Start login into the device-local account.
927  host->StartSignInScreen(LoginScreenContext());
928  chromeos::ExistingUserController* controller =
929      chromeos::ExistingUserController::current_controller();
930  ASSERT_TRUE(controller);
931  controller->LoginAsPublicAccount(user_id_1_);
932
933  // Wait for the session to start.
934  content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
935                                        base::Bind(IsSessionStarted)).Wait();
936
937  // Verify that the external data reference has propagated to the device-local
938  // account's ProfilePolicyConnector.
939  ProfilePolicyConnector* policy_connector =
940      ProfilePolicyConnectorFactory::GetForProfile(
941          ProfileManager::GetDefaultProfile());
942  ASSERT_TRUE(policy_connector);
943  const PolicyMap& policies = policy_connector->policy_service()->GetPolicies(
944      PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
945  policy_entry = policies.Get(key::kHomepageLocation);
946  ASSERT_TRUE(policy_entry);
947  EXPECT_TRUE(base::Value::Equals(metadata.get(), policy_entry->value));
948  ASSERT_TRUE(policy_entry->external_data_fetcher);
949
950  // Retrieve the external data via the ProfilePolicyConnector. The retrieval
951  // should succeed because the data has been cached.
952  run_loop.reset(new base::RunLoop);
953  fetched_external_data.reset();
954  policy_entry->external_data_fetcher->Fetch(base::Bind(
955      &test::ExternalDataFetchCallback,
956      &fetched_external_data,
957      run_loop->QuitClosure()));
958  run_loop->Run();
959
960  ASSERT_TRUE(fetched_external_data);
961  EXPECT_EQ(kExternalData, *fetched_external_data);
962}
963
964class TermsOfServiceTest : public DeviceLocalAccountTest,
965                           public testing::WithParamInterface<bool> {
966};
967
968IN_PROC_BROWSER_TEST_P(TermsOfServiceTest, TermsOfServiceScreen) {
969  // Specify Terms of Service URL.
970  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
971  device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value(
972      embedded_test_server()->GetURL(
973            std::string("/") +
974                (GetParam() ? kExistentTermsOfServicePath
975                            : kNonexistentTermsOfServicePath)).spec());
976  UploadAndInstallDeviceLocalAccountPolicy();
977  AddPublicSessionToDevicePolicy(kAccountId1);
978
979  // Wait for the device-local account policy to be fully loaded.
980  content::WindowedNotificationObserver(
981      chrome::NOTIFICATION_USER_LIST_CHANGED,
982      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
983
984  // Wait for the login UI to be ready.
985  chromeos::LoginDisplayHostImpl* host =
986      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
987          chromeos::LoginDisplayHostImpl::default_host());
988  ASSERT_TRUE(host);
989  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
990  ASSERT_TRUE(oobe_ui);
991  base::RunLoop oobe_ui_wait_run_loop;
992  const bool oobe_ui_ready =
993      oobe_ui->IsJSReady(oobe_ui_wait_run_loop.QuitClosure());
994  if (!oobe_ui_ready)
995    oobe_ui_wait_run_loop.Run();
996
997  // Start login into the device-local account.
998  host->StartSignInScreen(LoginScreenContext());
999  chromeos::ExistingUserController* controller =
1000      chromeos::ExistingUserController::current_controller();
1001  ASSERT_TRUE(controller);
1002  controller->LoginAsPublicAccount(user_id_1_);
1003
1004  // Set up an observer that will quit the message loop when login has succeeded
1005  // and the first wizard screen, if any, is being shown.
1006  base::RunLoop login_wait_run_loop;
1007  chromeos::MockConsumer login_status_consumer;
1008  EXPECT_CALL(login_status_consumer, OnLoginSuccess(_))
1009      .Times(1)
1010      .WillOnce(InvokeWithoutArgs(&login_wait_run_loop, &base::RunLoop::Quit));
1011
1012  // Spin the loop until the observer fires. Then, unregister the observer.
1013  controller->set_login_status_consumer(&login_status_consumer);
1014  login_wait_run_loop.Run();
1015  controller->set_login_status_consumer(NULL);
1016
1017  // Verify that the Terms of Service screen is being shown.
1018  chromeos::WizardController* wizard_controller =
1019        chromeos::WizardController::default_controller();
1020  ASSERT_TRUE(wizard_controller);
1021  ASSERT_TRUE(wizard_controller->current_screen());
1022  EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName,
1023            wizard_controller->current_screen()->GetName());
1024
1025  // Wait for the Terms of Service to finish downloading, then get the status of
1026  // the screen's UI elements.
1027  chromeos::WebUILoginView* web_ui_login_view = host->GetWebUILoginView();
1028  ASSERT_TRUE(web_ui_login_view);
1029  content::WebUI* web_ui = web_ui_login_view->GetWebUI();
1030  ASSERT_TRUE(web_ui);
1031  content::WebContents* contents = web_ui->GetWebContents();
1032  ASSERT_TRUE(contents);
1033  std::string json;
1034  ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents,
1035      "var screen = document.getElementById('terms-of-service');"
1036      "function SendReplyIfDownloadDone() {"
1037      "  if (screen.classList.contains('tos-loading'))"
1038      "    return false;"
1039      "  var status = {};"
1040      "  status.heading = document.getElementById('tos-heading').textContent;"
1041      "  status.subheading ="
1042      "      document.getElementById('tos-subheading').textContent;"
1043      "  status.contentHeading ="
1044      "      document.getElementById('tos-content-heading').textContent;"
1045      "  status.content ="
1046      "      document.getElementById('tos-content-main').textContent;"
1047      "  status.error = screen.classList.contains('error');"
1048      "  status.acceptEnabled ="
1049      "      !document.getElementById('tos-accept-button').disabled;"
1050      "  domAutomationController.send(JSON.stringify(status));"
1051      "  observer.disconnect();"
1052      "  return true;"
1053      "}"
1054      "var observer = new MutationObserver(SendReplyIfDownloadDone);"
1055      "if (!SendReplyIfDownloadDone()) {"
1056      "  var options = { attributes: true, attributeFilter: [ 'class' ] };"
1057      "  observer.observe(screen, options);"
1058      "}",
1059      &json));
1060  scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json));
1061  const base::DictionaryValue* status = NULL;
1062  ASSERT_TRUE(value_ptr.get());
1063  ASSERT_TRUE(value_ptr->GetAsDictionary(&status));
1064  std::string heading;
1065  EXPECT_TRUE(status->GetString("heading", &heading));
1066  std::string subheading;
1067  EXPECT_TRUE(status->GetString("subheading", &subheading));
1068  std::string content_heading;
1069  EXPECT_TRUE(status->GetString("contentHeading", &content_heading));
1070  std::string content;
1071  EXPECT_TRUE(status->GetString("content", &content));
1072  bool error;
1073  EXPECT_TRUE(status->GetBoolean("error", &error));
1074  bool accept_enabled;
1075  EXPECT_TRUE(status->GetBoolean("acceptEnabled", &accept_enabled));
1076
1077  // Verify that the screen's headings have been set correctly.
1078  EXPECT_EQ(
1079      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_HEADING,
1080                                UTF8ToUTF16(kDomain)),
1081      heading);
1082  EXPECT_EQ(
1083      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_SUBHEADING,
1084                                UTF8ToUTF16(kDomain)),
1085      subheading);
1086  EXPECT_EQ(
1087      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_CONTENT_HEADING,
1088                                UTF8ToUTF16(kDomain)),
1089      content_heading);
1090
1091  if (!GetParam()) {
1092    // The Terms of Service URL was invalid. Verify that the screen is showing
1093    // an error and the accept button is disabled.
1094    EXPECT_TRUE(error);
1095    EXPECT_FALSE(accept_enabled);
1096    return;
1097  }
1098
1099  // The Terms of Service URL was valid. Verify that the screen is showing the
1100  // downloaded Terms of Service and the accept button is enabled.
1101  base::FilePath test_dir;
1102  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
1103  std::string terms_of_service;
1104  ASSERT_TRUE(base::ReadFileToString(
1105      test_dir.Append(kExistentTermsOfServicePath), &terms_of_service));
1106  EXPECT_EQ(terms_of_service, content);
1107  EXPECT_FALSE(error);
1108  EXPECT_TRUE(accept_enabled);
1109
1110  // Click the accept button.
1111  ASSERT_TRUE(content::ExecuteScript(contents,
1112                                     "$('tos-accept-button').click();"));
1113
1114  // Wait for the session to start.
1115  if (!IsSessionStarted()) {
1116    content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
1117                                          base::Bind(IsSessionStarted)).Wait();
1118  }
1119}
1120
1121INSTANTIATE_TEST_CASE_P(TermsOfServiceTestInstance,
1122                        TermsOfServiceTest, testing::Bool());
1123
1124}  // namespace policy
1125