Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 #include "chrome/browser/chromeos/customization_wallpaper_downloader.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "ash/ash_switches.h" | |
| 10 #include "ash/desktop_background/desktop_background_controller.h" | |
| 11 #include "ash/shell.h" | |
| 12 #include "base/command_line.h" | |
| 13 #include "base/file_util.h" | |
| 14 #include "base/files/file_path.h" | |
| 15 #include "base/run_loop.h" | |
| 16 #include "base/time/time.h" | |
| 17 #include "chrome/browser/chromeos/customization_document.h" | |
| 18 #include "chrome/browser/chromeos/login/wallpaper_manager.h" | |
| 19 #include "chrome/browser/google/google_url_tracker.h" | |
| 20 #include "chrome/test/base/in_process_browser_test.h" | |
| 21 #include "chrome/test/base/testing_browser_process.h" | |
| 22 #include "chromeos/chromeos_switches.h" | |
| 23 #include "net/http/http_response_headers.h" | |
| 24 #include "net/http/http_status_code.h" | |
| 25 #include "net/url_request/test_url_fetcher_factory.h" | |
| 26 #include "net/url_request/url_fetcher_impl.h" | |
| 27 #include "testing/gmock/include/gmock/gmock.h" | |
| 28 #include "testing/gtest/include/gtest/gtest.h" | |
| 29 #include "ui/gfx/codec/jpeg_codec.h" | |
| 30 #include "ui/gfx/point.h" | |
| 31 #include "ui/gfx/rect.h" | |
| 32 | |
| 33 namespace chromeos { | |
| 34 | |
| 35 namespace { | |
| 36 | |
| 37 #define OEM_WALLPAPER_URL "http://somedomain.com/image.png" | |
| 38 const char kOEMWallpaperURL[] = OEM_WALLPAPER_URL; | |
| 39 | |
| 40 const char kServicesManifest[] = | |
| 41 "{" | |
| 42 " \"version\": \"1.0\"," | |
| 43 " \"default_wallpaper\": \"" OEM_WALLPAPER_URL "\",\n" | |
| 44 " \"default_apps\": [\n" | |
| 45 " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n" | |
| 46 " \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"\n" | |
| 47 " ],\n" | |
| 48 " \"localized_content\": {\n" | |
| 49 " \"en-US\": {\n" | |
| 50 " \"default_apps_folder_name\": \"EN-US OEM Name\"\n" | |
| 51 " },\n" | |
| 52 " \"en\": {\n" | |
| 53 " \"default_apps_folder_name\": \"EN OEM Name\"\n" | |
| 54 " },\n" | |
| 55 " \"default\": {\n" | |
| 56 " \"default_apps_folder_name\": \"Default OEM Name\"\n" | |
| 57 " }\n" | |
| 58 " }\n" | |
| 59 "}"; | |
| 60 | |
| 61 #undef OEM_WALLPAPER_URL | |
| 62 | |
| 63 // Expected minimal wallpaper download retry interval in seconds. | |
| 64 const size_t kMinOEMWallpaperRetryIntervalSec = 10; | |
| 65 | |
| 66 bool CreateJPEGImage(int width, | |
| 67 int height, | |
| 68 SkColor color, | |
| 69 std::vector<unsigned char>* output) { | |
| 70 SkBitmap bitmap; | |
| 71 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0); | |
| 72 bitmap.allocPixels(); | |
| 73 bitmap.eraseColor(color); | |
| 74 | |
| 75 const int kQuality = 80; | |
| 76 if (!gfx::JPEGCodec::Encode( | |
| 77 static_cast<const unsigned char*>(bitmap.getPixels()), | |
| 78 gfx::JPEGCodec::FORMAT_SkBitmap, | |
| 79 width, | |
| 80 height, | |
| 81 bitmap.rowBytes(), | |
| 82 kQuality, | |
| 83 output)) { | |
| 84 LOG(ERROR) << "Unable to encode " << width << "x" << height << " bitmap"; | |
| 85 return false; | |
| 86 } | |
| 87 return true; | |
| 88 } | |
| 89 | |
| 90 } // namespace | |
| 91 | |
| 92 class TestObserver : public WallpaperManager::Observer { | |
| 93 public: | |
| 94 explicit TestObserver(WallpaperManager* wallpaper_manager) | |
| 95 : finished_(false), wallpaper_manager_(wallpaper_manager) { | |
| 96 DCHECK(wallpaper_manager_); | |
| 97 wallpaper_manager_->AddObserver(this); | |
| 98 } | |
| 99 | |
| 100 virtual ~TestObserver() { | |
| 101 wallpaper_manager_->RemoveObserver(this); | |
| 102 } | |
| 103 | |
| 104 virtual void OnWallpaperAnimationFinished(const std::string&) OVERRIDE { | |
| 105 finished_ = true; | |
| 106 base::MessageLoop::current()->Quit(); | |
| 107 } | |
| 108 | |
| 109 void WaitForWallpaperAnimationFinished() { | |
| 110 while (!finished_) { | |
| 111 base::RunLoop().Run(); | |
| 112 } | |
| 113 } | |
| 114 | |
| 115 private: | |
| 116 bool finished_; | |
| 117 WallpaperManager* wallpaper_manager_; | |
| 118 | |
| 119 DISALLOW_COPY_AND_ASSIGN(TestObserver); | |
| 120 }; | |
| 121 | |
| 122 class CustomizationWallpaperDownloaderBrowserTest | |
| 123 : public InProcessBrowserTest { | |
| 124 public: | |
| 125 CustomizationWallpaperDownloaderBrowserTest() | |
| 126 : controller_(NULL), local_state_(NULL) { | |
| 127 } | |
| 128 | |
| 129 virtual ~CustomizationWallpaperDownloaderBrowserTest() {} | |
| 130 | |
| 131 virtual void SetUpOnMainThread() OVERRIDE { | |
| 132 controller_ = ash::Shell::GetInstance()->desktop_background_controller(); | |
| 133 local_state_ = g_browser_process->local_state(); | |
| 134 } | |
| 135 | |
| 136 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
| 137 command_line->AppendSwitch(chromeos::switches::kLoginManager); | |
| 138 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user"); | |
| 139 } | |
| 140 | |
| 141 virtual void CleanUpOnMainThread() OVERRIDE { controller_ = NULL; } | |
| 142 | |
| 143 void WaitAsyncWallpaperLoadFinished() { | |
| 144 base::RunLoop().RunUntilIdle(); | |
| 145 while (WallpaperManager::Get()->loading_.size()) { | |
| 146 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); | |
|
Dmitry Polukhin
2014/04/29 18:39:42
We need to fins better approach when sleep i.e. wa
Alexander Alekseev
2014/04/29 21:42:40
Done.
| |
| 147 base::RunLoop().RunUntilIdle(); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 protected: | |
| 152 // Colors used for different default wallpapers by | |
| 153 // CreateCmdlineWallpapers(). | |
| 154 static const SkColor kLargeDefaultWallpaperColor = SK_ColorRED; | |
| 155 static const SkColor kSmallDefaultWallpaperColor = SK_ColorGREEN; | |
| 156 static const SkColor kLargeGuestWallpaperColor = SK_ColorBLUE; | |
| 157 static const SkColor kSmallGuestWallpaperColor = SK_ColorYELLOW; | |
| 158 | |
| 159 // A color of "remote OEM wallpaper". Specifically chosen to not | |
| 160 // conflict with any of the default wallpaper colors. | |
| 161 static const SkColor kOEMWallpaperColor = SK_ColorMAGENTA; | |
| 162 | |
| 163 // Dimension used for width and height of default wallpaper images. A | |
| 164 // small value is used to minimize the amount of time spent compressing | |
| 165 // and writing images. | |
| 166 static const int kWallpaperSize = 2; | |
| 167 | |
| 168 // Return custom wallpaper path. Create directory if not exist. | |
| 169 base::FilePath GetCustomWallpaperPath(const char* sub_dir, | |
| 170 const std::string& username_hash, | |
| 171 const std::string& id) { | |
| 172 base::FilePath wallpaper_path = | |
| 173 WallpaperManager::Get()->GetCustomWallpaperPath( | |
| 174 sub_dir, username_hash, id); | |
| 175 if (!base::DirectoryExists(wallpaper_path.DirName())) | |
| 176 base::CreateDirectory(wallpaper_path.DirName()); | |
| 177 | |
| 178 return wallpaper_path; | |
| 179 } | |
| 180 | |
| 181 // Creates a test image of given size | |
| 182 gfx::ImageSkia CreateTestImage(int width, int height, SkColor color) { | |
| 183 SkBitmap bitmap; | |
| 184 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); | |
| 185 bitmap.allocPixels(); | |
| 186 bitmap.eraseColor(color); | |
| 187 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap); | |
| 188 } | |
| 189 | |
| 190 // Writes a JPEG image of the specified size and color to |path|. Returns | |
| 191 // true on success. | |
| 192 bool WriteJPEGFile(const base::FilePath& path, | |
| 193 int width, | |
| 194 int height, | |
| 195 SkColor color) { | |
| 196 std::vector<unsigned char> output; | |
| 197 if (!CreateJPEGImage(width, height, color, &output)) | |
| 198 return false; | |
| 199 | |
| 200 size_t bytes_written = base::WriteFile( | |
| 201 path, reinterpret_cast<const char*>(&output[0]), output.size()); | |
| 202 if (bytes_written != output.size()) { | |
| 203 LOG(ERROR) << "Wrote " << bytes_written << " byte(s) instead of " | |
| 204 << output.size() << " to " << path.value(); | |
| 205 return false; | |
| 206 } | |
| 207 return true; | |
| 208 } | |
| 209 | |
| 210 // Initializes default wallpaper paths "*default_*file" and writes JPEG | |
| 211 // wallpaper images to them. | |
| 212 // Only needs to be called (once) by tests that want to test loading of | |
| 213 // default wallpapers. | |
| 214 void CreateCmdlineWallpapers() { | |
| 215 cmdline_wallpaper_dir_.reset(new base::ScopedTempDir); | |
| 216 ASSERT_TRUE(cmdline_wallpaper_dir_->CreateUniqueTempDir()); | |
| 217 | |
| 218 std::vector<std::string> options; | |
| 219 options.push_back(std::string("WM_Test_cmdline")); | |
| 220 const base::FilePath small_file = | |
| 221 cmdline_wallpaper_dir_->path().Append(FILE_PATH_LITERAL("small.jpg")); | |
| 222 options.push_back(std::string("--") + | |
| 223 ash::switches::kAshDefaultWallpaperSmall + "=" + | |
| 224 small_file.value()); | |
| 225 const base::FilePath large_file = | |
| 226 cmdline_wallpaper_dir_->path().Append(FILE_PATH_LITERAL("large.jpg")); | |
| 227 options.push_back(std::string("--") + | |
| 228 ash::switches::kAshDefaultWallpaperLarge + "=" + | |
| 229 large_file.value()); | |
| 230 | |
| 231 const base::FilePath guest_small_file = | |
| 232 cmdline_wallpaper_dir_->path().Append( | |
| 233 FILE_PATH_LITERAL("guest_small.jpg")); | |
| 234 options.push_back(std::string("--") + | |
| 235 ash::switches::kAshGuestWallpaperSmall + "=" + | |
| 236 guest_small_file.value()); | |
| 237 const base::FilePath guest_large_file = | |
| 238 cmdline_wallpaper_dir_->path().Append( | |
| 239 FILE_PATH_LITERAL("guest_large.jpg")); | |
| 240 options.push_back(std::string("--") + | |
| 241 ash::switches::kAshGuestWallpaperLarge + "=" + | |
| 242 guest_large_file.value()); | |
| 243 | |
| 244 ASSERT_TRUE(WriteJPEGFile(small_file, | |
| 245 kWallpaperSize, | |
| 246 kWallpaperSize, | |
| 247 kSmallDefaultWallpaperColor)); | |
| 248 ASSERT_TRUE(WriteJPEGFile(large_file, | |
| 249 kWallpaperSize, | |
| 250 kWallpaperSize, | |
| 251 kLargeDefaultWallpaperColor)); | |
| 252 | |
| 253 ASSERT_TRUE(WriteJPEGFile(guest_small_file, | |
| 254 kWallpaperSize, | |
| 255 kWallpaperSize, | |
| 256 kSmallGuestWallpaperColor)); | |
| 257 ASSERT_TRUE(WriteJPEGFile(guest_large_file, | |
| 258 kWallpaperSize, | |
| 259 kWallpaperSize, | |
| 260 kLargeGuestWallpaperColor)); | |
| 261 | |
| 262 wallpaper_manager_command_line_.reset(new base::CommandLine(options)); | |
| 263 WallpaperManager::Get()->SetCommandLineForTesting( | |
| 264 wallpaper_manager_command_line_.get()); | |
| 265 } | |
| 266 | |
| 267 // Returns true if the color at the center of |image| is close to | |
| 268 // |expected_color|. (The center is used so small wallpaper images can be | |
| 269 // used.) | |
| 270 bool ImageIsNearColor(gfx::ImageSkia image, SkColor expected_color) { | |
| 271 if (image.size().IsEmpty()) { | |
| 272 LOG(ERROR) << "Image is empty"; | |
| 273 return false; | |
| 274 } | |
| 275 | |
| 276 const SkBitmap* bitmap = image.bitmap(); | |
| 277 if (!bitmap) { | |
| 278 LOG(ERROR) << "Unable to get bitmap from image"; | |
| 279 return false; | |
| 280 } | |
| 281 | |
| 282 bitmap->lockPixels(); | |
| 283 gfx::Point center = gfx::Rect(image.size()).CenterPoint(); | |
| 284 SkColor image_color = bitmap->getColor(center.x(), center.y()); | |
| 285 bitmap->unlockPixels(); | |
| 286 | |
| 287 const int kDiff = 3; | |
| 288 if (std::abs(static_cast<int>(SkColorGetA(image_color)) - | |
| 289 static_cast<int>(SkColorGetA(expected_color))) > kDiff || | |
| 290 std::abs(static_cast<int>(SkColorGetR(image_color)) - | |
| 291 static_cast<int>(SkColorGetR(expected_color))) > kDiff || | |
| 292 std::abs(static_cast<int>(SkColorGetG(image_color)) - | |
| 293 static_cast<int>(SkColorGetG(expected_color))) > kDiff || | |
| 294 std::abs(static_cast<int>(SkColorGetB(image_color)) - | |
| 295 static_cast<int>(SkColorGetB(expected_color))) > kDiff) { | |
| 296 LOG(ERROR) << "Expected color near 0x" << std::hex << expected_color | |
| 297 << " but got 0x" << image_color; | |
| 298 return false; | |
| 299 } | |
| 300 | |
| 301 return true; | |
| 302 } | |
| 303 bool LoadManifestFromString( | |
| 304 chromeos::ServicesCustomizationDocument* customization, | |
| 305 const std::string& manifest) { | |
| 306 return customization->LoadManifestFromString(manifest); | |
| 307 } | |
| 308 | |
| 309 ash::DesktopBackgroundController* controller_; | |
| 310 PrefService* local_state_; | |
| 311 scoped_ptr<base::CommandLine> wallpaper_manager_command_line_; | |
| 312 | |
| 313 // Directory created by CreateCmdlineWallpapersAndSetFlags() to store default | |
| 314 // wallpaper images. | |
| 315 scoped_ptr<base::ScopedTempDir> cmdline_wallpaper_dir_; | |
| 316 | |
| 317 private: | |
| 318 DISALLOW_COPY_AND_ASSIGN(CustomizationWallpaperDownloaderBrowserTest); | |
| 319 }; | |
| 320 | |
| 321 class WallpaperImageURLFetcherCallback { | |
| 322 public: | |
| 323 WallpaperImageURLFetcherCallback( | |
| 324 const GURL& url, | |
| 325 const size_t require_retries, | |
| 326 const std::vector<unsigned char>& jpeg_data_raw) | |
| 327 : url_(url), require_retries_(require_retries), factory_(NULL) { | |
| 328 jpeg_data_.resize(jpeg_data_raw.size()); | |
| 329 std::copy(jpeg_data_raw.begin(), jpeg_data_raw.end(), jpeg_data_.begin()); | |
| 330 } | |
| 331 | |
| 332 scoped_ptr<net::FakeURLFetcher> CreateURLFetcher( | |
| 333 const GURL& url, | |
| 334 net::URLFetcherDelegate* d, | |
| 335 const std::string& response_data, | |
| 336 net::HttpStatusCode response_code, | |
| 337 net::URLRequestStatus::Status status) { | |
| 338 attempts_.push_back(base::Time::Now()); | |
| 339 if (attempts_.size() > 1) { | |
| 340 const base::TimeDelta passed = | |
| 341 attempts_.back() - attempts_[attempts_.size() - 2]; | |
| 342 EXPECT_GE(passed, | |
| 343 base::TimeDelta::FromSeconds(kMinOEMWallpaperRetryIntervalSec)) | |
| 344 << "Retry too fast. Actual interval " << passed.InSecondsF() | |
| 345 << " seconds, but expected at least " | |
| 346 << kMinOEMWallpaperRetryIntervalSec << " seconds."; | |
| 347 } | |
| 348 if (attempts_.size() > require_retries_) { | |
| 349 response_code = net::HTTP_OK; | |
| 350 status = net::URLRequestStatus::SUCCESS; | |
| 351 factory_->SetFakeResponse(url, response_data, response_code, status); | |
| 352 } | |
| 353 scoped_ptr<net::FakeURLFetcher> fetcher( | |
| 354 new net::FakeURLFetcher(url, d, response_data, response_code, status)); | |
| 355 scoped_refptr<net::HttpResponseHeaders> download_headers = | |
| 356 new net::HttpResponseHeaders(""); | |
| 357 download_headers->AddHeader("Content-Type: image/jpeg"); | |
| 358 fetcher->set_response_headers(download_headers); | |
| 359 return fetcher.Pass(); | |
| 360 } | |
| 361 | |
| 362 void Initialize(net::FakeURLFetcherFactory* factory) { | |
| 363 factory_ = factory; | |
| 364 factory_->SetFakeResponse(url_, | |
| 365 jpeg_data_, | |
| 366 net::HTTP_INTERNAL_SERVER_ERROR, | |
| 367 net::URLRequestStatus::FAILED); | |
| 368 } | |
| 369 | |
| 370 size_t attempts() const { return attempts_.size(); } | |
| 371 | |
| 372 private: | |
| 373 const GURL url_; | |
| 374 // Respond with OK on required retry attempt. | |
| 375 const size_t require_retries_; | |
| 376 net::FakeURLFetcherFactory* factory_; | |
| 377 std::vector<base::Time> attempts_; | |
| 378 std::string jpeg_data_; | |
| 379 | |
| 380 DISALLOW_COPY_AND_ASSIGN(WallpaperImageURLFetcherCallback); | |
| 381 }; | |
| 382 | |
| 383 class WallpaperImageFetcherFactory { | |
| 384 public: | |
| 385 WallpaperImageFetcherFactory(const GURL& url, | |
| 386 int width, | |
| 387 int height, | |
| 388 SkColor color, | |
| 389 const size_t require_retries) { | |
| 390 // ASSERT_TRUE() cannot be directly used in constructor. | |
| 391 Initialize(url, width, height, color, require_retries); | |
| 392 } | |
| 393 | |
| 394 ~WallpaperImageFetcherFactory() { | |
| 395 fetcher_factory_.reset(); | |
| 396 net::URLFetcherImpl::set_factory(fallback_fetcher_factory_.get()); | |
| 397 fallback_fetcher_factory_.reset(); | |
| 398 } | |
| 399 | |
| 400 size_t attempts() const { return url_callback_->attempts(); } | |
| 401 | |
| 402 private: | |
| 403 void Initialize(const GURL& url, | |
| 404 int width, | |
| 405 int height, | |
| 406 SkColor color, | |
| 407 const size_t require_retries) { | |
| 408 std::vector<unsigned char> oem_wallpaper_; | |
| 409 ASSERT_TRUE(CreateJPEGImage(width, height, color, &oem_wallpaper_)); | |
| 410 | |
| 411 url_callback_.reset(new WallpaperImageURLFetcherCallback( | |
| 412 url, require_retries, oem_wallpaper_)); | |
| 413 fallback_fetcher_factory_.reset(new net::TestURLFetcherFactory); | |
| 414 net::URLFetcherImpl::set_factory(NULL); | |
| 415 fetcher_factory_.reset(new net::FakeURLFetcherFactory( | |
| 416 fallback_fetcher_factory_.get(), | |
| 417 base::Bind(&WallpaperImageURLFetcherCallback::CreateURLFetcher, | |
| 418 base::Unretained(url_callback_.get())))); | |
| 419 url_callback_->Initialize(fetcher_factory_.get()); | |
| 420 } | |
| 421 | |
| 422 scoped_ptr<WallpaperImageURLFetcherCallback> url_callback_; | |
| 423 | |
| 424 // Use a test factory as a fallback so we don't have to deal with other | |
| 425 // requests. | |
| 426 scoped_ptr<net::TestURLFetcherFactory> fallback_fetcher_factory_; | |
| 427 scoped_ptr<net::FakeURLFetcherFactory> fetcher_factory_; | |
| 428 | |
| 429 DISALLOW_COPY_AND_ASSIGN(WallpaperImageFetcherFactory); | |
| 430 }; | |
| 431 | |
| 432 IN_PROC_BROWSER_TEST_F(CustomizationWallpaperDownloaderBrowserTest, | |
| 433 OEMWallpaperIsPresent) { | |
| 434 CreateCmdlineWallpapers(); | |
| 435 WallpaperManager::Get()->SetDefaultWallpaperNow(std::string()); | |
| 436 WaitAsyncWallpaperLoadFinished(); | |
| 437 EXPECT_TRUE(ImageIsNearColor(controller_->GetWallpaper(), | |
| 438 kSmallDefaultWallpaperColor)); | |
| 439 | |
| 440 WallpaperImageFetcherFactory url_factory(GURL(kOEMWallpaperURL), | |
| 441 kWallpaperSize, | |
| 442 kWallpaperSize, | |
| 443 kOEMWallpaperColor, | |
| 444 0 /* require_retries */); | |
| 445 | |
| 446 TestObserver observer(WallpaperManager::Get()); | |
| 447 chromeos::ServicesCustomizationDocument* customization = | |
| 448 chromeos::ServicesCustomizationDocument::GetInstance(); | |
| 449 EXPECT_TRUE( | |
| 450 LoadManifestFromString(customization, std::string(kServicesManifest))); | |
| 451 | |
| 452 observer.WaitForWallpaperAnimationFinished(); | |
| 453 EXPECT_TRUE( | |
| 454 ImageIsNearColor(controller_->GetWallpaper(), kOEMWallpaperColor)); | |
| 455 EXPECT_EQ(size_t(1), url_factory.attempts()); | |
| 456 } | |
| 457 | |
| 458 IN_PROC_BROWSER_TEST_F(CustomizationWallpaperDownloaderBrowserTest, | |
| 459 OEMWallpaperRetryFetch) { | |
| 460 CreateCmdlineWallpapers(); | |
| 461 WallpaperManager::Get()->SetDefaultWallpaperNow(std::string()); | |
| 462 WaitAsyncWallpaperLoadFinished(); | |
| 463 EXPECT_TRUE(ImageIsNearColor(controller_->GetWallpaper(), | |
| 464 kSmallDefaultWallpaperColor)); | |
| 465 | |
| 466 WallpaperImageFetcherFactory url_factory(GURL(kOEMWallpaperURL), | |
| 467 kWallpaperSize, | |
| 468 kWallpaperSize, | |
| 469 kOEMWallpaperColor, | |
| 470 1 /* require_retries */); | |
| 471 | |
| 472 TestObserver observer(WallpaperManager::Get()); | |
| 473 chromeos::ServicesCustomizationDocument* customization = | |
| 474 chromeos::ServicesCustomizationDocument::GetInstance(); | |
| 475 EXPECT_TRUE( | |
| 476 LoadManifestFromString(customization, std::string(kServicesManifest))); | |
| 477 | |
| 478 observer.WaitForWallpaperAnimationFinished(); | |
| 479 EXPECT_TRUE( | |
| 480 ImageIsNearColor(controller_->GetWallpaper(), kOEMWallpaperColor)); | |
| 481 | |
| 482 EXPECT_EQ(size_t(2), url_factory.attempts()); | |
| 483 } | |
| 484 | |
| 485 } // namespace chromeos | |
| OLD | NEW |