1 // Copyright 2014 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 6 #include <vector> 7 8 #include "ash/desktop_background/desktop_background_controller.h" 9 #include "ash/shell.h" 10 #include "base/command_line.h" 11 #include "base/files/scoped_temp_dir.h" 12 #include "base/run_loop.h" 13 #include "base/time/time.h" 14 #include "chrome/browser/chromeos/customization_document.h" 15 #include "chrome/browser/chromeos/customization_wallpaper_downloader.h" 16 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h" 17 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.h" 18 #include "chrome/test/base/in_process_browser_test.h" 19 #include "chrome/test/base/testing_browser_process.h" 20 #include "chromeos/chromeos_switches.h" 21 #include "components/google/core/browser/google_url_tracker.h" 22 #include "net/http/http_response_headers.h" 23 #include "net/http/http_status_code.h" 24 #include "net/url_request/test_url_fetcher_factory.h" 25 #include "net/url_request/url_fetcher_impl.h" 26 #include "testing/gtest/include/gtest/gtest.h" 27 28 namespace chromeos { 29 30 namespace { 31 32 const char kOEMWallpaperURL[] = "http://somedomain.com/image.png"; 33 34 const char kServicesManifest[] = 35 "{" 36 " \"version\": \"1.0\"," 37 " \"default_wallpaper\": \"http://somedomain.com/image.png\",\n" 38 " \"default_apps\": [\n" 39 " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n" 40 " \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"\n" 41 " ],\n" 42 " \"localized_content\": {\n" 43 " \"en-US\": {\n" 44 " \"default_apps_folder_name\": \"EN-US OEM Name\"\n" 45 " },\n" 46 " \"en\": {\n" 47 " \"default_apps_folder_name\": \"EN OEM Name\"\n" 48 " },\n" 49 " \"default\": {\n" 50 " \"default_apps_folder_name\": \"Default OEM Name\"\n" 51 " }\n" 52 " }\n" 53 "}"; 54 55 // Expected minimal wallpaper download retry interval in milliseconds. 56 const int kDownloadRetryIntervalMS = 100; 57 58 class TestWallpaperObserver : public WallpaperManager::Observer { 59 public: 60 explicit TestWallpaperObserver(WallpaperManager* wallpaper_manager) 61 : finished_(false), 62 wallpaper_manager_(wallpaper_manager) { 63 DCHECK(wallpaper_manager_); 64 wallpaper_manager_->AddObserver(this); 65 } 66 67 virtual ~TestWallpaperObserver() { 68 wallpaper_manager_->RemoveObserver(this); 69 } 70 71 virtual void OnWallpaperAnimationFinished(const std::string&) OVERRIDE { 72 finished_ = true; 73 base::MessageLoop::current()->Quit(); 74 } 75 76 void WaitForWallpaperAnimationFinished() { 77 while (!finished_) 78 base::RunLoop().Run(); 79 } 80 81 private: 82 bool finished_; 83 WallpaperManager* wallpaper_manager_; 84 85 DISALLOW_COPY_AND_ASSIGN(TestWallpaperObserver); 86 }; 87 88 } // namespace 89 90 // This is helper class for net::FakeURLFetcherFactory. 91 class TestWallpaperImageURLFetcherCallback { 92 public: 93 TestWallpaperImageURLFetcherCallback( 94 const GURL& url, 95 const size_t require_retries, 96 const std::vector<unsigned char>& jpeg_data_raw) 97 : url_(url), 98 require_retries_(require_retries), 99 factory_(NULL) { 100 jpeg_data_.resize(jpeg_data_raw.size()); 101 std::copy(jpeg_data_raw.begin(), jpeg_data_raw.end(), jpeg_data_.begin()); 102 } 103 104 scoped_ptr<net::FakeURLFetcher> CreateURLFetcher( 105 const GURL& url, 106 net::URLFetcherDelegate* delegate, 107 const std::string& response_data, 108 net::HttpStatusCode response_code, 109 net::URLRequestStatus::Status status) { 110 chromeos::ServicesCustomizationDocument* customization = 111 chromeos::ServicesCustomizationDocument::GetInstance(); 112 customization->wallpaper_downloader_for_testing() 113 ->set_retry_delay_for_testing( 114 base::TimeDelta::FromMilliseconds(kDownloadRetryIntervalMS)); 115 116 attempts_.push_back(base::TimeTicks::Now()); 117 if (attempts_.size() > 1) { 118 const int retry = num_attempts() - 1; 119 const base::TimeDelta current_delay = 120 customization->wallpaper_downloader_for_testing() 121 ->retry_current_delay_for_testing(); 122 const double base_interval = base::TimeDelta::FromMilliseconds( 123 kDownloadRetryIntervalMS).InSecondsF(); 124 EXPECT_GE(current_delay, 125 base::TimeDelta::FromSecondsD(base_interval * retry * retry)) 126 << "Retry too fast. Actual interval " << current_delay.InSecondsF() 127 << " seconds, but expected at least " << base_interval 128 << " * (retry=" << retry 129 << " * retry)= " << base_interval * retry * retry << " seconds."; 130 } 131 if (attempts_.size() > require_retries_) { 132 response_code = net::HTTP_OK; 133 status = net::URLRequestStatus::SUCCESS; 134 factory_->SetFakeResponse(url, response_data, response_code, status); 135 } 136 scoped_ptr<net::FakeURLFetcher> fetcher(new net::FakeURLFetcher( 137 url, delegate, response_data, response_code, status)); 138 scoped_refptr<net::HttpResponseHeaders> download_headers = 139 new net::HttpResponseHeaders(std::string()); 140 download_headers->AddHeader("Content-Type: image/jpeg"); 141 fetcher->set_response_headers(download_headers); 142 return fetcher.Pass(); 143 } 144 145 void Initialize(net::FakeURLFetcherFactory* factory) { 146 factory_ = factory; 147 factory_->SetFakeResponse(url_, 148 jpeg_data_, 149 net::HTTP_INTERNAL_SERVER_ERROR, 150 net::URLRequestStatus::FAILED); 151 } 152 153 size_t num_attempts() const { return attempts_.size(); } 154 155 private: 156 const GURL url_; 157 // Respond with OK on required retry attempt. 158 const size_t require_retries_; 159 net::FakeURLFetcherFactory* factory_; 160 std::vector<base::TimeTicks> attempts_; 161 std::string jpeg_data_; 162 163 DISALLOW_COPY_AND_ASSIGN(TestWallpaperImageURLFetcherCallback); 164 }; 165 166 // This implements fake remote source for wallpaper image. 167 // JPEG image is created here and served to CustomizationWallpaperDownloader 168 // via net::FakeURLFetcher. 169 class WallpaperImageFetcherFactory { 170 public: 171 WallpaperImageFetcherFactory(const GURL& url, 172 int width, 173 int height, 174 SkColor color, 175 const size_t require_retries) { 176 // ASSERT_TRUE() cannot be directly used in constructor. 177 Initialize(url, width, height, color, require_retries); 178 } 179 180 ~WallpaperImageFetcherFactory() { 181 fetcher_factory_.reset(); 182 net::URLFetcherImpl::set_factory(fallback_fetcher_factory_.get()); 183 fallback_fetcher_factory_.reset(); 184 } 185 186 size_t num_attempts() const { return url_callback_->num_attempts(); } 187 188 private: 189 void Initialize(const GURL& url, 190 int width, 191 int height, 192 SkColor color, 193 const size_t require_retries) { 194 std::vector<unsigned char> oem_wallpaper_; 195 ASSERT_TRUE(wallpaper_manager_test_utils::CreateJPEGImage( 196 width, height, color, &oem_wallpaper_)); 197 198 url_callback_.reset(new TestWallpaperImageURLFetcherCallback( 199 url, require_retries, oem_wallpaper_)); 200 fallback_fetcher_factory_.reset(new net::TestURLFetcherFactory); 201 net::URLFetcherImpl::set_factory(NULL); 202 fetcher_factory_.reset(new net::FakeURLFetcherFactory( 203 fallback_fetcher_factory_.get(), 204 base::Bind(&TestWallpaperImageURLFetcherCallback::CreateURLFetcher, 205 base::Unretained(url_callback_.get())))); 206 url_callback_->Initialize(fetcher_factory_.get()); 207 } 208 209 scoped_ptr<TestWallpaperImageURLFetcherCallback> url_callback_; 210 211 // Use a test factory as a fallback so we don't have to deal with other 212 // requests. 213 scoped_ptr<net::TestURLFetcherFactory> fallback_fetcher_factory_; 214 scoped_ptr<net::FakeURLFetcherFactory> fetcher_factory_; 215 216 DISALLOW_COPY_AND_ASSIGN(WallpaperImageFetcherFactory); 217 }; 218 219 class CustomizationWallpaperDownloaderBrowserTest 220 : public InProcessBrowserTest { 221 public: 222 CustomizationWallpaperDownloaderBrowserTest() 223 : controller_(NULL), 224 local_state_(NULL) { 225 } 226 227 virtual ~CustomizationWallpaperDownloaderBrowserTest() {} 228 229 virtual void SetUpOnMainThread() OVERRIDE { 230 controller_ = ash::Shell::GetInstance()->desktop_background_controller(); 231 local_state_ = g_browser_process->local_state(); 232 } 233 234 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 235 command_line->AppendSwitch(chromeos::switches::kLoginManager); 236 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user"); 237 } 238 239 virtual void TearDownOnMainThread() OVERRIDE { controller_ = NULL; } 240 241 protected: 242 void CreateCmdlineWallpapers() { 243 cmdline_wallpaper_dir_.reset(new base::ScopedTempDir); 244 ASSERT_TRUE(cmdline_wallpaper_dir_->CreateUniqueTempDir()); 245 wallpaper_manager_test_utils::CreateCmdlineWallpapers( 246 *cmdline_wallpaper_dir_, &wallpaper_manager_command_line_); 247 } 248 249 ash::DesktopBackgroundController* controller_; 250 PrefService* local_state_; 251 scoped_ptr<base::CommandLine> wallpaper_manager_command_line_; 252 253 // Directory created by CreateCmdlineWallpapersAndSetFlags() to store default 254 // wallpaper images. 255 scoped_ptr<base::ScopedTempDir> cmdline_wallpaper_dir_; 256 257 private: 258 DISALLOW_COPY_AND_ASSIGN(CustomizationWallpaperDownloaderBrowserTest); 259 }; 260 261 IN_PROC_BROWSER_TEST_F(CustomizationWallpaperDownloaderBrowserTest, 262 OEMWallpaperIsPresent) { 263 CreateCmdlineWallpapers(); 264 WallpaperManager::Get()->SetDefaultWallpaperNow(std::string()); 265 wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished(); 266 EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor( 267 controller_->GetWallpaper(), 268 wallpaper_manager_test_utils::kSmallDefaultWallpaperColor)); 269 270 WallpaperImageFetcherFactory url_factory( 271 GURL(kOEMWallpaperURL), 272 wallpaper_manager_test_utils::kWallpaperSize, 273 wallpaper_manager_test_utils::kWallpaperSize, 274 wallpaper_manager_test_utils::kCustomWallpaperColor, 275 0 /* require_retries */); 276 277 TestWallpaperObserver observer(WallpaperManager::Get()); 278 chromeos::ServicesCustomizationDocument* customization = 279 chromeos::ServicesCustomizationDocument::GetInstance(); 280 EXPECT_TRUE( 281 customization->LoadManifestFromString(std::string(kServicesManifest))); 282 283 observer.WaitForWallpaperAnimationFinished(); 284 EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor( 285 controller_->GetWallpaper(), 286 wallpaper_manager_test_utils::kCustomWallpaperColor)); 287 EXPECT_EQ(1U, url_factory.num_attempts()); 288 } 289 290 IN_PROC_BROWSER_TEST_F(CustomizationWallpaperDownloaderBrowserTest, 291 OEMWallpaperRetryFetch) { 292 CreateCmdlineWallpapers(); 293 WallpaperManager::Get()->SetDefaultWallpaperNow(std::string()); 294 wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished(); 295 EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor( 296 controller_->GetWallpaper(), 297 wallpaper_manager_test_utils::kSmallDefaultWallpaperColor)); 298 299 WallpaperImageFetcherFactory url_factory( 300 GURL(kOEMWallpaperURL), 301 wallpaper_manager_test_utils::kWallpaperSize, 302 wallpaper_manager_test_utils::kWallpaperSize, 303 wallpaper_manager_test_utils::kCustomWallpaperColor, 304 1 /* require_retries */); 305 306 TestWallpaperObserver observer(WallpaperManager::Get()); 307 chromeos::ServicesCustomizationDocument* customization = 308 chromeos::ServicesCustomizationDocument::GetInstance(); 309 EXPECT_TRUE( 310 customization->LoadManifestFromString(std::string(kServicesManifest))); 311 312 observer.WaitForWallpaperAnimationFinished(); 313 EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor( 314 controller_->GetWallpaper(), 315 wallpaper_manager_test_utils::kCustomWallpaperColor)); 316 317 EXPECT_EQ(2U, url_factory.num_attempts()); 318 } 319 320 } // namespace chromeos 321