// Copyright 2014 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 #include "ash/desktop_background/desktop_background_controller.h" #include "ash/shell.h" #include "base/command_line.h" #include "base/files/scoped_temp_dir.h" #include "base/run_loop.h" #include "base/time/time.h" #include "chrome/browser/chromeos/customization_document.h" #include "chrome/browser/chromeos/customization_wallpaper_downloader.h" #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h" #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/testing_browser_process.h" #include "chromeos/chromeos_switches.h" #include "components/google/core/browser/google_url_tracker.h" #include "net/http/http_response_headers.h" #include "net/http/http_status_code.h" #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_fetcher_impl.h" #include "testing/gtest/include/gtest/gtest.h" namespace chromeos { namespace { const char kOEMWallpaperURL[] = "http://somedomain.com/image.png"; const char kServicesManifest[] = "{" " \"version\": \"1.0\"," " \"default_wallpaper\": \"http://somedomain.com/image.png\",\n" " \"default_apps\": [\n" " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n" " \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"\n" " ],\n" " \"localized_content\": {\n" " \"en-US\": {\n" " \"default_apps_folder_name\": \"EN-US OEM Name\"\n" " },\n" " \"en\": {\n" " \"default_apps_folder_name\": \"EN OEM Name\"\n" " },\n" " \"default\": {\n" " \"default_apps_folder_name\": \"Default OEM Name\"\n" " }\n" " }\n" "}"; // Expected minimal wallpaper download retry interval in milliseconds. const int kDownloadRetryIntervalMS = 100; class TestWallpaperObserver : public WallpaperManager::Observer { public: explicit TestWallpaperObserver(WallpaperManager* wallpaper_manager) : finished_(false), wallpaper_manager_(wallpaper_manager) { DCHECK(wallpaper_manager_); wallpaper_manager_->AddObserver(this); } virtual ~TestWallpaperObserver() { wallpaper_manager_->RemoveObserver(this); } virtual void OnWallpaperAnimationFinished(const std::string&) OVERRIDE { finished_ = true; base::MessageLoop::current()->Quit(); } void WaitForWallpaperAnimationFinished() { while (!finished_) base::RunLoop().Run(); } private: bool finished_; WallpaperManager* wallpaper_manager_; DISALLOW_COPY_AND_ASSIGN(TestWallpaperObserver); }; } // namespace // This is helper class for net::FakeURLFetcherFactory. class TestWallpaperImageURLFetcherCallback { public: TestWallpaperImageURLFetcherCallback( const GURL& url, const size_t require_retries, const std::vector& jpeg_data_raw) : url_(url), require_retries_(require_retries), factory_(NULL) { jpeg_data_.resize(jpeg_data_raw.size()); std::copy(jpeg_data_raw.begin(), jpeg_data_raw.end(), jpeg_data_.begin()); } scoped_ptr CreateURLFetcher( const GURL& url, net::URLFetcherDelegate* delegate, const std::string& response_data, net::HttpStatusCode response_code, net::URLRequestStatus::Status status) { chromeos::ServicesCustomizationDocument* customization = chromeos::ServicesCustomizationDocument::GetInstance(); customization->wallpaper_downloader_for_testing() ->set_retry_delay_for_testing( base::TimeDelta::FromMilliseconds(kDownloadRetryIntervalMS)); attempts_.push_back(base::TimeTicks::Now()); if (attempts_.size() > 1) { const int retry = num_attempts() - 1; const base::TimeDelta current_delay = customization->wallpaper_downloader_for_testing() ->retry_current_delay_for_testing(); const double base_interval = base::TimeDelta::FromMilliseconds( kDownloadRetryIntervalMS).InSecondsF(); EXPECT_GE(current_delay, base::TimeDelta::FromSecondsD(base_interval * retry * retry)) << "Retry too fast. Actual interval " << current_delay.InSecondsF() << " seconds, but expected at least " << base_interval << " * (retry=" << retry << " * retry)= " << base_interval * retry * retry << " seconds."; } if (attempts_.size() > require_retries_) { response_code = net::HTTP_OK; status = net::URLRequestStatus::SUCCESS; factory_->SetFakeResponse(url, response_data, response_code, status); } scoped_ptr fetcher(new net::FakeURLFetcher( url, delegate, response_data, response_code, status)); scoped_refptr download_headers = new net::HttpResponseHeaders(std::string()); download_headers->AddHeader("Content-Type: image/jpeg"); fetcher->set_response_headers(download_headers); return fetcher.Pass(); } void Initialize(net::FakeURLFetcherFactory* factory) { factory_ = factory; factory_->SetFakeResponse(url_, jpeg_data_, net::HTTP_INTERNAL_SERVER_ERROR, net::URLRequestStatus::FAILED); } size_t num_attempts() const { return attempts_.size(); } private: const GURL url_; // Respond with OK on required retry attempt. const size_t require_retries_; net::FakeURLFetcherFactory* factory_; std::vector attempts_; std::string jpeg_data_; DISALLOW_COPY_AND_ASSIGN(TestWallpaperImageURLFetcherCallback); }; // This implements fake remote source for wallpaper image. // JPEG image is created here and served to CustomizationWallpaperDownloader // via net::FakeURLFetcher. class WallpaperImageFetcherFactory { public: WallpaperImageFetcherFactory(const GURL& url, int width, int height, SkColor color, const size_t require_retries) { // ASSERT_TRUE() cannot be directly used in constructor. Initialize(url, width, height, color, require_retries); } ~WallpaperImageFetcherFactory() { fetcher_factory_.reset(); net::URLFetcherImpl::set_factory(fallback_fetcher_factory_.get()); fallback_fetcher_factory_.reset(); } size_t num_attempts() const { return url_callback_->num_attempts(); } private: void Initialize(const GURL& url, int width, int height, SkColor color, const size_t require_retries) { std::vector oem_wallpaper_; ASSERT_TRUE(wallpaper_manager_test_utils::CreateJPEGImage( width, height, color, &oem_wallpaper_)); url_callback_.reset(new TestWallpaperImageURLFetcherCallback( url, require_retries, oem_wallpaper_)); fallback_fetcher_factory_.reset(new net::TestURLFetcherFactory); net::URLFetcherImpl::set_factory(NULL); fetcher_factory_.reset(new net::FakeURLFetcherFactory( fallback_fetcher_factory_.get(), base::Bind(&TestWallpaperImageURLFetcherCallback::CreateURLFetcher, base::Unretained(url_callback_.get())))); url_callback_->Initialize(fetcher_factory_.get()); } scoped_ptr url_callback_; // Use a test factory as a fallback so we don't have to deal with other // requests. scoped_ptr fallback_fetcher_factory_; scoped_ptr fetcher_factory_; DISALLOW_COPY_AND_ASSIGN(WallpaperImageFetcherFactory); }; class CustomizationWallpaperDownloaderBrowserTest : public InProcessBrowserTest { public: CustomizationWallpaperDownloaderBrowserTest() : controller_(NULL), local_state_(NULL) { } virtual ~CustomizationWallpaperDownloaderBrowserTest() {} virtual void SetUpOnMainThread() OVERRIDE { controller_ = ash::Shell::GetInstance()->desktop_background_controller(); local_state_ = g_browser_process->local_state(); } virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { command_line->AppendSwitch(chromeos::switches::kLoginManager); command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user"); } virtual void TearDownOnMainThread() OVERRIDE { controller_ = NULL; } protected: void CreateCmdlineWallpapers() { cmdline_wallpaper_dir_.reset(new base::ScopedTempDir); ASSERT_TRUE(cmdline_wallpaper_dir_->CreateUniqueTempDir()); wallpaper_manager_test_utils::CreateCmdlineWallpapers( *cmdline_wallpaper_dir_, &wallpaper_manager_command_line_); } ash::DesktopBackgroundController* controller_; PrefService* local_state_; scoped_ptr wallpaper_manager_command_line_; // Directory created by CreateCmdlineWallpapersAndSetFlags() to store default // wallpaper images. scoped_ptr cmdline_wallpaper_dir_; private: DISALLOW_COPY_AND_ASSIGN(CustomizationWallpaperDownloaderBrowserTest); }; IN_PROC_BROWSER_TEST_F(CustomizationWallpaperDownloaderBrowserTest, OEMWallpaperIsPresent) { CreateCmdlineWallpapers(); WallpaperManager::Get()->SetDefaultWallpaperNow(std::string()); wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished(); EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor( controller_->GetWallpaper(), wallpaper_manager_test_utils::kSmallDefaultWallpaperColor)); WallpaperImageFetcherFactory url_factory( GURL(kOEMWallpaperURL), wallpaper_manager_test_utils::kWallpaperSize, wallpaper_manager_test_utils::kWallpaperSize, wallpaper_manager_test_utils::kCustomWallpaperColor, 0 /* require_retries */); TestWallpaperObserver observer(WallpaperManager::Get()); chromeos::ServicesCustomizationDocument* customization = chromeos::ServicesCustomizationDocument::GetInstance(); EXPECT_TRUE( customization->LoadManifestFromString(std::string(kServicesManifest))); observer.WaitForWallpaperAnimationFinished(); EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor( controller_->GetWallpaper(), wallpaper_manager_test_utils::kCustomWallpaperColor)); EXPECT_EQ(1U, url_factory.num_attempts()); } IN_PROC_BROWSER_TEST_F(CustomizationWallpaperDownloaderBrowserTest, OEMWallpaperRetryFetch) { CreateCmdlineWallpapers(); WallpaperManager::Get()->SetDefaultWallpaperNow(std::string()); wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished(); EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor( controller_->GetWallpaper(), wallpaper_manager_test_utils::kSmallDefaultWallpaperColor)); WallpaperImageFetcherFactory url_factory( GURL(kOEMWallpaperURL), wallpaper_manager_test_utils::kWallpaperSize, wallpaper_manager_test_utils::kWallpaperSize, wallpaper_manager_test_utils::kCustomWallpaperColor, 1 /* require_retries */); TestWallpaperObserver observer(WallpaperManager::Get()); chromeos::ServicesCustomizationDocument* customization = chromeos::ServicesCustomizationDocument::GetInstance(); EXPECT_TRUE( customization->LoadManifestFromString(std::string(kServicesManifest))); observer.WaitForWallpaperAnimationFinished(); EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor( controller_->GetWallpaper(), wallpaper_manager_test_utils::kCustomWallpaperColor)); EXPECT_EQ(2U, url_factory.num_attempts()); } } // namespace chromeos