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/extensions_helper.h" 6 7 #include <cstring> 8 9 #include "base/logging.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_util.h" 12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/sync/test/integration/status_change_checker.h" 14 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h" 15 #include "chrome/browser/sync/test/integration/sync_extension_helper.h" 16 #include "chrome/browser/sync/test/integration/sync_extension_installer.h" 17 #include "extensions/browser/extension_registry.h" 18 #include "extensions/browser/extension_registry_observer.h" 19 #include "extensions/common/manifest.h" 20 21 using sync_datatype_helper::test; 22 23 namespace extensions_helper { 24 25 const char extension_name_prefix[] = "fakeextension"; 26 27 bool HasSameExtensionsAsVerifier(int index) { 28 return SyncExtensionHelper::GetInstance()->ExtensionStatesMatch( 29 test()->GetProfile(index), test()->verifier()); 30 } 31 32 bool AllProfilesHaveSameExtensionsAsVerifier() { 33 for (int i = 0; i < test()->num_clients(); ++i) { 34 if (!HasSameExtensionsAsVerifier(i)) { 35 LOG(ERROR) << "Profile " << i << " doesn't have the same extensions as" 36 " the verifier profile."; 37 return false; 38 } 39 } 40 return true; 41 } 42 43 bool AllProfilesHaveSameExtensions() { 44 for (int i = 1; i < test()->num_clients(); ++i) { 45 if (!SyncExtensionHelper::GetInstance()->ExtensionStatesMatch( 46 test()->GetProfile(0), test()->GetProfile(i))) { 47 LOG(ERROR) << "Profile " << i << " doesnt have the same extensions as" 48 " profile 0."; 49 return false; 50 } 51 } 52 return true; 53 } 54 55 56 std::string InstallExtension(Profile* profile, int index) { 57 return SyncExtensionHelper::GetInstance()->InstallExtension( 58 profile, 59 CreateFakeExtensionName(index), 60 extensions::Manifest::TYPE_EXTENSION); 61 } 62 63 std::string InstallExtensionForAllProfiles(int index) { 64 for (int i = 0; i < test()->num_clients(); ++i) 65 InstallExtension(test()->GetProfile(i), index); 66 return InstallExtension(test()->verifier(), index); 67 } 68 69 void UninstallExtension(Profile* profile, int index) { 70 return SyncExtensionHelper::GetInstance()->UninstallExtension( 71 profile, CreateFakeExtensionName(index)); 72 } 73 74 std::vector<int> GetInstalledExtensions(Profile* profile) { 75 std::vector<int> indices; 76 std::vector<std::string> names = 77 SyncExtensionHelper::GetInstance()->GetInstalledExtensionNames(profile); 78 for (std::vector<std::string>::const_iterator it = names.begin(); 79 it != names.end(); ++it) { 80 int index; 81 if (ExtensionNameToIndex(*it, &index)) { 82 indices.push_back(index); 83 } 84 } 85 return indices; 86 } 87 88 void EnableExtension(Profile* profile, int index) { 89 return SyncExtensionHelper::GetInstance()->EnableExtension( 90 profile, CreateFakeExtensionName(index)); 91 } 92 93 void DisableExtension(Profile* profile, int index) { 94 return SyncExtensionHelper::GetInstance()->DisableExtension( 95 profile, CreateFakeExtensionName(index)); 96 } 97 98 bool IsExtensionEnabled(Profile* profile, int index) { 99 return SyncExtensionHelper::GetInstance()->IsExtensionEnabled( 100 profile, CreateFakeExtensionName(index)); 101 } 102 103 void IncognitoEnableExtension(Profile* profile, int index) { 104 return SyncExtensionHelper::GetInstance()->IncognitoEnableExtension( 105 profile, CreateFakeExtensionName(index)); 106 } 107 108 void IncognitoDisableExtension(Profile* profile, int index) { 109 return SyncExtensionHelper::GetInstance()->IncognitoDisableExtension( 110 profile, CreateFakeExtensionName(index)); 111 } 112 113 bool IsIncognitoEnabled(Profile* profile, int index) { 114 return SyncExtensionHelper::GetInstance()->IsIncognitoEnabled( 115 profile, CreateFakeExtensionName(index)); 116 } 117 118 void InstallExtensionsPendingForSync(Profile* profile) { 119 SyncExtensionHelper::GetInstance()->InstallExtensionsPendingForSync(profile); 120 } 121 122 std::string CreateFakeExtensionName(int index) { 123 return extension_name_prefix + base::IntToString(index); 124 } 125 126 bool ExtensionNameToIndex(const std::string& name, int* index) { 127 if (!StartsWithASCII(name, extension_name_prefix, true) || 128 !base::StringToInt(name.substr(strlen(extension_name_prefix)), index)) { 129 LOG(WARNING) << "Unable to convert extension name \"" << name 130 << "\" to index"; 131 return false; 132 } 133 return true; 134 } 135 136 namespace { 137 138 // A helper class to implement waiting for a set of profiles to have matching 139 // extensions lists. 140 class ExtensionsMatchChecker : public StatusChangeChecker, 141 public extensions::ExtensionRegistryObserver { 142 public: 143 explicit ExtensionsMatchChecker(const std::vector<Profile*>& profiles); 144 virtual ~ExtensionsMatchChecker(); 145 146 // StatusChangeChecker implementation. 147 virtual std::string GetDebugMessage() const OVERRIDE; 148 virtual bool IsExitConditionSatisfied() OVERRIDE; 149 150 // extensions::ExtensionRegistryObserver implementation. 151 virtual void OnExtensionLoaded( 152 content::BrowserContext* context, 153 const extensions::Extension* extension) OVERRIDE; 154 virtual void OnExtensionUnloaded( 155 content::BrowserContext* context, 156 const extensions::Extension* extenion, 157 extensions::UnloadedExtensionInfo::Reason reason) OVERRIDE; 158 virtual void OnExtensionInstalled( 159 content::BrowserContext* browser_context, 160 const extensions::Extension* extension, 161 bool is_update) OVERRIDE; 162 virtual void OnExtensionUninstalled( 163 content::BrowserContext* browser_context, 164 const extensions::Extension* extension, 165 extensions::UninstallReason reason) OVERRIDE; 166 167 void Wait(); 168 169 private: 170 std::vector<Profile*> profiles_; 171 ScopedVector<SyncedExtensionInstaller> synced_extension_installers_; 172 bool observing_; 173 174 DISALLOW_COPY_AND_ASSIGN(ExtensionsMatchChecker); 175 }; 176 177 ExtensionsMatchChecker::ExtensionsMatchChecker( 178 const std::vector<Profile*>& profiles) 179 : profiles_(profiles), observing_(false) { 180 DCHECK_GE(profiles_.size(), 2U); 181 } 182 183 ExtensionsMatchChecker::~ExtensionsMatchChecker() { 184 if (observing_) { 185 for (std::vector<Profile*>::iterator it = profiles_.begin(); 186 it != profiles_.end(); 187 ++it) { 188 extensions::ExtensionRegistry* registry = 189 extensions::ExtensionRegistry::Get(*it); 190 registry->RemoveObserver(this); 191 } 192 } 193 } 194 195 std::string ExtensionsMatchChecker::GetDebugMessage() const { 196 return "Waiting for extensions to match"; 197 } 198 199 bool ExtensionsMatchChecker::IsExitConditionSatisfied() { 200 std::vector<Profile*>::iterator it = profiles_.begin(); 201 Profile* profile0 = *it; 202 ++it; 203 for (; it != profiles_.end(); ++it) { 204 if (!SyncExtensionHelper::GetInstance()->ExtensionStatesMatch(profile0, 205 *it)) { 206 return false; 207 } 208 } 209 return true; 210 } 211 212 void ExtensionsMatchChecker::OnExtensionLoaded( 213 content::BrowserContext* context, 214 const extensions::Extension* extension) { 215 CheckExitCondition(); 216 } 217 218 void ExtensionsMatchChecker::OnExtensionUnloaded( 219 content::BrowserContext* context, 220 const extensions::Extension* extenion, 221 extensions::UnloadedExtensionInfo::Reason reason) { 222 CheckExitCondition(); 223 } 224 225 void ExtensionsMatchChecker::OnExtensionInstalled( 226 content::BrowserContext* browser_context, 227 const extensions::Extension* extension, 228 bool is_update) { 229 CheckExitCondition(); 230 } 231 232 void ExtensionsMatchChecker::OnExtensionUninstalled( 233 content::BrowserContext* browser_context, 234 const extensions::Extension* extension, 235 extensions::UninstallReason reason) { 236 CheckExitCondition(); 237 } 238 239 void ExtensionsMatchChecker::Wait() { 240 for (std::vector<Profile*>::iterator it = profiles_.begin(); 241 it != profiles_.end(); 242 ++it) { 243 // Begin mocking the installation of synced extensions from the web store. 244 synced_extension_installers_.push_back(new SyncedExtensionInstaller(*it)); 245 246 extensions::ExtensionRegistry* registry = 247 extensions::ExtensionRegistry::Get(*it); 248 registry->AddObserver(this); 249 } 250 251 observing_ = true; 252 253 if (IsExitConditionSatisfied()) { 254 VLOG(1) << "Extensions matched without waiting"; 255 return; 256 } 257 258 VLOG(1) << "Starting Wait: " << GetDebugMessage(); 259 StartBlockingWait(); 260 } 261 262 } // namespace 263 264 bool AwaitAllProfilesHaveSameExtensionsAsVerifier() { 265 std::vector<Profile*> profiles; 266 profiles.push_back(test()->verifier()); 267 for (int i = 0; i < test()->num_clients(); ++i) { 268 profiles.push_back(test()->GetProfile(i)); 269 } 270 271 ExtensionsMatchChecker checker(profiles); 272 checker.Wait(); 273 return !checker.TimedOut(); 274 } 275 276 } // namespace extensions_helper 277