Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / chrome / browser / sync / sync_ui_util_unittest.cc
blob39912adbbbf2f8f46b5a609d04ed2821b373cdc6
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.
5 #include <set>
6 #include "base/basictypes.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/signin/account_tracker_service_factory.h"
10 #include "chrome/browser/signin/chrome_signin_client_factory.h"
11 #include "chrome/browser/signin/signin_error_controller_factory.h"
12 #include "chrome/browser/sync/profile_sync_service_mock.h"
13 #include "chrome/browser/sync/sync_ui_util.h"
14 #include "chrome/grit/generated_resources.h"
15 #include "components/signin/core/browser/fake_auth_status_provider.h"
16 #include "components/signin/core/browser/fake_signin_manager.h"
17 #include "components/signin/core/browser/signin_manager.h"
18 #include "content/public/test/test_browser_thread.h"
19 #include "content/public/test/test_browser_thread_bundle.h"
20 #include "testing/gmock/include/gmock/gmock-actions.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "ui/base/l10n/l10n_util.h"
25 using ::testing::AtMost;
26 using ::testing::NiceMock;
27 using ::testing::Return;
28 using ::testing::ReturnRef;
29 using ::testing::SetArgPointee;
30 using ::testing::_;
31 using content::BrowserThread;
33 // A number of distinct states of the ProfileSyncService can be generated for
34 // tests.
35 enum DistinctState {
36 STATUS_CASE_SETUP_IN_PROGRESS,
37 STATUS_CASE_SETUP_ERROR,
38 STATUS_CASE_AUTHENTICATING,
39 STATUS_CASE_AUTH_ERROR,
40 STATUS_CASE_PROTOCOL_ERROR,
41 STATUS_CASE_PASSPHRASE_ERROR,
42 STATUS_CASE_SYNCED,
43 STATUS_CASE_SYNC_DISABLED_BY_POLICY,
44 NUMBER_OF_STATUS_CASES
47 namespace {
49 const char kTestGaiaId[] = "gaia-id-test_user@test.com";
50 const char kTestUser[] = "test_user@test.com";
52 #if !defined(OS_CHROMEOS)
53 // Utility function to test that GetStatusLabelsForSyncGlobalError returns
54 // the correct results for the given states.
55 void VerifySyncGlobalErrorResult(NiceMock<ProfileSyncServiceMock>* service,
56 GoogleServiceAuthError::State error_state,
57 bool is_signed_in,
58 bool is_error) {
59 EXPECT_CALL(*service, HasSyncSetupCompleted())
60 .WillRepeatedly(Return(is_signed_in));
62 GoogleServiceAuthError auth_error(error_state);
63 EXPECT_CALL(*service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error));
65 base::string16 label1, label2, label3;
66 sync_ui_util::GetStatusLabelsForSyncGlobalError(
67 service, &label1, &label2, &label3);
68 EXPECT_EQ(label1.empty(), !is_error);
69 EXPECT_EQ(label2.empty(), !is_error);
70 EXPECT_EQ(label3.empty(), !is_error);
72 #endif
74 } // namespace
77 class SyncUIUtilTest : public testing::Test {
78 private:
79 content::TestBrowserThreadBundle thread_bundle_;
82 #if !defined(OS_CHROMEOS)
83 // Test that GetStatusLabelsForSyncGlobalError returns an error if a
84 // passphrase is required.
85 TEST_F(SyncUIUtilTest, PassphraseGlobalError) {
86 scoped_ptr<Profile> profile(
87 ProfileSyncServiceMock::MakeSignedInTestingProfile());
88 NiceMock<ProfileSyncServiceMock> service(profile.get());
89 browser_sync::SyncBackendHost::Status status;
90 EXPECT_CALL(service, QueryDetailedSyncStatus(_))
91 .WillRepeatedly(Return(false));
92 EXPECT_CALL(service, IsPassphraseRequired())
93 .WillRepeatedly(Return(true));
94 EXPECT_CALL(service, IsPassphraseRequiredForDecryption())
95 .WillRepeatedly(Return(true));
97 VerifySyncGlobalErrorResult(&service,
98 GoogleServiceAuthError::NONE,
99 true /* signed in */,
100 true /* error */);
103 // Test that GetStatusLabelsForSyncGlobalError returns an error if a
104 // passphrase is required and not for auth errors.
105 TEST_F(SyncUIUtilTest, AuthAndPassphraseGlobalError) {
106 scoped_ptr<Profile> profile(
107 ProfileSyncServiceMock::MakeSignedInTestingProfile());
108 NiceMock<ProfileSyncServiceMock> service(profile.get());
109 browser_sync::SyncBackendHost::Status status;
110 EXPECT_CALL(service, QueryDetailedSyncStatus(_))
111 .WillRepeatedly(Return(false));
113 EXPECT_CALL(service, IsPassphraseRequired())
114 .WillRepeatedly(Return(true));
115 EXPECT_CALL(service, IsPassphraseRequiredForDecryption())
116 .WillRepeatedly(Return(true));
117 EXPECT_CALL(service, HasSyncSetupCompleted())
118 .WillRepeatedly(Return(true));
120 GoogleServiceAuthError auth_error(
121 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
122 EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error));
123 base::string16 menu_label, label2, label3;
124 sync_ui_util::GetStatusLabelsForSyncGlobalError(
125 &service, &menu_label, &label2, &label3);
126 // Make sure we are still displaying the passphrase error badge (don't show
127 // auth errors through SyncUIUtil).
128 EXPECT_EQ(menu_label, l10n_util::GetStringUTF16(
129 IDS_SYNC_PASSPHRASE_ERROR_WRENCH_MENU_ITEM));
132 // Test that GetStatusLabelsForSyncGlobalError does not indicate errors for
133 // auth errors (these are reported through SigninGlobalError).
134 TEST_F(SyncUIUtilTest, AuthStateGlobalError) {
135 scoped_ptr<Profile> profile(
136 ProfileSyncServiceMock::MakeSignedInTestingProfile());
137 NiceMock<ProfileSyncServiceMock> service(profile.get());
139 browser_sync::SyncBackendHost::Status status;
140 EXPECT_CALL(service, QueryDetailedSyncStatus(_))
141 .WillRepeatedly(Return(false));
143 GoogleServiceAuthError::State table[] = {
144 GoogleServiceAuthError::NONE,
145 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
146 GoogleServiceAuthError::USER_NOT_SIGNED_UP,
147 GoogleServiceAuthError::CONNECTION_FAILED,
148 GoogleServiceAuthError::CAPTCHA_REQUIRED,
149 GoogleServiceAuthError::ACCOUNT_DELETED,
150 GoogleServiceAuthError::ACCOUNT_DISABLED,
151 GoogleServiceAuthError::SERVICE_UNAVAILABLE,
152 GoogleServiceAuthError::TWO_FACTOR,
153 GoogleServiceAuthError::REQUEST_CANCELED,
154 GoogleServiceAuthError::HOSTED_NOT_ALLOWED
157 FakeSigninManagerBase signin(
158 ChromeSigninClientFactory::GetForProfile(profile.get()),
159 AccountTrackerServiceFactory::GetForProfile(profile.get()));
160 for (size_t i = 0; i < arraysize(table); ++i) {
161 VerifySyncGlobalErrorResult(&service,
162 table[i],
163 true /* signed in */,
164 false /* no error */);
165 VerifySyncGlobalErrorResult(&service,
166 table[i],
167 false /* not signed in */,
168 false /* no error */);
171 #endif
173 // TODO(tim): This shouldn't be required. r194857 removed the
174 // AuthInProgress override from FakeSigninManager, which meant this test started
175 // using the "real" SigninManager AuthInProgress logic. Without that override,
176 // it's no longer possible to test both chrome os + desktop flows as part of the
177 // same test, because AuthInProgress is always false on chrome os. Most of the
178 // tests are unaffected, but STATUS_CASE_AUTHENTICATING can't exist in both
179 // versions, so it we will require two separate tests, one using SigninManager
180 // and one using SigninManagerBase (which require different setup procedures.
181 class FakeSigninManagerForSyncUIUtilTest : public FakeSigninManagerBase {
182 public:
183 explicit FakeSigninManagerForSyncUIUtilTest(Profile* profile)
184 : FakeSigninManagerBase(
185 ChromeSigninClientFactory::GetForProfile(profile),
186 AccountTrackerServiceFactory::GetForProfile(profile)),
187 auth_in_progress_(false) {
188 Initialize(NULL);
191 ~FakeSigninManagerForSyncUIUtilTest() override {}
193 bool AuthInProgress() const override { return auth_in_progress_; }
195 void set_auth_in_progress() {
196 auth_in_progress_ = true;
199 private:
200 bool auth_in_progress_;
203 // Loads a ProfileSyncServiceMock to emulate one of a number of distinct cases
204 // in order to perform tests on the generated messages.
205 void GetDistinctCase(ProfileSyncServiceMock& service,
206 FakeSigninManagerForSyncUIUtilTest* signin,
207 FakeAuthStatusProvider* provider,
208 int caseNumber) {
209 // Auth Error object is returned by reference in mock and needs to stay in
210 // scope throughout test, so it is owned by calling method. However it is
211 // immutable so can only be allocated in this method.
212 switch (caseNumber) {
213 case STATUS_CASE_SETUP_IN_PROGRESS: {
214 EXPECT_CALL(service, HasSyncSetupCompleted())
215 .WillRepeatedly(Return(false));
216 EXPECT_CALL(service, IsFirstSetupInProgress())
217 .WillRepeatedly(Return(true));
218 browser_sync::SyncBackendHost::Status status;
219 EXPECT_CALL(service, QueryDetailedSyncStatus(_))
220 .WillRepeatedly(DoAll(SetArgPointee<0>(status),
221 Return(false)));
222 return;
224 case STATUS_CASE_SETUP_ERROR: {
225 EXPECT_CALL(service, HasSyncSetupCompleted())
226 .WillRepeatedly(Return(false));
227 EXPECT_CALL(service, IsFirstSetupInProgress())
228 .WillRepeatedly(Return(false));
229 EXPECT_CALL(service, HasUnrecoverableError())
230 .WillRepeatedly(Return(true));
231 browser_sync::SyncBackendHost::Status status;
232 EXPECT_CALL(service, QueryDetailedSyncStatus(_))
233 .WillRepeatedly(DoAll(SetArgPointee<0>(status),
234 Return(false)));
235 return;
237 case STATUS_CASE_AUTHENTICATING: {
238 EXPECT_CALL(service, HasSyncSetupCompleted())
239 .WillRepeatedly(Return(true));
240 EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(true));
241 EXPECT_CALL(service, IsPassphraseRequired())
242 .WillRepeatedly(Return(false));
243 browser_sync::SyncBackendHost::Status status;
244 EXPECT_CALL(service, QueryDetailedSyncStatus(_))
245 .WillRepeatedly(DoAll(SetArgPointee<0>(status),
246 Return(false)));
247 EXPECT_CALL(service, HasUnrecoverableError())
248 .WillRepeatedly(Return(false));
249 signin->set_auth_in_progress();
250 return;
252 case STATUS_CASE_AUTH_ERROR: {
253 EXPECT_CALL(service, HasSyncSetupCompleted())
254 .WillRepeatedly(Return(true));
255 EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(true));
256 EXPECT_CALL(service, IsPassphraseRequired())
257 .WillRepeatedly(Return(false));
258 browser_sync::SyncBackendHost::Status status;
259 EXPECT_CALL(service, QueryDetailedSyncStatus(_))
260 .WillRepeatedly(DoAll(SetArgPointee<0>(status),
261 Return(false)));
262 provider->SetAuthError(
263 signin->GetAuthenticatedAccountId(),
264 GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
265 EXPECT_CALL(service, HasUnrecoverableError())
266 .WillRepeatedly(Return(false));
267 return;
269 case STATUS_CASE_PROTOCOL_ERROR: {
270 EXPECT_CALL(service, HasSyncSetupCompleted())
271 .WillRepeatedly(Return(true));
272 EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(true));
273 EXPECT_CALL(service, IsPassphraseRequired())
274 .WillRepeatedly(Return(false));
275 syncer::SyncProtocolError protocolError;
276 protocolError.action = syncer::STOP_AND_RESTART_SYNC;
277 browser_sync::SyncBackendHost::Status status;
278 status.sync_protocol_error = protocolError;
279 EXPECT_CALL(service, QueryDetailedSyncStatus(_))
280 .WillRepeatedly(DoAll(SetArgPointee<0>(status),
281 Return(false)));
282 EXPECT_CALL(service, HasUnrecoverableError())
283 .WillRepeatedly(Return(false));
284 return;
286 case STATUS_CASE_PASSPHRASE_ERROR: {
287 EXPECT_CALL(service, HasSyncSetupCompleted())
288 .WillRepeatedly(Return(true));
289 EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(true));
290 browser_sync::SyncBackendHost::Status status;
291 EXPECT_CALL(service, QueryDetailedSyncStatus(_))
292 .WillRepeatedly(DoAll(SetArgPointee<0>(status),
293 Return(false)));
294 EXPECT_CALL(service, HasUnrecoverableError())
295 .WillRepeatedly(Return(false));
296 EXPECT_CALL(service, IsPassphraseRequired())
297 .WillRepeatedly(Return(true));
298 EXPECT_CALL(service, IsPassphraseRequiredForDecryption())
299 .WillRepeatedly(Return(true));
300 return;
302 case STATUS_CASE_SYNCED: {
303 EXPECT_CALL(service, HasSyncSetupCompleted())
304 .WillRepeatedly(Return(true));
305 EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(true));
306 EXPECT_CALL(service, IsPassphraseRequired())
307 .WillRepeatedly(Return(false));
308 browser_sync::SyncBackendHost::Status status;
309 EXPECT_CALL(service, QueryDetailedSyncStatus(_))
310 .WillRepeatedly(DoAll(SetArgPointee<0>(status),
311 Return(false)));
312 EXPECT_CALL(service, HasUnrecoverableError())
313 .WillRepeatedly(Return(false));
314 EXPECT_CALL(service, IsPassphraseRequired())
315 .WillRepeatedly(Return(false));
316 return;
318 case STATUS_CASE_SYNC_DISABLED_BY_POLICY: {
319 EXPECT_CALL(service, IsManaged()).WillRepeatedly(Return(true));
320 EXPECT_CALL(service, HasSyncSetupCompleted())
321 .WillRepeatedly(Return(false));
322 EXPECT_CALL(service, IsSyncActive()).WillRepeatedly(Return(false));
323 EXPECT_CALL(service, IsPassphraseRequired())
324 .WillRepeatedly(Return(false));
325 browser_sync::SyncBackendHost::Status status;
326 EXPECT_CALL(service, QueryDetailedSyncStatus(_))
327 .WillRepeatedly(DoAll(SetArgPointee<0>(status),
328 Return(false)));
329 EXPECT_CALL(service, HasUnrecoverableError())
330 .WillRepeatedly(Return(false));
331 return;
333 default:
334 NOTREACHED();
338 // This test ensures that a each distinctive ProfileSyncService statuses
339 // will return a unique combination of status and link messages from
340 // GetStatusLabels().
341 TEST_F(SyncUIUtilTest, DistinctCasesReportUniqueMessageSets) {
342 std::set<base::string16> messages;
343 for (int idx = 0; idx != NUMBER_OF_STATUS_CASES; idx++) {
344 scoped_ptr<Profile> profile(new TestingProfile());
345 ProfileSyncServiceMock service(profile.get());
346 GoogleServiceAuthError error = GoogleServiceAuthError::AuthErrorNone();
347 EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
348 FakeSigninManagerForSyncUIUtilTest signin(profile.get());
349 signin.SetAuthenticatedAccountInfo(kTestGaiaId, kTestUser);
350 scoped_ptr<FakeAuthStatusProvider> provider(new FakeAuthStatusProvider(
351 SigninErrorControllerFactory::GetForProfile(profile.get())));
352 GetDistinctCase(service, &signin, provider.get(), idx);
353 base::string16 status_label;
354 base::string16 link_label;
355 sync_ui_util::GetStatusLabels(&service,
356 signin,
357 sync_ui_util::WITH_HTML,
358 &status_label,
359 &link_label);
360 // If the status and link message combination is already present in the set
361 // of messages already seen, this is a duplicate rather than a unique
362 // message, and the test has failed.
363 EXPECT_FALSE(status_label.empty()) <<
364 "Empty status label returned for case #" << idx;
365 base::string16 combined_label =
366 status_label + base::ASCIIToUTF16("#") + link_label;
367 EXPECT_TRUE(messages.find(combined_label) == messages.end()) <<
368 "Duplicate message for case #" << idx << ": " << combined_label;
369 messages.insert(combined_label);
370 testing::Mock::VerifyAndClearExpectations(&service);
371 testing::Mock::VerifyAndClearExpectations(&signin);
372 EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
373 provider.reset();
374 signin.Shutdown();
378 // This test ensures that the html_links parameter on GetStatusLabels() is
379 // honored.
380 TEST_F(SyncUIUtilTest, HtmlNotIncludedInStatusIfNotRequested) {
381 for (int idx = 0; idx != NUMBER_OF_STATUS_CASES; idx++) {
382 scoped_ptr<Profile> profile(
383 ProfileSyncServiceMock::MakeSignedInTestingProfile());
384 ProfileSyncServiceMock service(profile.get());
385 GoogleServiceAuthError error = GoogleServiceAuthError::AuthErrorNone();
386 EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
387 FakeSigninManagerForSyncUIUtilTest signin(profile.get());
388 signin.SetAuthenticatedAccountInfo(kTestGaiaId, kTestUser);
389 scoped_ptr<FakeAuthStatusProvider> provider(new FakeAuthStatusProvider(
390 SigninErrorControllerFactory::GetForProfile(profile.get())));
391 GetDistinctCase(service, &signin, provider.get(), idx);
392 base::string16 status_label;
393 base::string16 link_label;
394 sync_ui_util::GetStatusLabels(&service,
395 signin,
396 sync_ui_util::PLAIN_TEXT,
397 &status_label,
398 &link_label);
400 // Ensures a search for string 'href' (found in links, not a string to be
401 // found in an English language message) fails when links are excluded from
402 // the status label.
403 EXPECT_FALSE(status_label.empty());
404 EXPECT_EQ(status_label.find(base::ASCIIToUTF16("href")),
405 base::string16::npos);
406 testing::Mock::VerifyAndClearExpectations(&service);
407 testing::Mock::VerifyAndClearExpectations(&signin);
408 EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
409 provider.reset();
410 signin.Shutdown();