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
HasSameExtensionsAsVerifier(int index)27 bool HasSameExtensionsAsVerifier(int index) {
28 return SyncExtensionHelper::GetInstance()->ExtensionStatesMatch(
29 test()->GetProfile(index), test()->verifier());
30 }
31
AllProfilesHaveSameExtensionsAsVerifier()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
AllProfilesHaveSameExtensions()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
InstallExtension(Profile * profile,int index)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
InstallExtensionForAllProfiles(int index)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
UninstallExtension(Profile * profile,int index)69 void UninstallExtension(Profile* profile, int index) {
70 return SyncExtensionHelper::GetInstance()->UninstallExtension(
71 profile, CreateFakeExtensionName(index));
72 }
73
GetInstalledExtensions(Profile * profile)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
EnableExtension(Profile * profile,int index)88 void EnableExtension(Profile* profile, int index) {
89 return SyncExtensionHelper::GetInstance()->EnableExtension(
90 profile, CreateFakeExtensionName(index));
91 }
92
DisableExtension(Profile * profile,int index)93 void DisableExtension(Profile* profile, int index) {
94 return SyncExtensionHelper::GetInstance()->DisableExtension(
95 profile, CreateFakeExtensionName(index));
96 }
97
IsExtensionEnabled(Profile * profile,int index)98 bool IsExtensionEnabled(Profile* profile, int index) {
99 return SyncExtensionHelper::GetInstance()->IsExtensionEnabled(
100 profile, CreateFakeExtensionName(index));
101 }
102
IncognitoEnableExtension(Profile * profile,int index)103 void IncognitoEnableExtension(Profile* profile, int index) {
104 return SyncExtensionHelper::GetInstance()->IncognitoEnableExtension(
105 profile, CreateFakeExtensionName(index));
106 }
107
IncognitoDisableExtension(Profile * profile,int index)108 void IncognitoDisableExtension(Profile* profile, int index) {
109 return SyncExtensionHelper::GetInstance()->IncognitoDisableExtension(
110 profile, CreateFakeExtensionName(index));
111 }
112
IsIncognitoEnabled(Profile * profile,int index)113 bool IsIncognitoEnabled(Profile* profile, int index) {
114 return SyncExtensionHelper::GetInstance()->IsIncognitoEnabled(
115 profile, CreateFakeExtensionName(index));
116 }
117
InstallExtensionsPendingForSync(Profile * profile)118 void InstallExtensionsPendingForSync(Profile* profile) {
119 SyncExtensionHelper::GetInstance()->InstallExtensionsPendingForSync(profile);
120 }
121
CreateFakeExtensionName(int index)122 std::string CreateFakeExtensionName(int index) {
123 return extension_name_prefix + base::IntToString(index);
124 }
125
ExtensionNameToIndex(const std::string & name,int * index)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
ExtensionsMatchChecker(const std::vector<Profile * > & profiles)177 ExtensionsMatchChecker::ExtensionsMatchChecker(
178 const std::vector<Profile*>& profiles)
179 : profiles_(profiles), observing_(false) {
180 DCHECK_GE(profiles_.size(), 2U);
181 }
182
~ExtensionsMatchChecker()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
GetDebugMessage() const195 std::string ExtensionsMatchChecker::GetDebugMessage() const {
196 return "Waiting for extensions to match";
197 }
198
IsExitConditionSatisfied()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
OnExtensionLoaded(content::BrowserContext * context,const extensions::Extension * extension)212 void ExtensionsMatchChecker::OnExtensionLoaded(
213 content::BrowserContext* context,
214 const extensions::Extension* extension) {
215 CheckExitCondition();
216 }
217
OnExtensionUnloaded(content::BrowserContext * context,const extensions::Extension * extenion,extensions::UnloadedExtensionInfo::Reason reason)218 void ExtensionsMatchChecker::OnExtensionUnloaded(
219 content::BrowserContext* context,
220 const extensions::Extension* extenion,
221 extensions::UnloadedExtensionInfo::Reason reason) {
222 CheckExitCondition();
223 }
224
OnExtensionInstalled(content::BrowserContext * browser_context,const extensions::Extension * extension,bool is_update)225 void ExtensionsMatchChecker::OnExtensionInstalled(
226 content::BrowserContext* browser_context,
227 const extensions::Extension* extension,
228 bool is_update) {
229 CheckExitCondition();
230 }
231
OnExtensionUninstalled(content::BrowserContext * browser_context,const extensions::Extension * extension,extensions::UninstallReason reason)232 void ExtensionsMatchChecker::OnExtensionUninstalled(
233 content::BrowserContext* browser_context,
234 const extensions::Extension* extension,
235 extensions::UninstallReason reason) {
236 CheckExitCondition();
237 }
238
Wait()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
AwaitAllProfilesHaveSameExtensionsAsVerifier()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