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