Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / sync_ui_util_unittest.cc
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 <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_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 "components/signin/core/browser/fake_auth_status_provider.h"
14 #include "components/signin/core/browser/profile_oauth2_token_service.h"
15 #include "components/signin/core/browser/signin_manager.h"
16 #include "content/public/test/test_browser_thread.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "grit/generated_resources.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"
23
24 using ::testing::AtMost;
25 using ::testing::NiceMock;
26 using ::testing::Return;
27 using ::testing::ReturnRef;
28 using ::testing::SetArgPointee;
29 using ::testing::_;
30 using content::BrowserThread;
31
32 // A number of distinct states of the ProfileSyncService can be generated for
33 // tests.
34 enum DistinctState {
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,
41   STATUS_CASE_SYNCED,
42   STATUS_CASE_SYNC_DISABLED_BY_POLICY,
43   NUMBER_OF_STATUS_CASES
44 };
45
46 namespace {
47
48 const char kTestUser[] = "test_user@test.com";
49
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,
55                                  bool is_signed_in,
56                                  bool is_error) {
57   EXPECT_CALL(*service, HasSyncSetupCompleted())
58               .WillRepeatedly(Return(is_signed_in));
59
60   GoogleServiceAuthError auth_error(error_state);
61   EXPECT_CALL(*service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error));
62
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);
69 }
70 #endif
71
72 } // namespace
73
74
75 class SyncUIUtilTest : public testing::Test {
76  private:
77   content::TestBrowserThreadBundle thread_bundle_;
78 };
79
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));
94
95   VerifySyncGlobalErrorResult(&service,
96                               GoogleServiceAuthError::NONE,
97                               true /* signed in */,
98                               true /* error */);
99 }
100
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));
110
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));
117
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));
128 }
129
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());
136
137   browser_sync::SyncBackendHost::Status status;
138   EXPECT_CALL(service, QueryDetailedSyncStatus(_))
139               .WillRepeatedly(Return(false));
140
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
153   };
154
155   FakeSigninManagerBase signin(profile.get());
156   for (size_t i = 0; i < arraysize(table); ++i) {
157     VerifySyncGlobalErrorResult(&service,
158                                 table[i],
159                                 true /* signed in */,
160                                 false /* no error */);
161     VerifySyncGlobalErrorResult(&service,
162                                 table[i],
163                                 false /* not signed in */,
164                                 false /* no error */);
165   }
166 }
167 #endif
168
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 {
178  public:
179   explicit FakeSigninManagerForSyncUIUtilTest(Profile* profile)
180       : FakeSigninManagerBase(profile), auth_in_progress_(false) {
181     Initialize(NULL);
182   }
183
184   virtual ~FakeSigninManagerForSyncUIUtilTest() {
185   }
186
187   virtual bool AuthInProgress() const OVERRIDE {
188     return auth_in_progress_;
189   }
190
191   void set_auth_in_progress() {
192     auth_in_progress_ = true;
193   }
194
195  private:
196   bool auth_in_progress_;
197 };
198
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,
204                      int caseNumber) {
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),
217                                   Return(false)));
218       return;
219     }
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),
230                                   Return(false)));
231       return;
232     }
233     case STATUS_CASE_AUTHENTICATING: {
234       EXPECT_CALL(service, HasSyncSetupCompleted())
235                   .WillRepeatedly(Return(true));
236       EXPECT_CALL(service, sync_initialized()).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),
242                                   Return(false)));
243       EXPECT_CALL(service, HasUnrecoverableError())
244                   .WillRepeatedly(Return(false));
245       signin->set_auth_in_progress();
246       return;
247     }
248     case STATUS_CASE_AUTH_ERROR: {
249       EXPECT_CALL(service, HasSyncSetupCompleted())
250                   .WillRepeatedly(Return(true));
251       EXPECT_CALL(service, sync_initialized()).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),
257                                   Return(false)));
258       provider->SetAuthError(
259           kTestUser,
260           GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
261       EXPECT_CALL(service, HasUnrecoverableError())
262                   .WillRepeatedly(Return(false));
263       return;
264     }
265     case STATUS_CASE_PROTOCOL_ERROR: {
266       EXPECT_CALL(service, HasSyncSetupCompleted())
267                   .WillRepeatedly(Return(true));
268       EXPECT_CALL(service, sync_initialized()).WillRepeatedly(Return(true));
269       EXPECT_CALL(service, IsPassphraseRequired())
270                   .WillRepeatedly(Return(false));
271       syncer::SyncProtocolError protocolError;
272       protocolError.action = syncer::STOP_AND_RESTART_SYNC;
273       browser_sync::SyncBackendHost::Status status;
274       status.sync_protocol_error = protocolError;
275       EXPECT_CALL(service, QueryDetailedSyncStatus(_))
276                   .WillRepeatedly(DoAll(SetArgPointee<0>(status),
277                                   Return(false)));
278       EXPECT_CALL(service, HasUnrecoverableError())
279                   .WillRepeatedly(Return(false));
280       return;
281     }
282     case STATUS_CASE_PASSPHRASE_ERROR: {
283       EXPECT_CALL(service, HasSyncSetupCompleted())
284                   .WillRepeatedly(Return(true));
285       EXPECT_CALL(service, sync_initialized()).WillRepeatedly(Return(true));
286       browser_sync::SyncBackendHost::Status status;
287       EXPECT_CALL(service, QueryDetailedSyncStatus(_))
288                   .WillRepeatedly(DoAll(SetArgPointee<0>(status),
289                                   Return(false)));
290       EXPECT_CALL(service, HasUnrecoverableError())
291                   .WillRepeatedly(Return(false));
292       EXPECT_CALL(service, IsPassphraseRequired())
293                   .WillRepeatedly(Return(true));
294       EXPECT_CALL(service, IsPassphraseRequiredForDecryption())
295                   .WillRepeatedly(Return(true));
296       return;
297     }
298     case STATUS_CASE_SYNCED: {
299       EXPECT_CALL(service, HasSyncSetupCompleted())
300               .WillRepeatedly(Return(true));
301       EXPECT_CALL(service, sync_initialized()).WillRepeatedly(Return(true));
302       EXPECT_CALL(service, IsPassphraseRequired())
303                   .WillRepeatedly(Return(false));
304       browser_sync::SyncBackendHost::Status status;
305       EXPECT_CALL(service, QueryDetailedSyncStatus(_))
306                   .WillRepeatedly(DoAll(SetArgPointee<0>(status),
307                                   Return(false)));
308       EXPECT_CALL(service, HasUnrecoverableError())
309                   .WillRepeatedly(Return(false));
310       EXPECT_CALL(service, IsPassphraseRequired())
311                   .WillRepeatedly(Return(false));
312       return;
313     }
314     case STATUS_CASE_SYNC_DISABLED_BY_POLICY: {
315       EXPECT_CALL(service, IsManaged()).WillRepeatedly(Return(true));
316       EXPECT_CALL(service, HasSyncSetupCompleted())
317           .WillRepeatedly(Return(false));
318       EXPECT_CALL(service, sync_initialized()).WillRepeatedly(Return(false));
319       EXPECT_CALL(service, IsPassphraseRequired())
320                   .WillRepeatedly(Return(false));
321       browser_sync::SyncBackendHost::Status status;
322       EXPECT_CALL(service, QueryDetailedSyncStatus(_))
323                   .WillRepeatedly(DoAll(SetArgPointee<0>(status),
324                                   Return(false)));
325       EXPECT_CALL(service, HasUnrecoverableError())
326                   .WillRepeatedly(Return(false));
327       return;
328     }
329     default:
330       NOTREACHED();
331   }
332 }
333
334 // This test ensures that a each distinctive ProfileSyncService statuses
335 // will return a unique combination of status and link messages from
336 // GetStatusLabels().
337 TEST_F(SyncUIUtilTest, DistinctCasesReportUniqueMessageSets) {
338   std::set<base::string16> messages;
339   for (int idx = 0; idx != NUMBER_OF_STATUS_CASES; idx++) {
340     scoped_ptr<Profile> profile(new TestingProfile());
341     ProfileSyncServiceMock service(profile.get());
342     GoogleServiceAuthError error = GoogleServiceAuthError::AuthErrorNone();
343     EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
344     FakeSigninManagerForSyncUIUtilTest signin(profile.get());
345     signin.SetAuthenticatedUsername(kTestUser);
346     scoped_ptr<FakeAuthStatusProvider> provider(new FakeAuthStatusProvider(
347         ProfileOAuth2TokenServiceFactory::GetForProfile(profile.get())->
348             signin_error_controller()));
349     GetDistinctCase(service, &signin, provider.get(), idx);
350     base::string16 status_label;
351     base::string16 link_label;
352     sync_ui_util::GetStatusLabels(&service,
353                                   signin,
354                                   sync_ui_util::WITH_HTML,
355                                   &status_label,
356                                   &link_label);
357     // If the status and link message combination is already present in the set
358     // of messages already seen, this is a duplicate rather than a unique
359     // message, and the test has failed.
360     EXPECT_FALSE(status_label.empty()) <<
361         "Empty status label returned for case #" << idx;
362     base::string16 combined_label =
363         status_label + base::ASCIIToUTF16("#") + link_label;
364     EXPECT_TRUE(messages.find(combined_label) == messages.end()) <<
365         "Duplicate message for case #" << idx << ": " << combined_label;
366     messages.insert(combined_label);
367     testing::Mock::VerifyAndClearExpectations(&service);
368     testing::Mock::VerifyAndClearExpectations(&signin);
369     EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
370     provider.reset();
371     signin.Shutdown();
372   }
373 }
374
375 // This test ensures that the html_links parameter on GetStatusLabels() is
376 // honored.
377 TEST_F(SyncUIUtilTest, HtmlNotIncludedInStatusIfNotRequested) {
378   for (int idx = 0; idx != NUMBER_OF_STATUS_CASES; idx++) {
379     scoped_ptr<Profile> profile(
380         ProfileSyncServiceMock::MakeSignedInTestingProfile());
381     ProfileSyncServiceMock service(profile.get());
382     GoogleServiceAuthError error = GoogleServiceAuthError::AuthErrorNone();
383     EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
384     FakeSigninManagerForSyncUIUtilTest signin(profile.get());
385     signin.SetAuthenticatedUsername(kTestUser);
386     scoped_ptr<FakeAuthStatusProvider> provider(new FakeAuthStatusProvider(
387         ProfileOAuth2TokenServiceFactory::GetForProfile(profile.get())->
388             signin_error_controller()));
389     GetDistinctCase(service, &signin, provider.get(), idx);
390     base::string16 status_label;
391     base::string16 link_label;
392     sync_ui_util::GetStatusLabels(&service,
393                                   signin,
394                                   sync_ui_util::PLAIN_TEXT,
395                                   &status_label,
396                                   &link_label);
397
398     // Ensures a search for string 'href' (found in links, not a string to be
399     // found in an English language message) fails when links are excluded from
400     // the status label.
401     EXPECT_FALSE(status_label.empty());
402     EXPECT_EQ(status_label.find(base::ASCIIToUTF16("href")),
403               base::string16::npos);
404     testing::Mock::VerifyAndClearExpectations(&service);
405     testing::Mock::VerifyAndClearExpectations(&signin);
406     EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
407     provider.reset();
408     signin.Shutdown();
409   }
410 }