summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chromeos/login/user.cc4
-rw-r--r--chrome/browser/chromeos/login/user_image_manager_browsertest.cc325
-rw-r--r--chrome/browser/chromeos/login/user_image_manager_impl.cc35
-rw-r--r--chrome/browser/chromeos/login/user_image_manager_impl.h4
-rw-r--r--chrome/browser/chromeos/login/user_image_manager_test_util.cc74
-rw-r--r--chrome/browser/chromeos/login/user_image_manager_test_util.h55
-rw-r--r--chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc2
-rw-r--r--chrome/chrome_tests.gypi2
-rw-r--r--chrome/test/data/chromeos/avatar1.jpg (renamed from chrome/test/data/policy/avatar1.jpg)bin285 -> 285 bytes
-rw-r--r--chrome/test/data/chromeos/avatar2.jpgbin0 -> 321 bytes
-rw-r--r--chrome/test/data/policy/avatar2.jpgbin285 -> 0 bytes
11 files changed, 469 insertions, 32 deletions
diff --git a/chrome/browser/chromeos/login/user.cc b/chrome/browser/chromeos/login/user.cc
index b47d650..df4d51c 100644
--- a/chrome/browser/chromeos/login/user.cc
+++ b/chrome/browser/chromeos/login/user.cc
@@ -28,6 +28,10 @@ std::string GetUserName(const std::string& email) {
} // namespace
+const int User::kExternalImageIndex;
+const int User::kProfileImageIndex;
+const int User::kInvalidImageIndex;
+
class RegularUser : public User {
public:
explicit RegularUser(const std::string& email);
diff --git a/chrome/browser/chromeos/login/user_image_manager_browsertest.cc b/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
index 90b92ae..05c1ee4 100644
--- a/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
@@ -2,58 +2,84 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <map>
#include <string>
-#include "base/command_line.h"
+#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "base/path_service.h"
#include "base/prefs/pref_change_registrar.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "base/run_loop.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/login/default_user_images.h"
+#include "chrome/browser/chromeos/login/login_manager_test.h"
#include "chrome/browser/chromeos/login/mock_user_manager.h"
+#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/user.h"
+#include "chrome/browser/chromeos/login/user_image.h"
+#include "chrome/browser/chromeos/login/user_image_manager.h"
+#include "chrome/browser/chromeos/login/user_image_manager_impl.h"
+#include "chrome/browser/chromeos/login/user_image_manager_test_util.h"
#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/profiles/profile_downloader.h"
#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/testing_browser_process.h"
-#include "chromeos/chromeos_switches.h"
#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
#include "content/public/test/test_utils.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_status.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/layout.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia.h"
namespace chromeos {
+namespace {
+
const char kTestUser1[] = "test-user@example.com";
const char kTestUser2[] = "test-user2@example.com";
-class UserImageManagerTest : public InProcessBrowserTest {
+} // namespace
+
+class UserImageManagerTest : public LoginManagerTest,
+ public UserManager::Observer {
protected:
- UserImageManagerTest() {
+ UserImageManagerTest() : LoginManagerTest(true) {
}
- // InProcessBrowserTest overrides:
+ // LoginManagerTest overrides:
virtual void SetUpOnMainThread() OVERRIDE {
+ LoginManagerTest::SetUpOnMainThread();
local_state_ = g_browser_process->local_state();
+ UserManager::Get()->AddObserver(this);
}
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
- command_line->AppendSwitch(switches::kLoginManager);
- command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
+ virtual void TearDownOnMainThread() OVERRIDE {
+ UserManager::Get()->RemoveObserver(this);
+ LoginManagerTest::TearDownOnMainThread();
}
- // Adds given user to Local State, if not there.
- void AddUser(const std::string& username) {
- ListPrefUpdate users_pref(local_state_, "LoggedInUsers");
- users_pref->AppendIfNotPresent(new base::StringValue(username));
+ // UserManager::Observer overrides:
+ virtual void LocalStateChanged(UserManager* user_manager) OVERRIDE {
+ if (run_loop_)
+ run_loop_->Quit();
}
// Logs in |username|.
@@ -65,7 +91,7 @@ class UserImageManagerTest : public InProcessBrowserTest {
void SetOldUserImageInfo(const std::string& username,
int image_index,
const base::FilePath& image_path) {
- AddUser(username);
+ RegisterUser(username);
DictionaryPrefUpdate images_pref(local_state_, "UserImages");
base::DictionaryValue* image_properties = new base::DictionaryValue();
image_properties->Set(
@@ -141,14 +167,96 @@ class UserImageManagerTest : public InProcessBrowserTest {
// Returns the image path for user |username| with specified |extension|.
base::FilePath GetUserImagePath(const std::string& username,
- const std::string& extension) {
+ const std::string& extension) {
base::FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
return user_data_dir.Append(username).AddExtension(extension);
}
+ // Returns the path to a test image that can be set as the user image.
+ base::FilePath GetTestImagePath() {
+ base::FilePath test_data_dir;
+ if (!PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir)) {
+ ADD_FAILURE();
+ return base::FilePath();
+ }
+ return test_data_dir.Append("chromeos").Append("avatar1.jpg");
+ }
+
+ // Completes the download of all non-image profile data for the currently
+ // logged-in user. This method must only be called after a profile data
+ // download has been started.
+ // |url_fetcher_factory| will capture the net::TestURLFetcher created by the
+ // ProfileDownloader to download the profile image.
+ void CompleteProfileMetadataDownload(
+ net::TestURLFetcherFactory* url_fetcher_factory) {
+ ProfileDownloader* profile_downloader =
+ reinterpret_cast<UserImageManagerImpl*>(
+ UserManager::Get()->GetUserImageManager())->
+ profile_downloader_.get();
+ ASSERT_TRUE(profile_downloader);
+
+ static_cast<OAuth2TokenService::Consumer*>(profile_downloader)->
+ OnGetTokenSuccess(NULL,
+ std::string(),
+ base::Time::Now() + base::TimeDelta::FromDays(1));
+
+ net::TestURLFetcher* fetcher = url_fetcher_factory->GetFetcherByID(0);
+ ASSERT_TRUE(fetcher);
+ fetcher->SetResponseString(
+ "{ \"picture\": \"http://localhost/avatar.jpg\" }");
+ fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
+ net::OK));
+ fetcher->set_response_code(200);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ // Completes the download of the currently logged-in user's profile image.
+ // This method must only be called after a profile data download including
+ // the profile image has been started, the download of all non-image data has
+ // been completed by calling CompleteProfileMetadataDownload() and the
+ // net::TestURLFetcher created by the ProfileDownloader to download the
+ // profile image has been captured by |url_fetcher_factory|.
+ void CompleteProfileImageDownload(
+ net::TestURLFetcherFactory* url_fetcher_factory) {
+ std::string profile_image_data;
+ base::FilePath test_data_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
+ EXPECT_TRUE(ReadFileToString(
+ test_data_dir.Append("chromeos").Append("avatar1.jpg"),
+ &profile_image_data));
+
+ base::RunLoop run_loop;
+ PrefChangeRegistrar pref_change_registrar;
+ pref_change_registrar.Init(local_state_);
+ pref_change_registrar.Add("UserDisplayName", run_loop.QuitClosure());
+ net::TestURLFetcher* fetcher = url_fetcher_factory->GetFetcherByID(0);
+ ASSERT_TRUE(fetcher);
+ fetcher->SetResponseString(profile_image_data);
+ fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
+ net::OK));
+ fetcher->set_response_code(200);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ run_loop.Run();
+
+ const User* user = UserManager::Get()->GetLoggedInUser();
+ ASSERT_TRUE(user);
+ const std::map<std::string, linked_ptr<UserImageManagerImpl::Job> >&
+ job_map = reinterpret_cast<UserImageManagerImpl*>(
+ UserManager::Get()->GetUserImageManager())->jobs_;
+ if (job_map.find(user->email()) != job_map.end()) {
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ }
+ }
+
PrefService* local_state_;
+ scoped_ptr<gfx::ImageSkia> decoded_image_;
+
+ scoped_ptr<base::RunLoop> run_loop_;
+
private:
DISALLOW_COPY_AND_ASSIGN(UserImageManagerTest);
};
@@ -243,4 +351,191 @@ IN_PROC_BROWSER_TEST_F(UserImageManagerTest, NonJPEGImageFromFile) {
EXPECT_EQ(saved_image.height(), user->image().height());
}
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, PRE_SaveUserDefaultImageIndex) {
+ RegisterUser(kTestUser1);
+}
+
+// Verifies that SaveUserDefaultImageIndex() correctly sets and persists the
+// chosen user image.
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, SaveUserDefaultImageIndex) {
+ const User* user = UserManager::Get()->FindUser(kTestUser1);
+ ASSERT_TRUE(user);
+
+ const gfx::ImageSkia& default_image =
+ GetDefaultImage(kFirstDefaultImageIndex);
+
+ UserImageManager* user_image_manager =
+ UserManager::Get()->GetUserImageManager();
+ user_image_manager->SaveUserDefaultImageIndex(kTestUser1,
+ kFirstDefaultImageIndex);
+
+ EXPECT_TRUE(user->HasDefaultImage());
+ EXPECT_EQ(kFirstDefaultImageIndex, user->image_index());
+ EXPECT_TRUE(test::AreImagesEqual(default_image, user->image()));
+ ExpectNewUserImageInfo(kTestUser1, kFirstDefaultImageIndex, base::FilePath());
+}
+
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, PRE_SaveUserImage) {
+ RegisterUser(kTestUser1);
+}
+
+// Verifies that SaveUserImage() correctly sets and persists the chosen user
+// image.
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, SaveUserImage) {
+ const User* user = UserManager::Get()->FindUser(kTestUser1);
+ ASSERT_TRUE(user);
+
+ SkBitmap custom_image_bitmap;
+ custom_image_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
+ custom_image_bitmap.allocPixels();
+ custom_image_bitmap.setImmutable();
+ const gfx::ImageSkia custom_image =
+ gfx::ImageSkia::CreateFrom1xBitmap(custom_image_bitmap);
+
+ run_loop_.reset(new base::RunLoop);
+ UserImageManager* user_image_manager =
+ UserManager::Get()->GetUserImageManager();
+ user_image_manager->SaveUserImage(kTestUser1,
+ UserImage::CreateAndEncode(custom_image));
+ run_loop_->Run();
+
+ EXPECT_FALSE(user->HasDefaultImage());
+ EXPECT_EQ(User::kExternalImageIndex, user->image_index());
+ EXPECT_TRUE(test::AreImagesEqual(custom_image, user->image()));
+ ExpectNewUserImageInfo(kTestUser1,
+ User::kExternalImageIndex,
+ GetUserImagePath(kTestUser1, "jpg"));
+
+ const scoped_ptr<gfx::ImageSkia> saved_image =
+ test::ImageLoader(GetUserImagePath(kTestUser1, "jpg")).Load();
+ ASSERT_TRUE(saved_image);
+
+ // Check image dimensions. Images can't be compared since JPEG is lossy.
+ EXPECT_EQ(custom_image.width(), saved_image->width());
+ EXPECT_EQ(custom_image.height(), saved_image->height());
+}
+
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, PRE_SaveUserImageFromFile) {
+ RegisterUser(kTestUser1);
+}
+
+// Verifies that SaveUserImageFromFile() correctly sets and persists the chosen
+// user image.
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, SaveUserImageFromFile) {
+ const User* user = UserManager::Get()->FindUser(kTestUser1);
+ ASSERT_TRUE(user);
+
+ const base::FilePath custom_image_path = GetTestImagePath();
+ const scoped_ptr<gfx::ImageSkia> custom_image =
+ test::ImageLoader(custom_image_path).Load();
+ ASSERT_TRUE(custom_image);
+
+ run_loop_.reset(new base::RunLoop);
+ UserImageManager* user_image_manager =
+ UserManager::Get()->GetUserImageManager();
+ user_image_manager->SaveUserImageFromFile(kTestUser1, custom_image_path);
+ run_loop_->Run();
+
+ EXPECT_FALSE(user->HasDefaultImage());
+ EXPECT_EQ(User::kExternalImageIndex, user->image_index());
+ EXPECT_TRUE(test::AreImagesEqual(*custom_image, user->image()));
+ ExpectNewUserImageInfo(kTestUser1,
+ User::kExternalImageIndex,
+ GetUserImagePath(kTestUser1, "jpg"));
+
+ const scoped_ptr<gfx::ImageSkia> saved_image =
+ test::ImageLoader(GetUserImagePath(kTestUser1, "jpg")).Load();
+ ASSERT_TRUE(saved_image);
+
+ // Check image dimensions. Images can't be compared since JPEG is lossy.
+ EXPECT_EQ(custom_image->width(), saved_image->width());
+ EXPECT_EQ(custom_image->height(), saved_image->height());
+}
+
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest,
+ PRE_SaveUserImageFromProfileImage) {
+ RegisterUser(kTestUser1);
+ chromeos::StartupUtils::MarkOobeCompleted();
+}
+
+// Verifies that SaveUserImageFromProfileImage() correctly downloads, sets and
+// persists the chosen user image.
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, SaveUserImageFromProfileImage) {
+ const User* user = UserManager::Get()->FindUser(kTestUser1);
+ ASSERT_TRUE(user);
+
+ UserImageManagerImpl::IgnoreProfileDataDownloadDelayForTesting();
+ LoginUser(kTestUser1);
+
+ run_loop_.reset(new base::RunLoop);
+ UserImageManager* user_image_manager =
+ UserManager::Get()->GetUserImageManager();
+ user_image_manager->SaveUserImageFromProfileImage(kTestUser1);
+ run_loop_->Run();
+
+ net::TestURLFetcherFactory url_fetcher_factory;
+ CompleteProfileMetadataDownload(&url_fetcher_factory);
+ CompleteProfileImageDownload(&url_fetcher_factory);
+
+ const gfx::ImageSkia& profile_image =
+ user_image_manager->DownloadedProfileImage();
+
+ EXPECT_FALSE(user->HasDefaultImage());
+ EXPECT_EQ(User::kProfileImageIndex, user->image_index());
+ EXPECT_TRUE(test::AreImagesEqual(profile_image, user->image()));
+ ExpectNewUserImageInfo(kTestUser1,
+ User::kProfileImageIndex,
+ GetUserImagePath(kTestUser1, "jpg"));
+
+ const scoped_ptr<gfx::ImageSkia> saved_image =
+ test::ImageLoader(GetUserImagePath(kTestUser1, "jpg")).Load();
+ ASSERT_TRUE(saved_image);
+
+ // Check image dimensions. Images can't be compared since JPEG is lossy.
+ EXPECT_EQ(profile_image.width(), saved_image->width());
+ EXPECT_EQ(profile_image.height(), saved_image->height());
+}
+
+
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest,
+ PRE_ProfileImageDownloadDoesNotClobber) {
+ RegisterUser(kTestUser1);
+ chromeos::StartupUtils::MarkOobeCompleted();
+}
+
+// Sets the user image to the profile image, then sets it to one of the default
+// images while the profile image download is still in progress. Verifies that
+// when the download completes, the profile image is ignored and does not
+// clobber the default image chosen in the meantime.
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest,
+ ProfileImageDownloadDoesNotClobber) {
+ const User* user = UserManager::Get()->FindUser(kTestUser1);
+ ASSERT_TRUE(user);
+
+ const gfx::ImageSkia& default_image =
+ GetDefaultImage(kFirstDefaultImageIndex);
+
+ UserImageManagerImpl::IgnoreProfileDataDownloadDelayForTesting();
+ LoginUser(kTestUser1);
+
+ run_loop_.reset(new base::RunLoop);
+ UserImageManager* user_image_manager =
+ UserManager::Get()->GetUserImageManager();
+ user_image_manager->SaveUserImageFromProfileImage(kTestUser1);
+ run_loop_->Run();
+
+ net::TestURLFetcherFactory url_fetcher_factory;
+ CompleteProfileMetadataDownload(&url_fetcher_factory);
+
+ user_image_manager->SaveUserDefaultImageIndex(kTestUser1,
+ kFirstDefaultImageIndex);
+
+ CompleteProfileImageDownload(&url_fetcher_factory);
+
+ EXPECT_TRUE(user->HasDefaultImage());
+ EXPECT_EQ(kFirstDefaultImageIndex, user->image_index());
+ EXPECT_TRUE(test::AreImagesEqual(default_image, user->image()));
+ ExpectNewUserImageInfo(kTestUser1, kFirstDefaultImageIndex, base::FilePath());
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_image_manager_impl.cc b/chrome/browser/chromeos/login/user_image_manager_impl.cc
index c98699b..8b1a53b 100644
--- a/chrome/browser/chromeos/login/user_image_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_image_manager_impl.cc
@@ -35,7 +35,6 @@
#include "chromeos/chromeos_switches.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
-#include "ui/base/webui/web_ui_util.h"
#include "ui/gfx/image/image_skia.h"
namespace chromeos {
@@ -93,11 +92,16 @@ const char kProfileDownloadSuccessTime[] =
"UserImage.ProfileDownloadTime.Success";
// Time histogram suffix for a profile image download after login.
const char kProfileDownloadReasonLoggedIn[] = "LoggedIn";
+// Time histogram suffix for a profile image download when the user chooses the
+// profile image but it has not been downloaded yet.
+const char kProfileDownloadReasonProfileImageChosen[] = "ProfileImageChosen";
// Time histogram suffix for a scheduled profile image download.
const char kProfileDownloadReasonScheduled[] = "Scheduled";
// Time histogram suffix for a profile image download retry.
const char kProfileDownloadReasonRetry[] = "Retry";
+static bool g_ignore_profile_data_download_delay_ = false;
+
// Add a histogram showing the time it takes to download profile image.
// Separate histograms are reported for each download |reason| and |result|.
void AddProfileImageTimeHistogram(ProfileDownloadResult result,
@@ -547,7 +551,6 @@ void UserImageManagerImpl::UserLoggedIn(const std::string& user_id,
// Reset the downloaded profile image as a new user logged in.
downloaded_profile_image_ = gfx::ImageSkia();
- downloaded_profile_image_data_url_.clear();
profile_image_url_ = GURL();
profile_image_requested_ = false;
@@ -558,7 +561,9 @@ void UserImageManagerImpl::UserLoggedIn(const std::string& user_id,
// optionally image).
profile_download_one_shot_timer_.Start(
FROM_HERE,
- base::TimeDelta::FromSeconds(kProfileDataDownloadDelaySec),
+ g_ignore_profile_data_download_delay_ ?
+ base::TimeDelta() :
+ base::TimeDelta::FromSeconds(kProfileDataDownloadDelaySec),
base::Bind(&UserImageManagerImpl::DownloadProfileData,
base::Unretained(this),
kProfileDownloadReasonLoggedIn));
@@ -619,6 +624,10 @@ void UserImageManagerImpl::SaveUserImageFromProfileImage(
downloaded_profile_image_.isNull() ?
UserImage() :
UserImage::CreateAndEncode(downloaded_profile_image_));
+ // If no profile image has been downloaded yet, ensure that a download is
+ // started.
+ if (downloaded_profile_image_.isNull())
+ DownloadProfileData(kProfileDownloadReasonProfileImageChosen);
}
void UserImageManagerImpl::DeleteUserImage(const std::string& user_id) {
@@ -662,8 +671,6 @@ void UserImageManagerImpl::TryToInitDownloadedProfileImage() {
// profile image and the user image has been loaded successfully.
VLOG(1) << "Profile image initialized from disk.";
downloaded_profile_image_ = user->image();
- downloaded_profile_image_data_url_ =
- webui::GetBitmapDataUrl(*downloaded_profile_image_.bitmap());
profile_image_url_ = user->image_url();
}
}
@@ -696,6 +703,11 @@ void UserImageManagerImpl::DownloadProfileData(const std::string& reason) {
profile_downloader_->Start();
}
+// static
+void UserImageManagerImpl::IgnoreProfileDataDownloadDelayForTesting() {
+ g_ignore_profile_data_download_delay_ = true;
+}
+
bool UserImageManagerImpl::NeedsProfilePicture() const {
return downloading_profile_image_;
}
@@ -764,23 +776,14 @@ void UserImageManagerImpl::OnProfileDownloadSuccess(
chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
content::Source<UserImageManager>(this),
content::NotificationService::NoDetails());
+ } else {
+ profile_image_requested_ = false;
}
// Nothing to do if the picture is cached or is the default avatar.
if (result != kDownloadSuccess)
return;
- profile_image_requested_ = false;
-
- // Check if this image is not the same as already downloaded.
- const std::string new_image_data_url =
- webui::GetBitmapDataUrl(SkBitmap(downloader->GetProfilePicture()));
- if (!downloaded_profile_image_data_url_.empty() &&
- new_image_data_url == downloaded_profile_image_data_url_) {
- return;
- }
-
- downloaded_profile_image_data_url_ = new_image_data_url;
downloaded_profile_image_ = gfx::ImageSkia::CreateFrom1xBitmap(
downloader->GetProfilePicture());
profile_image_url_ = GURL(downloader->GetProfilePictureURL());
diff --git a/chrome/browser/chromeos/login/user_image_manager_impl.h b/chrome/browser/chromeos/login/user_image_manager_impl.h
index fa88f06..68f2197 100644
--- a/chrome/browser/chromeos/login/user_image_manager_impl.h
+++ b/chrome/browser/chromeos/login/user_image_manager_impl.h
@@ -62,7 +62,11 @@ class UserImageManagerImpl : public UserImageManager,
virtual UserImageSyncObserver* GetSyncObserver() const OVERRIDE;
virtual void Shutdown() OVERRIDE;
+ static void IgnoreProfileDataDownloadDelayForTesting();
+
private:
+ friend class UserImageManagerTest;
+
// Every image load or update is encapsulated by a Job. Whenever an image load
// or update is requested for a user, the Job currently running for that user
// (if any) is canceled. This ensures that at most one Job is running per user
diff --git a/chrome/browser/chromeos/login/user_image_manager_test_util.cc b/chrome/browser/chromeos/login/user_image_manager_test_util.cc
new file mode 100644
index 0000000..01e9163
--- /dev/null
+++ b/chrome/browser/chromeos/login/user_image_manager_test_util.cc
@@ -0,0 +1,74 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/user_image_manager_test_util.h"
+
+#include <string>
+
+#include "base/file_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
+
+namespace chromeos {
+namespace test {
+
+bool AreImagesEqual(const gfx::ImageSkia& first, const gfx::ImageSkia& second) {
+ if (first.width() != second.width() || first.height() != second.height())
+ return false;
+ const SkBitmap* first_bitmap = first.bitmap();
+ const SkBitmap* second_bitmap = second.bitmap();
+ if (!first_bitmap && !second_bitmap)
+ return true;
+ if (!first_bitmap || !second_bitmap)
+ return false;
+
+ const size_t size = first_bitmap->getSize();
+ if (second_bitmap->getSize() != size)
+ return false;
+
+ SkAutoLockPixels first_pixel_lock(*first_bitmap);
+ SkAutoLockPixels second_pixel_lock(*second_bitmap);
+ uint8_t* first_data = reinterpret_cast<uint8_t*>(first_bitmap->getPixels());
+ uint8_t* second_data = reinterpret_cast<uint8_t*>(second_bitmap->getPixels());
+ for (size_t i = 0; i < size; ++i) {
+ if (first_data[i] != second_data[i])
+ return false;
+ }
+ return true;
+}
+
+ImageLoader::ImageLoader(const base::FilePath& path) : path_(path) {
+}
+
+ImageLoader::~ImageLoader() {
+}
+
+scoped_ptr<gfx::ImageSkia> ImageLoader::Load() {
+ std::string image_data;
+ ReadFileToString(path_, &image_data);
+ scoped_refptr<ImageDecoder> image_decoder = new ImageDecoder(
+ this,
+ image_data,
+ ImageDecoder::ROBUST_JPEG_CODEC);
+ image_decoder->Start(base::MessageLoopProxy::current());
+ run_loop_.Run();
+ return decoded_image_.Pass();
+}
+
+void ImageLoader::OnImageDecoded(const ImageDecoder* decoder,
+ const SkBitmap& decoded_image) {
+ decoded_image_.reset(
+ new gfx::ImageSkia(gfx::ImageSkiaRep(decoded_image, 1.0f)));
+ run_loop_.Quit();
+}
+
+void ImageLoader::OnDecodeImageFailed(const ImageDecoder* decoder) {
+ run_loop_.Quit();
+}
+
+} // namespace test
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_image_manager_test_util.h b/chrome/browser/chromeos/login/user_image_manager_test_util.h
new file mode 100644
index 0000000..04b6f39
--- /dev/null
+++ b/chrome/browser/chromeos/login/user_image_manager_test_util.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_MANAGER_TEST_UTIL_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_MANAGER_TEST_UTIL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "chrome/browser/image_decoder.h"
+
+class SKBitmap;
+
+namespace base {
+class FilePath;
+}
+
+namespace gfx {
+class ImageSkia;
+}
+
+namespace chromeos {
+namespace test {
+
+// Returns |true| if the two given images are pixel-for-pixel identical.
+bool AreImagesEqual(const gfx::ImageSkia& first, const gfx::ImageSkia& second);
+
+class ImageLoader : public ImageDecoder::Delegate {
+ public:
+ explicit ImageLoader(const base::FilePath& path);
+ virtual ~ImageLoader();
+
+ scoped_ptr<gfx::ImageSkia> Load();
+
+ // ImageDecoder::Delegate:
+ virtual void OnImageDecoded(const ImageDecoder* decoder,
+ const SkBitmap& decoded_image) OVERRIDE;
+ virtual void OnDecodeImageFailed(const ImageDecoder* decoder) OVERRIDE;
+
+ private:
+ base::FilePath path_;
+ base::RunLoop run_loop_;
+
+ scoped_ptr<gfx::ImageSkia> decoded_image_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageLoader);
+};
+
+} // namespace test
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_MANAGER_TEST_UTIL_H_
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
index 34bd0ba..fed62e4 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
+++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
@@ -78,7 +78,7 @@ void ConstructAvatarPolicy(const std::string& file_name,
base::FilePath test_data_dir;
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
ASSERT_TRUE(base::ReadFileToString(
- test_data_dir.Append("policy").Append(file_name),
+ test_data_dir.Append("chromeos").Append(file_name),
policy_data));
const std::string sha1 = base::SHA1HashString(*policy_data);
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 195807e..a23a8a9 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1037,6 +1037,8 @@
'browser/chromeos/login/test_login_utils.h',
'browser/chromeos/login/user_adding_screen_browsertest.cc',
'browser/chromeos/login/user_image_manager_browsertest.cc',
+ 'browser/chromeos/login/user_image_manager_test_util.cc',
+ 'browser/chromeos/login/user_image_manager_test_util.h',
'browser/chromeos/login/wizard_controller_browsertest.cc',
'browser/chromeos/login/wizard_in_process_browser_test.cc',
'browser/chromeos/login/wizard_in_process_browser_test.h',
diff --git a/chrome/test/data/policy/avatar1.jpg b/chrome/test/data/chromeos/avatar1.jpg
index 655dea9..655dea9 100644
--- a/chrome/test/data/policy/avatar1.jpg
+++ b/chrome/test/data/chromeos/avatar1.jpg
Binary files differ
diff --git a/chrome/test/data/chromeos/avatar2.jpg b/chrome/test/data/chromeos/avatar2.jpg
new file mode 100644
index 0000000..3031bfc
--- /dev/null
+++ b/chrome/test/data/chromeos/avatar2.jpg
Binary files differ
diff --git a/chrome/test/data/policy/avatar2.jpg b/chrome/test/data/policy/avatar2.jpg
deleted file mode 100644
index b6f56cf..0000000
--- a/chrome/test/data/policy/avatar2.jpg
+++ /dev/null
Binary files differ