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_auth_status_provider.h"
10 #include "chrome/browser/signin/fake_signin_manager.h"
11 #include "chrome/browser/signin/signin_manager.h"
12 #include "chrome/browser/sync/profile_sync_service_mock.h"
13 #include "chrome/browser/sync/sync_ui_util.h"
14 #include "content/public/test/test_browser_thread.h"
15 #include "content/public/test/test_browser_thread_bundle.h"
16 #include "grit/generated_resources.h"
17 #include "testing/gmock/include/gmock/gmock-actions.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "ui/base/l10n/l10n_util.h"
22 using ::testing::AtMost
;
23 using ::testing::NiceMock
;
24 using ::testing::Return
;
25 using ::testing::ReturnRef
;
26 using ::testing::SetArgPointee
;
28 using content::BrowserThread
;
30 // A number of distinct states of the ProfileSyncService can be generated for
33 STATUS_CASE_SETUP_IN_PROGRESS
,
34 STATUS_CASE_SETUP_ERROR
,
35 STATUS_CASE_AUTHENTICATING
,
36 STATUS_CASE_AUTH_ERROR
,
37 STATUS_CASE_PROTOCOL_ERROR
,
38 STATUS_CASE_PASSPHRASE_ERROR
,
40 STATUS_CASE_SYNC_DISABLED_BY_POLICY
,
41 NUMBER_OF_STATUS_CASES
46 const char kTestUser
[] = "test_user@test.com";
48 // Utility function to test that GetStatusLabelsForSyncGlobalError returns
49 // the correct results for the given states.
50 void VerifySyncGlobalErrorResult(NiceMock
<ProfileSyncServiceMock
>* service
,
51 const SigninManagerBase
& signin
,
52 GoogleServiceAuthError::State error_state
,
55 EXPECT_CALL(*service
, HasSyncSetupCompleted())
56 .WillRepeatedly(Return(is_signed_in
));
58 GoogleServiceAuthError
auth_error(error_state
);
59 EXPECT_CALL(*service
, GetAuthError()).WillRepeatedly(ReturnRef(auth_error
));
61 base::string16 label1
, label2
, label3
;
62 sync_ui_util::GetStatusLabelsForSyncGlobalError(
63 service
, signin
, &label1
, &label2
, &label3
);
64 EXPECT_EQ(label1
.empty(), !is_error
);
65 EXPECT_EQ(label2
.empty(), !is_error
);
66 EXPECT_EQ(label3
.empty(), !is_error
);
72 class SyncUIUtilTest
: public testing::Test
{
74 content::TestBrowserThreadBundle thread_bundle_
;
77 // Test that GetStatusLabelsForSyncGlobalError returns an error if a
78 // passphrase is required.
79 TEST_F(SyncUIUtilTest
, PassphraseGlobalError
) {
80 scoped_ptr
<Profile
> profile(
81 ProfileSyncServiceMock::MakeSignedInTestingProfile());
82 NiceMock
<ProfileSyncServiceMock
> service(profile
.get());
83 FakeSigninManagerBase signin
;
84 browser_sync::SyncBackendHost::Status status
;
85 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
86 .WillRepeatedly(Return(false));
87 EXPECT_CALL(service
, IsPassphraseRequired())
88 .WillRepeatedly(Return(true));
89 EXPECT_CALL(service
, IsPassphraseRequiredForDecryption())
90 .WillRepeatedly(Return(true));
91 VerifySyncGlobalErrorResult(
92 &service
, signin
, GoogleServiceAuthError::NONE
, true, true);
95 // Test that GetStatusLabelsForSyncGlobalError returns an error if a
96 // passphrase is required and not for auth errors.
97 TEST_F(SyncUIUtilTest
, AuthAndPassphraseGlobalError
) {
98 scoped_ptr
<Profile
> profile(
99 ProfileSyncServiceMock::MakeSignedInTestingProfile());
100 NiceMock
<ProfileSyncServiceMock
> service(profile
.get());
101 FakeSigninManagerBase signin
;
102 browser_sync::SyncBackendHost::Status status
;
103 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
104 .WillRepeatedly(Return(false));
106 EXPECT_CALL(service
, IsPassphraseRequired())
107 .WillRepeatedly(Return(true));
108 EXPECT_CALL(service
, IsPassphraseRequiredForDecryption())
109 .WillRepeatedly(Return(true));
110 EXPECT_CALL(service
, HasSyncSetupCompleted())
111 .WillRepeatedly(Return(true));
113 GoogleServiceAuthError
auth_error(
114 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
);
115 EXPECT_CALL(service
, GetAuthError()).WillRepeatedly(ReturnRef(auth_error
));
116 base::string16 menu_label
, label2
, label3
;
117 sync_ui_util::GetStatusLabelsForSyncGlobalError(
118 &service
, signin
, &menu_label
, &label2
, &label3
);
119 // Make sure we are still displaying the passphrase error badge (don't show
120 // auth errors through SyncUIUtil).
121 EXPECT_EQ(menu_label
, l10n_util::GetStringUTF16(
122 IDS_SYNC_PASSPHRASE_ERROR_WRENCH_MENU_ITEM
));
125 // Test that GetStatusLabelsForSyncGlobalError does not indicate errors for
126 // auth errors (these are reported through SigninGlobalError).
127 TEST_F(SyncUIUtilTest
, AuthStateGlobalError
) {
128 scoped_ptr
<Profile
> profile(
129 ProfileSyncServiceMock::MakeSignedInTestingProfile());
130 NiceMock
<ProfileSyncServiceMock
> service(profile
.get());
132 browser_sync::SyncBackendHost::Status status
;
133 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
134 .WillRepeatedly(Return(false));
136 GoogleServiceAuthError::State table
[] = {
137 GoogleServiceAuthError::NONE
,
138 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
,
139 GoogleServiceAuthError::USER_NOT_SIGNED_UP
,
140 GoogleServiceAuthError::CONNECTION_FAILED
,
141 GoogleServiceAuthError::CAPTCHA_REQUIRED
,
142 GoogleServiceAuthError::ACCOUNT_DELETED
,
143 GoogleServiceAuthError::ACCOUNT_DISABLED
,
144 GoogleServiceAuthError::SERVICE_UNAVAILABLE
,
145 GoogleServiceAuthError::TWO_FACTOR
,
146 GoogleServiceAuthError::REQUEST_CANCELED
,
147 GoogleServiceAuthError::HOSTED_NOT_ALLOWED
150 FakeSigninManagerBase signin
;
151 for (size_t i
= 0; i
< arraysize(table
); ++i
) {
152 VerifySyncGlobalErrorResult(&service
, signin
, table
[i
], true, false);
153 VerifySyncGlobalErrorResult(&service
, signin
, table
[i
], false, false);
157 // TODO(tim): This shouldn't be required. r194857 removed the
158 // AuthInProgress override from FakeSigninManager, which meant this test started
159 // using the "real" SigninManager AuthInProgress logic. Without that override,
160 // it's no longer possible to test both chrome os + desktop flows as part of the
161 // same test, because AuthInProgress is always false on chrome os. Most of the
162 // tests are unaffected, but STATUS_CASE_AUTHENTICATING can't exist in both
163 // versions, so it we will require two separate tests, one using SigninManager
164 // and one using SigninManagerBase (which require different setup procedures.
165 class FakeSigninManagerForSyncUIUtilTest
: public FakeSigninManagerBase
{
167 explicit FakeSigninManagerForSyncUIUtilTest(Profile
* profile
)
168 : auth_in_progress_(false) {
169 Initialize(profile
, NULL
);
172 virtual ~FakeSigninManagerForSyncUIUtilTest() {
175 virtual bool AuthInProgress() const OVERRIDE
{
176 return auth_in_progress_
;
179 void set_auth_in_progress() {
180 auth_in_progress_
= true;
184 bool auth_in_progress_
;
187 // Loads a ProfileSyncServiceMock to emulate one of a number of distinct cases
188 // in order to perform tests on the generated messages.
189 void GetDistinctCase(ProfileSyncServiceMock
& service
,
190 FakeSigninManagerForSyncUIUtilTest
* signin
,
191 FakeAuthStatusProvider
* provider
,
193 // Auth Error object is returned by reference in mock and needs to stay in
194 // scope throughout test, so it is owned by calling method. However it is
195 // immutable so can only be allocated in this method.
196 switch (caseNumber
) {
197 case STATUS_CASE_SETUP_IN_PROGRESS
: {
198 EXPECT_CALL(service
, HasSyncSetupCompleted())
199 .WillRepeatedly(Return(false));
200 EXPECT_CALL(service
, FirstSetupInProgress())
201 .WillRepeatedly(Return(true));
202 browser_sync::SyncBackendHost::Status status
;
203 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
204 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
208 case STATUS_CASE_SETUP_ERROR
: {
209 EXPECT_CALL(service
, HasSyncSetupCompleted())
210 .WillRepeatedly(Return(false));
211 EXPECT_CALL(service
, FirstSetupInProgress())
212 .WillRepeatedly(Return(false));
213 EXPECT_CALL(service
, HasUnrecoverableError())
214 .WillRepeatedly(Return(true));
215 browser_sync::SyncBackendHost::Status status
;
216 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
217 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
221 case STATUS_CASE_AUTHENTICATING
: {
222 EXPECT_CALL(service
, HasSyncSetupCompleted())
223 .WillRepeatedly(Return(true));
224 EXPECT_CALL(service
, sync_initialized()).WillRepeatedly(Return(true));
225 EXPECT_CALL(service
, IsPassphraseRequired())
226 .WillRepeatedly(Return(false));
227 browser_sync::SyncBackendHost::Status status
;
228 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
229 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
231 EXPECT_CALL(service
, HasUnrecoverableError())
232 .WillRepeatedly(Return(false));
233 signin
->set_auth_in_progress();
236 case STATUS_CASE_AUTH_ERROR
: {
237 EXPECT_CALL(service
, HasSyncSetupCompleted())
238 .WillRepeatedly(Return(true));
239 EXPECT_CALL(service
, sync_initialized()).WillRepeatedly(Return(true));
240 EXPECT_CALL(service
, IsPassphraseRequired())
241 .WillRepeatedly(Return(false));
242 browser_sync::SyncBackendHost::Status status
;
243 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
244 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
246 provider
->SetAuthError(
248 GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE
));
249 EXPECT_CALL(service
, HasUnrecoverableError())
250 .WillRepeatedly(Return(false));
253 case STATUS_CASE_PROTOCOL_ERROR
: {
254 EXPECT_CALL(service
, HasSyncSetupCompleted())
255 .WillRepeatedly(Return(true));
256 EXPECT_CALL(service
, sync_initialized()).WillRepeatedly(Return(true));
257 EXPECT_CALL(service
, IsPassphraseRequired())
258 .WillRepeatedly(Return(false));
259 syncer::SyncProtocolError protocolError
;
260 protocolError
.action
= syncer::STOP_AND_RESTART_SYNC
;
261 browser_sync::SyncBackendHost::Status status
;
262 status
.sync_protocol_error
= protocolError
;
263 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
264 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
266 EXPECT_CALL(service
, HasUnrecoverableError())
267 .WillRepeatedly(Return(false));
270 case STATUS_CASE_PASSPHRASE_ERROR
: {
271 EXPECT_CALL(service
, HasSyncSetupCompleted())
272 .WillRepeatedly(Return(true));
273 EXPECT_CALL(service
, sync_initialized()).WillRepeatedly(Return(true));
274 browser_sync::SyncBackendHost::Status status
;
275 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
276 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
278 EXPECT_CALL(service
, HasUnrecoverableError())
279 .WillRepeatedly(Return(false));
280 EXPECT_CALL(service
, IsPassphraseRequired())
281 .WillRepeatedly(Return(true));
282 EXPECT_CALL(service
, IsPassphraseRequiredForDecryption())
283 .WillRepeatedly(Return(true));
286 case STATUS_CASE_SYNCED
: {
287 EXPECT_CALL(service
, HasSyncSetupCompleted())
288 .WillRepeatedly(Return(true));
289 EXPECT_CALL(service
, sync_initialized()).WillRepeatedly(Return(true));
290 EXPECT_CALL(service
, IsPassphraseRequired())
291 .WillRepeatedly(Return(false));
292 browser_sync::SyncBackendHost::Status status
;
293 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
294 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
296 EXPECT_CALL(service
, HasUnrecoverableError())
297 .WillRepeatedly(Return(false));
298 EXPECT_CALL(service
, IsPassphraseRequired())
299 .WillRepeatedly(Return(false));
302 case STATUS_CASE_SYNC_DISABLED_BY_POLICY
: {
303 EXPECT_CALL(service
, IsManaged()).WillRepeatedly(Return(true));
304 EXPECT_CALL(service
, HasSyncSetupCompleted())
305 .WillRepeatedly(Return(false));
306 EXPECT_CALL(service
, sync_initialized()).WillRepeatedly(Return(false));
307 EXPECT_CALL(service
, IsPassphraseRequired())
308 .WillRepeatedly(Return(false));
309 browser_sync::SyncBackendHost::Status status
;
310 EXPECT_CALL(service
, QueryDetailedSyncStatus(_
))
311 .WillRepeatedly(DoAll(SetArgPointee
<0>(status
),
313 EXPECT_CALL(service
, HasUnrecoverableError())
314 .WillRepeatedly(Return(false));
322 // This test ensures that a each distinctive ProfileSyncService statuses
323 // will return a unique combination of status and link messages from
324 // GetStatusLabels().
325 TEST_F(SyncUIUtilTest
, DistinctCasesReportUniqueMessageSets
) {
326 std::set
<base::string16
> messages
;
327 for (int idx
= 0; idx
!= NUMBER_OF_STATUS_CASES
; idx
++) {
328 scoped_ptr
<Profile
> profile(new TestingProfile());
329 ProfileSyncServiceMock
service(profile
.get());
330 GoogleServiceAuthError error
= GoogleServiceAuthError::AuthErrorNone();
331 EXPECT_CALL(service
, GetAuthError()).WillRepeatedly(ReturnRef(error
));
332 FakeSigninManagerForSyncUIUtilTest
signin(profile
.get());
333 signin
.SetAuthenticatedUsername(kTestUser
);
334 scoped_ptr
<FakeAuthStatusProvider
> provider(
335 new FakeAuthStatusProvider(
336 SigninGlobalError::GetForProfile(profile
.get())));
337 GetDistinctCase(service
, &signin
, provider
.get(), idx
);
338 base::string16 status_label
;
339 base::string16 link_label
;
340 sync_ui_util::GetStatusLabels(&service
,
342 sync_ui_util::WITH_HTML
,
345 // If the status and link message combination is already present in the set
346 // of messages already seen, this is a duplicate rather than a unique
347 // message, and the test has failed.
348 EXPECT_FALSE(status_label
.empty()) <<
349 "Empty status label returned for case #" << idx
;
350 base::string16 combined_label
=
351 status_label
+ base::ASCIIToUTF16("#") + link_label
;
352 EXPECT_TRUE(messages
.find(combined_label
) == messages
.end()) <<
353 "Duplicate message for case #" << idx
<< ": " << combined_label
;
354 messages
.insert(combined_label
);
355 testing::Mock::VerifyAndClearExpectations(&service
);
356 testing::Mock::VerifyAndClearExpectations(&signin
);
357 EXPECT_CALL(service
, GetAuthError()).WillRepeatedly(ReturnRef(error
));
363 // This test ensures that the html_links parameter on GetStatusLabels() is
365 TEST_F(SyncUIUtilTest
, HtmlNotIncludedInStatusIfNotRequested
) {
366 for (int idx
= 0; idx
!= NUMBER_OF_STATUS_CASES
; idx
++) {
367 scoped_ptr
<Profile
> profile(
368 ProfileSyncServiceMock::MakeSignedInTestingProfile());
369 ProfileSyncServiceMock
service(profile
.get());
370 GoogleServiceAuthError error
= GoogleServiceAuthError::AuthErrorNone();
371 EXPECT_CALL(service
, GetAuthError()).WillRepeatedly(ReturnRef(error
));
372 FakeSigninManagerForSyncUIUtilTest
signin(profile
.get());
373 signin
.SetAuthenticatedUsername(kTestUser
);
374 scoped_ptr
<FakeAuthStatusProvider
> provider(
375 new FakeAuthStatusProvider(
376 SigninGlobalError::GetForProfile(profile
.get())));
377 GetDistinctCase(service
, &signin
, provider
.get(), idx
);
378 base::string16 status_label
;
379 base::string16 link_label
;
380 sync_ui_util::GetStatusLabels(&service
,
382 sync_ui_util::PLAIN_TEXT
,
386 // Ensures a search for string 'href' (found in links, not a string to be
387 // found in an English language message) fails when links are excluded from
389 EXPECT_FALSE(status_label
.empty());
390 EXPECT_EQ(status_label
.find(base::ASCIIToUTF16("href")),
391 base::string16::npos
);
392 testing::Mock::VerifyAndClearExpectations(&service
);
393 testing::Mock::VerifyAndClearExpectations(&signin
);
394 EXPECT_CALL(service
, GetAuthError()).WillRepeatedly(ReturnRef(error
));