Home | History | Annotate | Download | only in chromeos
      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 CleanUpOnMainThread() 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