extensions_helper.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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
21using sync_datatype_helper::test;
22
23namespace extensions_helper {
24
25const char extension_name_prefix[] = "fakeextension";
26
27bool HasSameExtensionsAsVerifier(int index) {
28  return SyncExtensionHelper::GetInstance()->ExtensionStatesMatch(
29      test()->GetProfile(index), test()->verifier());
30}
31
32bool 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
43bool 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
56std::string InstallExtension(Profile* profile, int index) {
57  return SyncExtensionHelper::GetInstance()->InstallExtension(
58      profile,
59      CreateFakeExtensionName(index),
60      extensions::Manifest::TYPE_EXTENSION);
61}
62
63std::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
69void UninstallExtension(Profile* profile, int index) {
70  return SyncExtensionHelper::GetInstance()->UninstallExtension(
71      profile, CreateFakeExtensionName(index));
72}
73
74std::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
88void EnableExtension(Profile* profile, int index) {
89  return SyncExtensionHelper::GetInstance()->EnableExtension(
90      profile, CreateFakeExtensionName(index));
91}
92
93void DisableExtension(Profile* profile, int index) {
94  return SyncExtensionHelper::GetInstance()->DisableExtension(
95      profile, CreateFakeExtensionName(index));
96}
97
98bool IsExtensionEnabled(Profile* profile, int index) {
99  return SyncExtensionHelper::GetInstance()->IsExtensionEnabled(
100      profile, CreateFakeExtensionName(index));
101}
102
103void IncognitoEnableExtension(Profile* profile, int index) {
104  return SyncExtensionHelper::GetInstance()->IncognitoEnableExtension(
105      profile, CreateFakeExtensionName(index));
106}
107
108void IncognitoDisableExtension(Profile* profile, int index) {
109  return SyncExtensionHelper::GetInstance()->IncognitoDisableExtension(
110      profile, CreateFakeExtensionName(index));
111}
112
113bool IsIncognitoEnabled(Profile* profile, int index) {
114  return SyncExtensionHelper::GetInstance()->IsIncognitoEnabled(
115      profile, CreateFakeExtensionName(index));
116}
117
118void InstallExtensionsPendingForSync(Profile* profile) {
119  SyncExtensionHelper::GetInstance()->InstallExtensionsPendingForSync(profile);
120}
121
122std::string CreateFakeExtensionName(int index) {
123  return extension_name_prefix + base::IntToString(index);
124}
125
126bool 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
136namespace {
137
138// A helper class to implement waiting for a set of profiles to have matching
139// extensions lists.
140class 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) OVERRIDE;
165
166  void Wait();
167
168 private:
169  std::vector<Profile*> profiles_;
170  ScopedVector<SyncedExtensionInstaller> synced_extension_installers_;
171  bool observing_;
172
173  DISALLOW_COPY_AND_ASSIGN(ExtensionsMatchChecker);
174};
175
176ExtensionsMatchChecker::ExtensionsMatchChecker(
177    const std::vector<Profile*>& profiles)
178    : profiles_(profiles), observing_(false) {
179  DCHECK_GE(profiles_.size(), 2U);
180}
181
182ExtensionsMatchChecker::~ExtensionsMatchChecker() {
183  if (observing_) {
184    for (std::vector<Profile*>::iterator it = profiles_.begin();
185         it != profiles_.end();
186         ++it) {
187      extensions::ExtensionRegistry* registry =
188          extensions::ExtensionRegistry::Get(*it);
189      registry->RemoveObserver(this);
190    }
191  }
192}
193
194std::string ExtensionsMatchChecker::GetDebugMessage() const {
195  return "Waiting for extensions to match";
196}
197
198bool ExtensionsMatchChecker::IsExitConditionSatisfied() {
199  std::vector<Profile*>::iterator it = profiles_.begin();
200  Profile* profile0 = *it;
201  ++it;
202  for (; it != profiles_.end(); ++it) {
203    if (!SyncExtensionHelper::GetInstance()->ExtensionStatesMatch(profile0,
204                                                                  *it)) {
205      return false;
206    }
207  }
208  return true;
209}
210
211void ExtensionsMatchChecker::OnExtensionLoaded(
212    content::BrowserContext* context,
213    const extensions::Extension* extension) {
214  CheckExitCondition();
215}
216
217void ExtensionsMatchChecker::OnExtensionUnloaded(
218    content::BrowserContext* context,
219    const extensions::Extension* extenion,
220    extensions::UnloadedExtensionInfo::Reason reason) {
221  CheckExitCondition();
222}
223
224void ExtensionsMatchChecker::OnExtensionInstalled(
225    content::BrowserContext* browser_context,
226    const extensions::Extension* extension,
227    bool is_update) {
228  CheckExitCondition();
229}
230
231void ExtensionsMatchChecker::OnExtensionUninstalled(
232    content::BrowserContext* browser_context,
233    const extensions::Extension* extension) {
234  CheckExitCondition();
235}
236
237void ExtensionsMatchChecker::Wait() {
238  for (std::vector<Profile*>::iterator it = profiles_.begin();
239       it != profiles_.end();
240       ++it) {
241    // Begin mocking the installation of synced extensions from the web store.
242    synced_extension_installers_.push_back(new SyncedExtensionInstaller(*it));
243
244    extensions::ExtensionRegistry* registry =
245        extensions::ExtensionRegistry::Get(*it);
246    registry->AddObserver(this);
247  }
248
249  observing_ = true;
250
251  if (IsExitConditionSatisfied()) {
252    VLOG(1) << "Extensions matched without waiting";
253    return;
254  }
255
256  VLOG(1) << "Starting Wait: " << GetDebugMessage();
257  StartBlockingWait();
258}
259
260}  // namespace
261
262bool AwaitAllProfilesHaveSameExtensionsAsVerifier() {
263  std::vector<Profile*> profiles;
264  profiles.push_back(test()->verifier());
265  for (int i = 0; i < test()->num_clients(); ++i) {
266    profiles.push_back(test()->GetProfile(i));
267  }
268
269  ExtensionsMatchChecker checker(profiles);
270  checker.Wait();
271  return !checker.TimedOut();
272}
273
274}  // namespace extensions_helper
275