Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync / sync_ui_util_unittest.cc
blob7728606ea56a1d52a5c7c63b39df855f3ed7a46e
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/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;
27 using ::testing::_;
28 using content::BrowserThread;
30 // A number of distinct states of the ProfileSyncService can be generated for
31 // tests.
32 enum DistinctState {
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,
39 STATUS_CASE_SYNCED,
40 STATUS_CASE_SYNC_DISABLED_BY_POLICY,
41 NUMBER_OF_STATUS_CASES
44 namespace {
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,
53 bool is_signed_in,
54 bool is_error) {
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);
69 } // namespace
72 class SyncUIUtilTest : public testing::Test {
73 private:
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 {
166 public:
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;
183 private:
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,
192 int caseNumber) {
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),
205 Return(false)));
206 return;
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),
218 Return(false)));
219 return;
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),
230 Return(false)));
231 EXPECT_CALL(service, HasUnrecoverableError())
232 .WillRepeatedly(Return(false));
233 signin->set_auth_in_progress();
234 return;
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),
245 Return(false)));
246 provider->SetAuthError(
247 kTestUser,
248 GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
249 EXPECT_CALL(service, HasUnrecoverableError())
250 .WillRepeatedly(Return(false));
251 return;
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),
265 Return(false)));
266 EXPECT_CALL(service, HasUnrecoverableError())
267 .WillRepeatedly(Return(false));
268 return;
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),
277 Return(false)));
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));
284 return;
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),
295 Return(false)));
296 EXPECT_CALL(service, HasUnrecoverableError())
297 .WillRepeatedly(Return(false));
298 EXPECT_CALL(service, IsPassphraseRequired())
299 .WillRepeatedly(Return(false));
300 return;
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),
312 Return(false)));
313 EXPECT_CALL(service, HasUnrecoverableError())
314 .WillRepeatedly(Return(false));
315 return;
317 default:
318 NOTREACHED();
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,
341 signin,
342 sync_ui_util::WITH_HTML,
343 &status_label,
344 &link_label);
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));
358 provider.reset();
359 signin.Shutdown();
363 // This test ensures that the html_links parameter on GetStatusLabels() is
364 // honored.
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,
381 signin,
382 sync_ui_util::PLAIN_TEXT,
383 &status_label,
384 &link_label);
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
388 // the status label.
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));
395 provider.reset();
396 signin.Shutdown();