1// Copyright (c) 2012 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/apps_helper.h" 6 7#include "base/logging.h" 8#include "base/strings/string_number_conversions.h" 9#include "chrome/browser/chrome_notification_types.h" 10#include "chrome/browser/profiles/profile.h" 11#include "chrome/browser/sync/test/integration/status_change_checker.h" 12#include "chrome/browser/sync/test/integration/sync_app_helper.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/sync/test/integration/sync_extension_installer.h" 16#include "content/public/browser/notification_observer.h" 17#include "content/public/browser/notification_registrar.h" 18#include "content/public/browser/notification_service.h" 19#include "extensions/browser/extension_prefs.h" 20#include "extensions/browser/extension_prefs_observer.h" 21#include "extensions/browser/extension_registry.h" 22#include "extensions/browser/extension_registry_observer.h" 23#include "extensions/common/manifest.h" 24 25using sync_datatype_helper::test; 26 27namespace { 28 29std::string CreateFakeAppName(int index) { 30 return "fakeapp" + base::IntToString(index); 31} 32 33} // namespace 34 35namespace apps_helper { 36 37bool HasSameAppsAsVerifier(int index) { 38 return SyncAppHelper::GetInstance()->AppStatesMatch( 39 test()->GetProfile(index), test()->verifier()); 40} 41 42bool AllProfilesHaveSameAppsAsVerifier() { 43 for (int i = 0; i < test()->num_clients(); ++i) { 44 if (!HasSameAppsAsVerifier(i)) { 45 DVLOG(1) << "Profile " << i << " doesn't have the same apps as the" 46 " verifier profile."; 47 return false; 48 } 49 } 50 return true; 51} 52 53std::string InstallApp(Profile* profile, int index) { 54 return SyncExtensionHelper::GetInstance()->InstallExtension( 55 profile, 56 CreateFakeAppName(index), 57 extensions::Manifest::TYPE_HOSTED_APP); 58} 59 60std::string InstallPlatformApp(Profile* profile, int index) { 61 return SyncExtensionHelper::GetInstance()->InstallExtension( 62 profile, 63 CreateFakeAppName(index), 64 extensions::Manifest::TYPE_PLATFORM_APP); 65} 66 67std::string InstallAppForAllProfiles(int index) { 68 for (int i = 0; i < test()->num_clients(); ++i) 69 InstallApp(test()->GetProfile(i), index); 70 return InstallApp(test()->verifier(), index); 71} 72 73void UninstallApp(Profile* profile, int index) { 74 return SyncExtensionHelper::GetInstance()->UninstallExtension( 75 profile, CreateFakeAppName(index)); 76} 77 78void EnableApp(Profile* profile, int index) { 79 return SyncExtensionHelper::GetInstance()->EnableExtension( 80 profile, CreateFakeAppName(index)); 81} 82 83void DisableApp(Profile* profile, int index) { 84 return SyncExtensionHelper::GetInstance()->DisableExtension( 85 profile, CreateFakeAppName(index)); 86} 87 88void IncognitoEnableApp(Profile* profile, int index) { 89 return SyncExtensionHelper::GetInstance()->IncognitoEnableExtension( 90 profile, CreateFakeAppName(index)); 91} 92 93void IncognitoDisableApp(Profile* profile, int index) { 94 return SyncExtensionHelper::GetInstance()->IncognitoDisableExtension( 95 profile, CreateFakeAppName(index)); 96} 97 98void InstallAppsPendingForSync(Profile* profile) { 99 SyncExtensionHelper::GetInstance()->InstallExtensionsPendingForSync(profile); 100} 101 102syncer::StringOrdinal GetPageOrdinalForApp(Profile* profile, 103 int app_index) { 104 return SyncAppHelper::GetInstance()->GetPageOrdinalForApp( 105 profile, CreateFakeAppName(app_index)); 106} 107 108void SetPageOrdinalForApp(Profile* profile, 109 int app_index, 110 const syncer::StringOrdinal& page_ordinal) { 111 SyncAppHelper::GetInstance()->SetPageOrdinalForApp( 112 profile, CreateFakeAppName(app_index), page_ordinal); 113} 114 115syncer::StringOrdinal GetAppLaunchOrdinalForApp(Profile* profile, 116 int app_index) { 117 return SyncAppHelper::GetInstance()->GetAppLaunchOrdinalForApp( 118 profile, CreateFakeAppName(app_index)); 119} 120 121void SetAppLaunchOrdinalForApp( 122 Profile* profile, 123 int app_index, 124 const syncer::StringOrdinal& app_launch_ordinal) { 125 SyncAppHelper::GetInstance()->SetAppLaunchOrdinalForApp( 126 profile, CreateFakeAppName(app_index), app_launch_ordinal); 127} 128 129void CopyNTPOrdinals(Profile* source, Profile* destination, int index) { 130 SetPageOrdinalForApp(destination, index, GetPageOrdinalForApp(source, index)); 131 SetAppLaunchOrdinalForApp( 132 destination, index, GetAppLaunchOrdinalForApp(source, index)); 133} 134 135void FixNTPOrdinalCollisions(Profile* profile) { 136 SyncAppHelper::GetInstance()->FixNTPOrdinalCollisions(profile); 137} 138 139namespace { 140 141// A helper class to implement waiting for a set of profiles to have matching 142// extensions lists. 143class AppsMatchChecker : public StatusChangeChecker, 144 public extensions::ExtensionRegistryObserver, 145 public extensions::ExtensionPrefsObserver, 146 public content::NotificationObserver { 147 public: 148 explicit AppsMatchChecker(const std::vector<Profile*>& profiles); 149 virtual ~AppsMatchChecker(); 150 151 // StatusChangeChecker implementation. 152 virtual std::string GetDebugMessage() const OVERRIDE; 153 virtual bool IsExitConditionSatisfied() OVERRIDE; 154 155 // extensions::ExtensionRegistryObserver implementation. 156 virtual void OnExtensionLoaded( 157 content::BrowserContext* context, 158 const extensions::Extension* extension) OVERRIDE; 159 virtual void OnExtensionUnloaded( 160 content::BrowserContext* context, 161 const extensions::Extension* extenion, 162 extensions::UnloadedExtensionInfo::Reason reason) OVERRIDE; 163 virtual void OnExtensionInstalled(content::BrowserContext* browser_context, 164 const extensions::Extension* extension, 165 bool is_update) OVERRIDE; 166 virtual void OnExtensionUninstalled( 167 content::BrowserContext* browser_context, 168 const extensions::Extension* extension, 169 extensions::UninstallReason reason) OVERRIDE; 170 171 // extensions::ExtensionPrefsObserver implementation. 172 virtual void OnExtensionDisableReasonsChanged(const std::string& extension_id, 173 int disabled_reasons) OVERRIDE; 174 virtual void OnExtensionRegistered(const std::string& extension_id, 175 const base::Time& install_time, 176 bool is_enabled) OVERRIDE; 177 virtual void OnExtensionPrefsLoaded( 178 const std::string& extension_id, 179 const extensions::ExtensionPrefs* prefs) OVERRIDE; 180 virtual void OnExtensionPrefsDeleted( 181 const std::string& extension_id) OVERRIDE; 182 virtual void OnExtensionStateChanged(const std::string& extension_id, 183 bool state) OVERRIDE; 184 185 // Implementation of content::NotificationObserver. 186 virtual void Observe(int type, 187 const content::NotificationSource& source, 188 const content::NotificationDetails& details) OVERRIDE; 189 190 void Wait(); 191 192 private: 193 std::vector<Profile*> profiles_; 194 bool observing_; 195 196 content::NotificationRegistrar registrar_; 197 198 // This installs apps, too. 199 ScopedVector<SyncedExtensionInstaller> synced_extension_installers_; 200 201 DISALLOW_COPY_AND_ASSIGN(AppsMatchChecker); 202}; 203 204AppsMatchChecker::AppsMatchChecker(const std::vector<Profile*>& profiles) 205 : profiles_(profiles), observing_(false) { 206 DCHECK_GE(profiles_.size(), 2U); 207} 208 209AppsMatchChecker::~AppsMatchChecker() { 210 if (observing_) { 211 for (std::vector<Profile*>::iterator it = profiles_.begin(); 212 it != profiles_.end(); 213 ++it) { 214 extensions::ExtensionRegistry* registry = 215 extensions::ExtensionRegistry::Get(*it); 216 registry->RemoveObserver(this); 217 extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(*it); 218 prefs->RemoveObserver(this); 219 } 220 } 221} 222 223std::string AppsMatchChecker::GetDebugMessage() const { 224 return "Waiting for apps to match"; 225} 226 227bool AppsMatchChecker::IsExitConditionSatisfied() { 228 std::vector<Profile*>::iterator it = profiles_.begin(); 229 Profile* profile0 = *it; 230 ++it; 231 for (; it != profiles_.end(); ++it) { 232 if (!SyncAppHelper::GetInstance()->AppStatesMatch(profile0, *it)) { 233 return false; 234 } 235 } 236 return true; 237} 238 239void AppsMatchChecker::OnExtensionLoaded( 240 content::BrowserContext* context, 241 const extensions::Extension* extension) { 242 CheckExitCondition(); 243} 244 245void AppsMatchChecker::OnExtensionUnloaded( 246 content::BrowserContext* context, 247 const extensions::Extension* extenion, 248 extensions::UnloadedExtensionInfo::Reason reason) { 249 CheckExitCondition(); 250} 251 252void AppsMatchChecker::OnExtensionInstalled( 253 content::BrowserContext* browser_context, 254 const extensions::Extension* extension, 255 bool is_update) { 256 CheckExitCondition(); 257} 258 259void AppsMatchChecker::OnExtensionUninstalled( 260 content::BrowserContext* browser_context, 261 const extensions::Extension* extension, 262 extensions::UninstallReason reason) { 263 CheckExitCondition(); 264} 265 266void AppsMatchChecker::OnExtensionDisableReasonsChanged( 267 const std::string& extension_id, 268 int disabled_reasons) { 269 CheckExitCondition(); 270} 271 272void AppsMatchChecker::OnExtensionRegistered(const std::string& extension_id, 273 const base::Time& install_time, 274 bool is_enabled) { 275 CheckExitCondition(); 276} 277 278void AppsMatchChecker::OnExtensionPrefsLoaded( 279 const std::string& extension_id, 280 const extensions::ExtensionPrefs* prefs) { 281 CheckExitCondition(); 282} 283 284void AppsMatchChecker::OnExtensionPrefsDeleted( 285 const std::string& extension_id) { 286 CheckExitCondition(); 287} 288 289void AppsMatchChecker::OnExtensionStateChanged(const std::string& extension_id, 290 bool state) { 291 CheckExitCondition(); 292} 293 294void AppsMatchChecker::Observe(int type, 295 const content::NotificationSource& source, 296 const content::NotificationDetails& details) { 297 DCHECK_EQ(chrome::NOTIFICATION_APP_LAUNCHER_REORDERED, type); 298 CheckExitCondition(); 299} 300 301void AppsMatchChecker::Wait() { 302 for (std::vector<Profile*>::iterator it = profiles_.begin(); 303 it != profiles_.end(); 304 ++it) { 305 // Begin mocking the installation of synced extensions from the web store. 306 synced_extension_installers_.push_back(new SyncedExtensionInstaller(*it)); 307 308 // Register as an observer of ExtensionsRegistry to receive notifications of 309 // big events, like installs and uninstalls. 310 extensions::ExtensionRegistry* registry = 311 extensions::ExtensionRegistry::Get(*it); 312 registry->AddObserver(this); 313 314 // Register for ExtensionPrefs events, too, so we can get notifications 315 // about 316 // smaller but still syncable events, like launch type changes. 317 extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(*it); 318 prefs->AddObserver(this); 319 } 320 321 registrar_.Add(this, 322 chrome::NOTIFICATION_APP_LAUNCHER_REORDERED, 323 content::NotificationService::AllSources()); 324 325 observing_ = true; 326 327 if (IsExitConditionSatisfied()) { 328 DVLOG(1) << "Apps matched without waiting"; 329 return; 330 } 331 332 DVLOG(1) << "Starting Wait: " << GetDebugMessage(); 333 StartBlockingWait(); 334} 335 336} // namespace 337 338bool AwaitAllProfilesHaveSameAppsAsVerifier() { 339 std::vector<Profile*> profiles; 340 profiles.push_back(test()->verifier()); 341 for (int i = 0; i < test()->num_clients(); ++i) { 342 profiles.push_back(test()->GetProfile(i)); 343 } 344 345 AppsMatchChecker checker(profiles); 346 checker.Wait(); 347 return !checker.TimedOut(); 348} 349 350} // namespace apps_helper 351