Home | History | Annotate | Download | only in integration
      1 // Copyright (c) 2011 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/sync/test/integration/themes_helper.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/logging.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "base/strings/stringprintf.h"
     11 #include "chrome/browser/chrome_notification_types.h"
     12 #include "chrome/browser/sync/test/integration/status_change_checker.h"
     13 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
     14 #include "chrome/browser/sync/test/integration/sync_extension_helper.h"
     15 #include "chrome/browser/themes/theme_service.h"
     16 #include "chrome/browser/themes/theme_service_factory.h"
     17 #include "components/crx_file/id_util.h"
     18 #include "content/public/browser/notification_observer.h"
     19 #include "content/public/browser/notification_registrar.h"
     20 #include "content/public/browser/notification_source.h"
     21 #include "extensions/common/manifest.h"
     22 
     23 using sync_datatype_helper::test;
     24 
     25 namespace {
     26 
     27 // Make a name to pass to an extension helper.
     28 std::string MakeName(int index) {
     29   return "faketheme" + base::IntToString(index);
     30 }
     31 
     32 ThemeService* GetThemeService(Profile* profile) {
     33   return ThemeServiceFactory::GetForProfile(profile);
     34 }
     35 
     36 }  // namespace
     37 
     38 namespace themes_helper {
     39 
     40 std::string GetCustomTheme(int index) {
     41   return crx_file::id_util::GenerateId(MakeName(index));
     42 }
     43 
     44 std::string GetThemeID(Profile* profile) {
     45   return GetThemeService(profile)->GetThemeID();
     46 }
     47 
     48 bool UsingCustomTheme(Profile* profile) {
     49   return GetThemeID(profile) != ThemeService::kDefaultThemeID;
     50 }
     51 
     52 bool UsingDefaultTheme(Profile* profile) {
     53   return GetThemeService(profile)->UsingDefaultTheme();
     54 }
     55 
     56 bool UsingSystemTheme(Profile* profile) {
     57   return GetThemeService(profile)->UsingSystemTheme();
     58 }
     59 
     60 bool ThemeIsPendingInstall(Profile* profile, const std::string& id) {
     61   return SyncExtensionHelper::GetInstance()->
     62       IsExtensionPendingInstallForSync(profile, id);
     63 }
     64 
     65 void UseCustomTheme(Profile* profile, int index) {
     66   SyncExtensionHelper::GetInstance()->InstallExtension(
     67       profile, MakeName(index), extensions::Manifest::TYPE_THEME);
     68 }
     69 
     70 void UseDefaultTheme(Profile* profile) {
     71   GetThemeService(profile)->UseDefaultTheme();
     72 }
     73 
     74 void UseSystemTheme(Profile* profile) {
     75   GetThemeService(profile)->UseSystemTheme();
     76 }
     77 
     78 namespace {
     79 
     80 // Helper to wait until the specified theme is pending for install on the
     81 // specified profile.
     82 //
     83 // The themes sync integration tests don't actually install any custom themes,
     84 // but they do occasionally check that the ThemeService attempts to install
     85 // synced themes.
     86 class ThemePendingInstallChecker : public StatusChangeChecker,
     87                                    public content::NotificationObserver {
     88  public:
     89   ThemePendingInstallChecker(Profile* profile, const std::string& theme);
     90   virtual ~ThemePendingInstallChecker();
     91 
     92   // Implementation of StatusChangeChecker.
     93   virtual std::string GetDebugMessage() const OVERRIDE;
     94   virtual bool IsExitConditionSatisfied() OVERRIDE;
     95 
     96   // Implementation of content::NotificationObserver.
     97   virtual void Observe(int type,
     98                        const content::NotificationSource& source,
     99                        const content::NotificationDetails& details) OVERRIDE;
    100 
    101   // Waits until the condition to be met or a timeout occurs.
    102   void Wait();
    103 
    104  private:
    105   Profile* profile_;
    106   const std::string& theme_;
    107 
    108   content::NotificationRegistrar registrar_;
    109 };
    110 
    111 ThemePendingInstallChecker::ThemePendingInstallChecker(Profile* profile,
    112                                                        const std::string& theme)
    113     : profile_(profile), theme_(theme) {
    114 }
    115 
    116 ThemePendingInstallChecker::~ThemePendingInstallChecker() {
    117 }
    118 
    119 std::string ThemePendingInstallChecker::GetDebugMessage() const {
    120   return base::StringPrintf("Waiting for pending theme to be '%s'",
    121                             theme_.c_str());
    122 }
    123 
    124 bool ThemePendingInstallChecker::IsExitConditionSatisfied() {
    125   return ThemeIsPendingInstall(profile_, theme_);
    126 }
    127 
    128 void ThemePendingInstallChecker::Observe(
    129     int type,
    130     const content::NotificationSource& source,
    131     const content::NotificationDetails& details) {
    132   DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_UPDATING_STARTED, type);
    133   CheckExitCondition();
    134 }
    135 
    136 void ThemePendingInstallChecker::Wait() {
    137   // We'll check to see if the condition is met whenever the extension system
    138   // tries to contact the web store.
    139   registrar_.Add(this,
    140                  extensions::NOTIFICATION_EXTENSION_UPDATING_STARTED,
    141                  content::Source<Profile>(profile_));
    142 
    143   if (IsExitConditionSatisfied()) {
    144     return;
    145   }
    146 
    147   StartBlockingWait();
    148 }
    149 
    150 }  // namespace
    151 
    152 bool AwaitThemeIsPendingInstall(Profile* profile, const std::string& theme) {
    153   ThemePendingInstallChecker checker(profile, theme);
    154   checker.Wait();
    155   return !checker.TimedOut();
    156 }
    157 
    158 namespace {
    159 
    160 // Helper to wait until a given condition is met, checking every time the
    161 // current theme changes.
    162 //
    163 // The |exit_condition_| closure may be invoked zero or more times.
    164 class ThemeConditionChecker : public StatusChangeChecker,
    165                               public content::NotificationObserver {
    166  public:
    167   ThemeConditionChecker(Profile* profile,
    168                         const std::string& debug_message_,
    169                         base::Callback<bool(ThemeService*)> exit_condition);
    170   virtual ~ThemeConditionChecker();
    171 
    172   // Implementation of StatusChangeChecker.
    173   virtual std::string GetDebugMessage() const OVERRIDE;
    174   virtual bool IsExitConditionSatisfied() OVERRIDE;
    175 
    176   // Implementation of content::NotificationObserver.
    177   virtual void Observe(int type,
    178                        const content::NotificationSource& source,
    179                        const content::NotificationDetails& details) OVERRIDE;
    180 
    181   // Waits until the condition to be met or a timeout occurs.
    182   void Wait();
    183 
    184  private:
    185   Profile* profile_;
    186   const std::string debug_message_;
    187   base::Callback<bool(ThemeService*)> exit_condition_;
    188 
    189   content::NotificationRegistrar registrar_;
    190 };
    191 
    192 ThemeConditionChecker::ThemeConditionChecker(
    193     Profile* profile,
    194     const std::string& debug_message,
    195     base::Callback<bool(ThemeService*)> exit_condition)
    196     : profile_(profile),
    197       debug_message_(debug_message),
    198       exit_condition_(exit_condition) {
    199 }
    200 
    201 ThemeConditionChecker::~ThemeConditionChecker() {
    202 }
    203 
    204 std::string ThemeConditionChecker::GetDebugMessage() const {
    205   return debug_message_;
    206 }
    207 
    208 bool ThemeConditionChecker::IsExitConditionSatisfied() {
    209   return exit_condition_.Run(GetThemeService(profile_));
    210 }
    211 
    212 void ThemeConditionChecker::Observe(
    213     int type,
    214     const content::NotificationSource& source,
    215     const content::NotificationDetails& details) {
    216   DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
    217   CheckExitCondition();
    218 }
    219 
    220 void ThemeConditionChecker::Wait() {
    221   registrar_.Add(this,
    222                  chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
    223                  content::Source<ThemeService>(GetThemeService(profile_)));
    224 
    225   if (IsExitConditionSatisfied()) {
    226     return;
    227   }
    228 
    229   StartBlockingWait();
    230 }
    231 
    232 // Helper function to let us bind this functionality into a base::Callback.
    233 bool UsingSystemThemeFunc(ThemeService* theme_service) {
    234   return theme_service->UsingSystemTheme();
    235 }
    236 
    237 // Helper function to let us bind this functionality into a base::Callback.
    238 bool UsingDefaultThemeFunc(ThemeService* theme_service) {
    239   return theme_service->UsingDefaultTheme();
    240 }
    241 
    242 }  // namespace
    243 
    244 bool AwaitUsingSystemTheme(Profile* profile) {
    245   ThemeConditionChecker checker(
    246       profile,
    247       std::string("Waiting until profile is using system theme"),
    248       base::Bind(&UsingSystemThemeFunc));
    249   checker.Wait();
    250   return !checker.TimedOut();
    251 }
    252 
    253 bool AwaitUsingDefaultTheme(Profile* profile) {
    254   ThemeConditionChecker checker(
    255       profile,
    256       std::string("Waiting until profile is using default theme"),
    257       base::Bind(&UsingDefaultThemeFunc));
    258   checker.Wait();
    259   return !checker.TimedOut();
    260 }
    261 
    262 }  // namespace themes_helper
    263