1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string>
6#include <vector>
7
8#include "base/command_line.h"
9#include "base/memory/ref_counted.h"
10#include "base/run_loop.h"
11#include "chrome/browser/chromeos/login/session/user_session_manager.h"
12#include "chrome/test/base/in_process_browser_test.h"
13#include "chromeos/chromeos_switches.h"
14#include "chromeos/dbus/cryptohome_client.h"
15#include "chromeos/dbus/dbus_thread_manager.h"
16#include "chromeos/dbus/fake_session_manager_client.h"
17#include "chromeos/dbus/session_manager_client.h"
18#include "components/user_manager/user.h"
19#include "components/user_manager/user_manager.h"
20#include "content/public/test/test_utils.h"
21#include "testing/gmock/include/gmock/gmock.h"
22#include "third_party/cros_system_api/dbus/service_constants.h"
23
24namespace chromeos {
25
26namespace {
27
28const char kUserId1[] = "user1@example.com";
29const char kUserId2[] = "user2@example.com";
30const char kUserId3[] = "user3@example.com";
31
32}  // namespace
33
34class CrashRestoreSimpleTest : public InProcessBrowserTest {
35 protected:
36  CrashRestoreSimpleTest() {}
37
38  virtual ~CrashRestoreSimpleTest() {}
39
40  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
41    command_line->AppendSwitchASCII(switches::kLoginUser, kUserId1);
42    command_line->AppendSwitchASCII(
43        switches::kLoginProfile,
44        CryptohomeClient::GetStubSanitizedUsername(kUserId1));
45  }
46
47  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
48    // Redirect session_manager DBus calls to FakeSessionManagerClient.
49    session_manager_client_ = new FakeSessionManagerClient;
50    chromeos::DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient(
51        scoped_ptr<SessionManagerClient>(session_manager_client_));
52    session_manager_client_->StartSession(kUserId1);
53  }
54
55  FakeSessionManagerClient* session_manager_client_;
56};
57
58IN_PROC_BROWSER_TEST_F(CrashRestoreSimpleTest, RestoreSessionForOneUser) {
59  user_manager::UserManager* user_manager = user_manager::UserManager::Get();
60  user_manager::User* user = user_manager->GetActiveUser();
61  ASSERT_TRUE(user);
62  EXPECT_EQ(kUserId1, user->email());
63  EXPECT_EQ(CryptohomeClient::GetStubSanitizedUsername(kUserId1),
64            user->username_hash());
65  EXPECT_EQ(1UL, user_manager->GetLoggedInUsers().size());
66}
67
68// Observer that keeps track of user sessions restore event.
69class UserSessionRestoreObserver : public UserSessionStateObserver {
70 public:
71  UserSessionRestoreObserver()
72      : running_loop_(false),
73        user_sessions_restored_(
74            UserSessionManager::GetInstance()->UserSessionsRestored()) {
75    if (!user_sessions_restored_)
76      UserSessionManager::GetInstance()->AddSessionStateObserver(this);
77  }
78  virtual ~UserSessionRestoreObserver() {}
79
80  virtual void PendingUserSessionsRestoreFinished() OVERRIDE {
81    user_sessions_restored_ = true;
82    UserSessionManager::GetInstance()->RemoveSessionStateObserver(this);
83    if (!running_loop_)
84      return;
85
86    message_loop_runner_->Quit();
87    running_loop_ = false;
88  }
89
90  // Wait until the user sessions are restored. If that happened between the
91  // construction of this object and this call or even before it was created
92  // then it returns immediately.
93  void Wait() {
94    if (user_sessions_restored_)
95      return;
96
97    running_loop_ = true;
98    message_loop_runner_ = new content::MessageLoopRunner();
99    message_loop_runner_->Run();
100  }
101
102 private:
103  bool running_loop_;
104  bool user_sessions_restored_;
105  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
106
107  DISALLOW_COPY_AND_ASSIGN(UserSessionRestoreObserver);
108};
109
110class CrashRestoreComplexTest : public CrashRestoreSimpleTest {
111 protected:
112  CrashRestoreComplexTest() {}
113  virtual ~CrashRestoreComplexTest() {}
114
115  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
116    CrashRestoreSimpleTest::SetUpInProcessBrowserTestFixture();
117    session_manager_client_->StartSession(kUserId2);
118    session_manager_client_->StartSession(kUserId3);
119  }
120};
121
122IN_PROC_BROWSER_TEST_F(CrashRestoreComplexTest, RestoreSessionForThreeUsers) {
123  {
124    UserSessionRestoreObserver restore_observer;
125    restore_observer.Wait();
126  }
127
128  DCHECK(UserSessionManager::GetInstance()->UserSessionsRestored());
129
130  // User that is last in the user sessions map becomes active. This behavior
131  // will become better defined once each user gets a separate user desktop.
132  user_manager::UserManager* user_manager = user_manager::UserManager::Get();
133  user_manager::User* user = user_manager->GetActiveUser();
134  ASSERT_TRUE(user);
135  EXPECT_EQ(kUserId3, user->email());
136  EXPECT_EQ(CryptohomeClient::GetStubSanitizedUsername(kUserId3),
137            user->username_hash());
138  const user_manager::UserList& users = user_manager->GetLoggedInUsers();
139  ASSERT_EQ(3UL, users.size());
140
141  // User that becomes active moves to the beginning of the list.
142  EXPECT_EQ(kUserId3, users[0]->email());
143  EXPECT_EQ(CryptohomeClient::GetStubSanitizedUsername(kUserId3),
144            users[0]->username_hash());
145  EXPECT_EQ(kUserId2, users[1]->email());
146  EXPECT_EQ(CryptohomeClient::GetStubSanitizedUsername(kUserId2),
147            users[1]->username_hash());
148  EXPECT_EQ(kUserId1, users[2]->email());
149  EXPECT_EQ(CryptohomeClient::GetStubSanitizedUsername(kUserId1),
150            users[2]->username_hash());
151}
152
153}  // namespace chromeos
154