1 // Copyright (c) 2012 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.
7 #include "base/command_line.h"
8 #include "base/file_util.h"
9 #include "base/memory/ref_counted_memory.h"
10 #include "base/path_service.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/prefs/scoped_user_pref_update.h"
13 #include "base/values.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/chromeos/login/default_user_images.h"
16 #include "chrome/browser/chromeos/login/mock_user_manager.h"
17 #include "chrome/browser/chromeos/login/user_image_manager_impl.h"
18 #include "chrome/browser/chromeos/login/user_manager.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/test/base/in_process_browser_test.h"
22 #include "chrome/test/base/testing_browser_process.h"
23 #include "chromeos/chromeos_switches.h"
24 #include "content/public/browser/notification_observer.h"
25 #include "content/public/browser/notification_registrar.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/test/test_utils.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 #include "ui/base/layout.h"
30 #include "ui/base/resource/resource_bundle.h"
34 const char kTestUser1[] = "test-user@example.com";
35 const char kTestUser2[] = "test-user2@example.com";
37 class UserImageManagerTest : public InProcessBrowserTest,
38 public content::NotificationObserver,
39 public UserManager::Observer {
41 UserImageManagerTest() {
44 // InProcessBrowserTest overrides:
45 virtual void SetUpOnMainThread() OVERRIDE {
46 UserManager::Get()->AddObserver(this);
47 user_image_manager_ = UserManager::Get()->GetUserImageManager();
48 local_state_ = g_browser_process->local_state();
49 // No migration delay for testing.
50 UserImageManagerImpl::user_image_migration_delay_sec = 0;
53 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
54 command_line->AppendSwitch(switches::kLoginManager);
55 command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
58 // content::NotificationObserver overrides:
59 virtual void Observe(int type,
60 const content::NotificationSource& source,
61 const content::NotificationDetails& details) OVERRIDE {
62 DCHECK(type == chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED);
63 registrar_.Remove(this, chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
64 content::NotificationService::AllSources());
65 base::MessageLoopForUI::current()->Quit();
68 // UserManager::Observer overrides:
69 virtual void LocalStateChanged(UserManager* user_manager) OVERRIDE {
70 base::MessageLoopForUI::current()->Quit();
73 // Adds given user to Local State, if not there.
74 void AddUser(const std::string& username) {
75 ListPrefUpdate users_pref(local_state_, "LoggedInUsers");
76 users_pref->AppendIfNotPresent(new base::StringValue(username));
79 // Logs in |username|.
80 void LogIn(const std::string& username) {
81 UserManager::Get()->UserLoggedIn(username, username, false);
84 // Subscribes for image change notification.
85 void ExpectImageChange() {
86 registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
87 content::NotificationService::AllSources());
90 // Stores old (pre-migration) user image info.
91 void SetOldUserImageInfo(const std::string& username,
93 const base::FilePath& image_path) {
95 DictionaryPrefUpdate images_pref(local_state_, "UserImages");
96 base::DictionaryValue* image_properties = new base::DictionaryValue();
97 image_properties->Set(
98 "index", base::Value::CreateIntegerValue(image_index));
99 image_properties->Set(
100 "path" , new base::StringValue(image_path.value()));
101 images_pref->SetWithoutPathExpansion(username, image_properties);
104 // Verifies user image info in |images_pref| dictionary.
105 void ExpectUserImageInfo(const base::DictionaryValue* images_pref,
106 const std::string& username,
108 const base::FilePath& image_path) {
109 ASSERT_TRUE(images_pref);
110 const base::DictionaryValue* image_properties = NULL;
111 images_pref->GetDictionaryWithoutPathExpansion(username, &image_properties);
112 ASSERT_TRUE(image_properties);
113 int actual_image_index;
114 std::string actual_image_path;
115 ASSERT_TRUE(image_properties->GetInteger("index", &actual_image_index) &&
116 image_properties->GetString("path", &actual_image_path));
117 EXPECT_EQ(image_index, actual_image_index);
118 EXPECT_EQ(image_path.value(), actual_image_path);
121 // Verifies that there is no image info for |username| in dictionary
123 void ExpectNoUserImageInfo(const base::DictionaryValue* images_pref,
124 const std::string& username) {
125 ASSERT_TRUE(images_pref);
126 const base::DictionaryValue* image_properties = NULL;
127 images_pref->GetDictionaryWithoutPathExpansion(username, &image_properties);
128 ASSERT_FALSE(image_properties);
131 // Verifies that old user image info matches |image_index| and |image_path|
132 // and that new user image info does not exist.
133 void ExpectOldUserImageInfo(const std::string& username,
135 const base::FilePath& image_path) {
136 ExpectUserImageInfo(local_state_->GetDictionary("UserImages"),
137 username, image_index, image_path);
138 ExpectNoUserImageInfo(local_state_->GetDictionary("user_image_info"),
142 // Verifies that new user image info matches |image_index| and |image_path|
143 // and that old user image info does not exist.
144 void ExpectNewUserImageInfo(const std::string& username,
146 const base::FilePath& image_path) {
147 ExpectUserImageInfo(local_state_->GetDictionary("user_image_info"),
148 username, image_index, image_path);
149 ExpectNoUserImageInfo(local_state_->GetDictionary("UserImages"),
153 // Sets bitmap |resource_id| as image for |username| and saves it to disk.
154 void SaveUserImagePNG(const std::string& username,
156 base::FilePath image_path = GetUserImagePath(username, "png");
157 scoped_refptr<base::RefCountedStaticMemory> image_data(
158 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
159 resource_id, ui::SCALE_FACTOR_100P));
160 int written = file_util::WriteFile(
162 reinterpret_cast<const char*>(image_data->front()),
164 EXPECT_EQ(static_cast<int>(image_data->size()), written);
165 SetOldUserImageInfo(username, User::kExternalImageIndex, image_path);
168 // Returns the image path for user |username| with specified |extension|.
169 base::FilePath GetUserImagePath(const std::string& username,
170 const std::string& extension) {
171 base::FilePath user_data_dir;
172 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
173 return user_data_dir.Append(username).AddExtension(extension);
176 UserImageManager* user_image_manager_;
177 PrefService* local_state_;
178 content::NotificationRegistrar registrar_;
181 DISALLOW_COPY_AND_ASSIGN(UserImageManagerTest);
184 IN_PROC_BROWSER_TEST_F(UserImageManagerTest, PRE_DefaultUserImagePreserved) {
185 // Setup an old default (stock) user image.
186 ScopedUserManagerEnabler(new MockUserManager);
187 SetOldUserImageInfo(kTestUser1, kFirstDefaultImageIndex, base::FilePath());
190 IN_PROC_BROWSER_TEST_F(UserImageManagerTest, DefaultUserImagePreserved) {
191 UserManager::Get()->GetUsers(); // Load users.
192 // Old info preserved.
193 ExpectOldUserImageInfo(kTestUser1, kFirstDefaultImageIndex, base::FilePath());
195 // Wait for migration.
196 content::RunMessageLoop();
197 // Image info is migrated now.
198 ExpectNewUserImageInfo(kTestUser1, kFirstDefaultImageIndex, base::FilePath());
201 IN_PROC_BROWSER_TEST_F(UserImageManagerTest, PRE_OtherUsersUnaffected) {
202 // Setup two users with stock images.
203 ScopedUserManagerEnabler(new MockUserManager);
204 SetOldUserImageInfo(kTestUser1, kFirstDefaultImageIndex, base::FilePath());
205 SetOldUserImageInfo(kTestUser2, kFirstDefaultImageIndex + 1,
209 IN_PROC_BROWSER_TEST_F(UserImageManagerTest, OtherUsersUnaffected) {
210 UserManager::Get()->GetUsers(); // Load users.
211 // Old info preserved.
212 ExpectOldUserImageInfo(kTestUser1, kFirstDefaultImageIndex, base::FilePath());
213 ExpectOldUserImageInfo(kTestUser2, kFirstDefaultImageIndex + 1,
216 // Wait for migration.
217 content::RunMessageLoop();
218 // Image info is migrated for the first user and unaffected for the rest.
219 ExpectNewUserImageInfo(kTestUser1, kFirstDefaultImageIndex, base::FilePath());
220 ExpectOldUserImageInfo(kTestUser2, kFirstDefaultImageIndex + 1,
224 IN_PROC_BROWSER_TEST_F(UserImageManagerTest, PRE_PRE_NonJPEGImageFromFile) {
225 // Setup a user with non-JPEG image.
226 ScopedUserManagerEnabler(new MockUserManager);
228 kTestUser1, kDefaultImageResourceIDs[kFirstDefaultImageIndex]);
231 IN_PROC_BROWSER_TEST_F(UserImageManagerTest, PRE_NonJPEGImageFromFile) {
232 UserManager::Get()->GetUsers(); // Load users.
233 // Old info preserved.
234 ExpectOldUserImageInfo(kTestUser1, User::kExternalImageIndex,
235 GetUserImagePath(kTestUser1, "png"));
236 const User* user = UserManager::Get()->FindUser(kTestUser1);
237 EXPECT_TRUE(user->image_is_stub());
239 // Wait for migration.
240 content::RunMessageLoop();
241 // Image info is migrated and the image is converted to JPG.
242 ExpectNewUserImageInfo(kTestUser1, User::kExternalImageIndex,
243 GetUserImagePath(kTestUser1, "jpg"));
244 user = UserManager::Get()->GetLoggedInUser();
246 EXPECT_FALSE(user->image_is_safe_format());
247 // Check image dimensions.
248 const gfx::ImageSkia& saved_image = GetDefaultImage(kFirstDefaultImageIndex);
249 EXPECT_EQ(saved_image.width(), user->image().width());
250 EXPECT_EQ(saved_image.height(), user->image().height());
253 // http://crbug.com/257009.
254 IN_PROC_BROWSER_TEST_F(UserImageManagerTest, DISABLED_NonJPEGImageFromFile) {
256 UserManager::Get()->GetUsers(); // Load users.
257 // Wait for image load.
258 content::RunMessageLoop();
259 // Now the migrated image is used.
260 const User* user = UserManager::Get()->FindUser(kTestUser1);
262 EXPECT_TRUE(user->image_is_safe_format());
263 // Check image dimensions. Images can't be compared since JPEG is lossy.
264 const gfx::ImageSkia& saved_image = GetDefaultImage(kFirstDefaultImageIndex);
265 EXPECT_EQ(saved_image.width(), user->image().width());
266 EXPECT_EQ(saved_image.height(), user->image().height());
269 } // namespace chromeos