- add sources.
[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_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"
21
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;
29
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
42 };
43
44 namespace {
45
46 const char kTestUser[] = "test_user@test.com";
47
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));
57
58   GoogleServiceAuthError auth_error(error_state);
59   EXPECT_CALL(*service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error));
60
61   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);
67 }
68
69 } // namespace
70
71
72 class SyncUIUtilTest : public testing::Test {
73  private:
74   content::TestBrowserThreadBundle thread_bundle_;
75 };
76
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);
93 }
94
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));
105
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));
112
113   GoogleServiceAuthError auth_error(
114       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
115   EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error));
116   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));
123 }
124
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());
131
132   browser_sync::SyncBackendHost::Status status;
133   EXPECT_CALL(service, QueryDetailedSyncStatus(_))
134               .WillRepeatedly(Return(false));
135
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
148   };
149
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);
154   }
155 }
156
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);
170   }
171
172   virtual ~FakeSigninManagerForSyncUIUtilTest() {
173   }
174
175   virtual bool AuthInProgress() const OVERRIDE {
176     return auth_in_progress_;
177   }
178
179   void set_auth_in_progress() {
180     auth_in_progress_ = true;
181   }
182
183  private:
184   bool auth_in_progress_;
185 };
186
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;
207     }
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;
220     }
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;
235     }
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;
252     }
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;
269     }
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;
285     }
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;
301     }
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;
316     }
317     default:
318       NOTREACHED();
319   }
320 }
321
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<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     string16 status_label;
339     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     string16 combined_label =
351         status_label + string16(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();
360   }
361 }
362
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     string16 status_label;
379     string16 link_label;
380     sync_ui_util::GetStatusLabels(&service,
381                                   signin,
382                                   sync_ui_util::PLAIN_TEXT,
383                                   &status_label,
384                                   &link_label);
385
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(string16(ASCIIToUTF16("href"))),
391               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();
397   }
398 }