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.
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/fake_signin_manager.h"
10 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
11 #include "chrome/browser/sync/profile_sync_service_mock.h"
12 #include "chrome/browser/sync/sync_ui_util.h"
13 #include "chrome/grit/generated_resources.h"
14 #include "components/signin/core/browser/fake_auth_status_provider.h"
15 #include "components/signin/core/browser/profile_oauth2_token_service.h"
16 #include "components/signin/core/browser/signin_manager.h"
17 #include "content/public/test/test_browser_thread.h"
18 #include "content/public/test/test_browser_thread_bundle.h"
19 #include "testing/gmock/include/gmock/gmock-actions.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "ui/base/l10n/l10n_util.h"
24 using ::testing::AtMost
;
25 using ::testing::NiceMock
;
26 using ::testing::Return
;
27 using ::testing::ReturnRef
;
28 using ::testing::SetArgPointee
;
30 using content::BrowserThread
;
32 // A number of distinct states of the ProfileSyncService can be generated for
35 STATUS_CASE_SETUP_IN_PROGRESS
,
36 STATUS_CASE_SETUP_ERROR
,
37 STATUS_CASE_AUTHENTICATING
,
38 STATUS_CASE_AUTH_ERROR
,
39 STATUS_CASE_PROTOCOL_ERROR
,
40 STATUS_CASE_PASSPHRASE_ERROR
,
42 STATUS_CASE_SYNC_DISABLED_BY_POLICY
,
43 NUMBER_OF_STATUS_CASES
48 const char kTestUser
[] = "test_user@test.com";
50 #if !defined(OS_CHROMEOS)
51 // Utility function to test that GetStatusLabelsForSyncGlobalError returns
52 // the correct results for the given states.
53 void VerifySyncGlobalErrorResult(NiceMock
<ProfileSyncServiceMock
>* service
,
54 GoogleServiceAuthError::State error_state
,
57 EXPECT_CALL(*service
, HasSyncSetupCompleted())
58 .WillRepeatedly(Return(is_signed_in
));
60 GoogleServiceAuthError
auth_error(error_state
);
61 EXPECT_CALL(*service
, GetAuthError()).WillRepeatedly(ReturnRef(auth_error
));
63 base::string16 label1
, label2
, label3
;
64 sync_ui_util::GetStatusLabelsForSyncGlobalError(
65 service
, &label1
, &label2
, &label3
);
66 EXPECT_EQ(label1
.empty(), !is_error
);
67 EXPECT_EQ(label2
.empty(), !is_error
);
68 EXPECT_EQ(label3
.empty(), !is_error
);
75 class SyncUIUtilTest
: public testing::Test
{
77 content::TestBrowserThreadBundle thread_bundle_
;
80 #if !defined(OS_CHROMEOS)
81 // Test that GetStatusLabelsForSyncGlobalError returns an error if a
82 // passphrase is required.
83 TEST_F(SyncUIUtilTest
, PassphraseGlobalError
) {
84 scoped_ptr
<Profile
> profile(
85 ProfileSyncServiceMock::MakeSignedInTestingProfile());
86 NiceMock
<ProfileSyncServiceMock
> service(profile
.get());
87 browser_sync::SyncBackendHost::Status status
;
88 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
89 .WillRepeatedly(Return(false));
90 EXPECT_CALL(service
, IsPassphraseRequired())
91 .WillRepeatedly(Return(true));
92 EXPECT_CALL(service
, IsPassphraseRequiredForDecryption())
93 .WillRepeatedly(Return(true));
95 VerifySyncGlobalErrorResult(&service
,
96 GoogleServiceAuthError::NONE
,
101 // Test that GetStatusLabelsForSyncGlobalError returns an error if a
102 // passphrase is required and not for auth errors.
103 TEST_F(SyncUIUtilTest
, AuthAndPassphraseGlobalError
) {
104 scoped_ptr
<Profile
> profile(
105 ProfileSyncServiceMock::MakeSignedInTestingProfile());
106 NiceMock
<ProfileSyncServiceMock
> service(profile
.get());
107 browser_sync::SyncBackendHost::Status status
;
108 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
109 .WillRepeatedly(Return(false));
111 EXPECT_CALL(service
, IsPassphraseRequired())
112 .WillRepeatedly(Return(true));
113 EXPECT_CALL(service
, IsPassphraseRequiredForDecryption())
114 .WillRepeatedly(Return(true));
115 EXPECT_CALL(service
, HasSyncSetupCompleted())
116 .WillRepeatedly(Return(true));
118 GoogleServiceAuthError
auth_error(
119 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
);
120 EXPECT_CALL(service
, GetAuthError()).WillRepeatedly(ReturnRef(auth_error
));
121 base::string16 menu_label
, label2
, label3
;
122 sync_ui_util::GetStatusLabelsForSyncGlobalError(
123 &service
, &menu_label
, &label2
, &label3
);
124 // Make sure we are still displaying the passphrase error badge (don't show
125 // auth errors through SyncUIUtil).
126 EXPECT_EQ(menu_label
, l10n_util::GetStringUTF16(
127 IDS_SYNC_PASSPHRASE_ERROR_WRENCH_MENU_ITEM
));
130 // Test that GetStatusLabelsForSyncGlobalError does not indicate errors for
131 // auth errors (these are reported through SigninGlobalError).
132 TEST_F(SyncUIUtilTest
, AuthStateGlobalError
) {
133 scoped_ptr
<Profile
> profile(
134 ProfileSyncServiceMock::MakeSignedInTestingProfile());
135 NiceMock
<ProfileSyncServiceMock
> service(profile
.get());
137 browser_sync::SyncBackendHost::Status status
;
138 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
139 .WillRepeatedly(Return(false));
141 GoogleServiceAuthError::State table
[] = {
142 GoogleServiceAuthError::NONE
,
143 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
,
144 GoogleServiceAuthError::USER_NOT_SIGNED_UP
,
145 GoogleServiceAuthError::CONNECTION_FAILED
,
146 GoogleServiceAuthError::CAPTCHA_REQUIRED
,
147 GoogleServiceAuthError::ACCOUNT_DELETED
,
148 GoogleServiceAuthError::ACCOUNT_DISABLED
,
149 GoogleServiceAuthError::SERVICE_UNAVAILABLE
,
150 GoogleServiceAuthError::TWO_FACTOR
,
151 GoogleServiceAuthError::REQUEST_CANCELED
,
152 GoogleServiceAuthError::HOSTED_NOT_ALLOWED
155 FakeSigninManagerBase
signin(profile
.get());
156 for (size_t i
= 0; i
< arraysize(table
); ++i
) {
157 VerifySyncGlobalErrorResult(&service
,
159 true /* signed in */,
160 false /* no error */);
161 VerifySyncGlobalErrorResult(&service
,
163 false /* not signed in */,
164 false /* no error */);
169 // TODO(tim): This shouldn't be required. r194857 removed the
170 // AuthInProgress override from FakeSigninManager, which meant this test started
171 // using the "real" SigninManager AuthInProgress logic. Without that override,
172 // it's no longer possible to test both chrome os + desktop flows as part of the
173 // same test, because AuthInProgress is always false on chrome os. Most of the
174 // tests are unaffected, but STATUS_CASE_AUTHENTICATING can't exist in both
175 // versions, so it we will require two separate tests, one using SigninManager
176 // and one using SigninManagerBase (which require different setup procedures.
177 class FakeSigninManagerForSyncUIUtilTest
: public FakeSigninManagerBase
{
179 explicit FakeSigninManagerForSyncUIUtilTest(Profile
* profile
)
180 : FakeSigninManagerBase(profile
), auth_in_progress_(false) {
184 virtual ~FakeSigninManagerForSyncUIUtilTest() {
187 virtual bool AuthInProgress() const override
{
188 return auth_in_progress_
;
191 void set_auth_in_progress() {
192 auth_in_progress_
= true;
196 bool auth_in_progress_
;
199 // Loads a ProfileSyncServiceMock to emulate one of a number of distinct cases
200 // in order to perform tests on the generated messages.
201 void GetDistinctCase(ProfileSyncServiceMock
& service
,
202 FakeSigninManagerForSyncUIUtilTest
* signin
,
203 FakeAuthStatusProvider
* provider
,
205 // Auth Error object is returned by reference in mock and needs to stay in
206 // scope throughout test, so it is owned by calling method. However it is
207 // immutable so can only be allocated in this method.
208 switch (caseNumber
) {
209 case STATUS_CASE_SETUP_IN_PROGRESS
: {
210 EXPECT_CALL(service
, HasSyncSetupCompleted())
211 .WillRepeatedly(Return(false));
212 EXPECT_CALL(service
, FirstSetupInProgress())
213 .WillRepeatedly(Return(true));
214 browser_sync::SyncBackendHost::Status status
;
215 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
216 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
220 case STATUS_CASE_SETUP_ERROR
: {
221 EXPECT_CALL(service
, HasSyncSetupCompleted())
222 .WillRepeatedly(Return(false));
223 EXPECT_CALL(service
, FirstSetupInProgress())
224 .WillRepeatedly(Return(false));
225 EXPECT_CALL(service
, HasUnrecoverableError())
226 .WillRepeatedly(Return(true));
227 browser_sync::SyncBackendHost::Status status
;
228 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
229 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
233 case STATUS_CASE_AUTHENTICATING
: {
234 EXPECT_CALL(service
, HasSyncSetupCompleted())
235 .WillRepeatedly(Return(true));
236 EXPECT_CALL(service
, SyncActive()).WillRepeatedly(Return(true));
237 EXPECT_CALL(service
, IsPassphraseRequired())
238 .WillRepeatedly(Return(false));
239 browser_sync::SyncBackendHost::Status status
;
240 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
241 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
243 EXPECT_CALL(service
, HasUnrecoverableError())
244 .WillRepeatedly(Return(false));
245 signin
->set_auth_in_progress();
248 case STATUS_CASE_AUTH_ERROR
: {
249 EXPECT_CALL(service
, HasSyncSetupCompleted())
250 .WillRepeatedly(Return(true));
251 EXPECT_CALL(service
, SyncActive()).WillRepeatedly(Return(true));
252 EXPECT_CALL(service
, IsPassphraseRequired())
253 .WillRepeatedly(Return(false));
254 browser_sync::SyncBackendHost::Status status
;
255 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
256 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
258 provider
->SetAuthError(
261 GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE
));
262 EXPECT_CALL(service
, HasUnrecoverableError())
263 .WillRepeatedly(Return(false));
266 case STATUS_CASE_PROTOCOL_ERROR
: {
267 EXPECT_CALL(service
, HasSyncSetupCompleted())
268 .WillRepeatedly(Return(true));
269 EXPECT_CALL(service
, SyncActive()).WillRepeatedly(Return(true));
270 EXPECT_CALL(service
, IsPassphraseRequired())
271 .WillRepeatedly(Return(false));
272 syncer::SyncProtocolError protocolError
;
273 protocolError
.action
= syncer::STOP_AND_RESTART_SYNC
;
274 browser_sync::SyncBackendHost::Status status
;
275 status
.sync_protocol_error
= protocolError
;
276 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
277 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
279 EXPECT_CALL(service
, HasUnrecoverableError())
280 .WillRepeatedly(Return(false));
283 case STATUS_CASE_PASSPHRASE_ERROR
: {
284 EXPECT_CALL(service
, HasSyncSetupCompleted())
285 .WillRepeatedly(Return(true));
286 EXPECT_CALL(service
, SyncActive()).WillRepeatedly(Return(true));
287 browser_sync::SyncBackendHost::Status status
;
288 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
289 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
291 EXPECT_CALL(service
, HasUnrecoverableError())
292 .WillRepeatedly(Return(false));
293 EXPECT_CALL(service
, IsPassphraseRequired())
294 .WillRepeatedly(Return(true));
295 EXPECT_CALL(service
, IsPassphraseRequiredForDecryption())
296 .WillRepeatedly(Return(true));
299 case STATUS_CASE_SYNCED
: {
300 EXPECT_CALL(service
, HasSyncSetupCompleted())
301 .WillRepeatedly(Return(true));
302 EXPECT_CALL(service
, SyncActive()).WillRepeatedly(Return(true));
303 EXPECT_CALL(service
, IsPassphraseRequired())
304 .WillRepeatedly(Return(false));
305 browser_sync::SyncBackendHost::Status status
;
306 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
307 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
309 EXPECT_CALL(service
, HasUnrecoverableError())
310 .WillRepeatedly(Return(false));
311 EXPECT_CALL(service
, IsPassphraseRequired())
312 .WillRepeatedly(Return(false));
315 case STATUS_CASE_SYNC_DISABLED_BY_POLICY
: {
316 EXPECT_CALL(service
, IsManaged()).WillRepeatedly(Return(true));
317 EXPECT_CALL(service
, HasSyncSetupCompleted())
318 .WillRepeatedly(Return(false));
319 EXPECT_CALL(service
, SyncActive()).WillRepeatedly(Return(false));
320 EXPECT_CALL(service
, IsPassphraseRequired())
321 .WillRepeatedly(Return(false));
322 browser_sync::SyncBackendHost::Status status
;
323 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
324 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
326 EXPECT_CALL(service
, HasUnrecoverableError())
327 .WillRepeatedly(Return(false));
335 // This test ensures that a each distinctive ProfileSyncService statuses
336 // will return a unique combination of status and link messages from
337 // GetStatusLabels().
338 TEST_F(SyncUIUtilTest
, DistinctCasesReportUniqueMessageSets
) {
339 std::set
<base::string16
> messages
;
340 for (int idx
= 0; idx
!= NUMBER_OF_STATUS_CASES
; idx
++) {
341 scoped_ptr
<Profile
> profile(new TestingProfile());
342 ProfileSyncServiceMock
service(profile
.get());
343 GoogleServiceAuthError error
= GoogleServiceAuthError::AuthErrorNone();
344 EXPECT_CALL(service
, GetAuthError()).WillRepeatedly(ReturnRef(error
));
345 FakeSigninManagerForSyncUIUtilTest
signin(profile
.get());
346 signin
.SetAuthenticatedUsername(kTestUser
);
347 scoped_ptr
<FakeAuthStatusProvider
> provider(new FakeAuthStatusProvider(
348 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
.get())->
349 signin_error_controller()));
350 GetDistinctCase(service
, &signin
, provider
.get(), idx
);
351 base::string16 status_label
;
352 base::string16 link_label
;
353 sync_ui_util::GetStatusLabels(&service
,
355 sync_ui_util::WITH_HTML
,
358 // If the status and link message combination is already present in the set
359 // of messages already seen, this is a duplicate rather than a unique
360 // message, and the test has failed.
361 EXPECT_FALSE(status_label
.empty()) <<
362 "Empty status label returned for case #" << idx
;
363 base::string16 combined_label
=
364 status_label
+ base::ASCIIToUTF16("#") + link_label
;
365 EXPECT_TRUE(messages
.find(combined_label
) == messages
.end()) <<
366 "Duplicate message for case #" << idx
<< ": " << combined_label
;
367 messages
.insert(combined_label
);
368 testing::Mock::VerifyAndClearExpectations(&service
);
369 testing::Mock::VerifyAndClearExpectations(&signin
);
370 EXPECT_CALL(service
, GetAuthError()).WillRepeatedly(ReturnRef(error
));
376 // This test ensures that the html_links parameter on GetStatusLabels() is
378 TEST_F(SyncUIUtilTest
, HtmlNotIncludedInStatusIfNotRequested
) {
379 for (int idx
= 0; idx
!= NUMBER_OF_STATUS_CASES
; idx
++) {
380 scoped_ptr
<Profile
> profile(
381 ProfileSyncServiceMock::MakeSignedInTestingProfile());
382 ProfileSyncServiceMock
service(profile
.get());
383 GoogleServiceAuthError error
= GoogleServiceAuthError::AuthErrorNone();
384 EXPECT_CALL(service
, GetAuthError()).WillRepeatedly(ReturnRef(error
));
385 FakeSigninManagerForSyncUIUtilTest
signin(profile
.get());
386 signin
.SetAuthenticatedUsername(kTestUser
);
387 scoped_ptr
<FakeAuthStatusProvider
> provider(new FakeAuthStatusProvider(
388 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
.get())->
389 signin_error_controller()));
390 GetDistinctCase(service
, &signin
, provider
.get(), idx
);
391 base::string16 status_label
;
392 base::string16 link_label
;
393 sync_ui_util::GetStatusLabels(&service
,
395 sync_ui_util::PLAIN_TEXT
,
399 // Ensures a search for string 'href' (found in links, not a string to be
400 // found in an English language message) fails when links are excluded from
402 EXPECT_FALSE(status_label
.empty());
403 EXPECT_EQ(status_label
.find(base::ASCIIToUTF16("href")),
404 base::string16::npos
);
405 testing::Mock::VerifyAndClearExpectations(&service
);
406 testing::Mock::VerifyAndClearExpectations(&signin
);
407 EXPECT_CALL(service
, GetAuthError()).WillRepeatedly(ReturnRef(error
));