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 "chrome/browser/sync/sync_global_error.h"
6
7#include "chrome/browser/chrome_notification_types.h"
8#include "chrome/browser/sync/profile_sync_service_mock.h"
9#include "chrome/browser/sync/sync_error_controller.h"
10#include "chrome/browser/sync/sync_global_error_factory.h"
11#include "chrome/browser/ui/browser.h"
12#include "chrome/browser/ui/webui/signin/login_ui_service.h"
13#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
14#include "chrome/test/base/browser_with_test_window_test.h"
15#include "chrome/test/base/testing_profile.h"
16#include "content/public/browser/notification_observer.h"
17#include "content/public/browser/notification_registrar.h"
18#include "content/public/browser/notification_source.h"
19#include "testing/gmock/include/gmock/gmock.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22using ::testing::NiceMock;
23using ::testing::Return;
24using ::testing::ReturnRef;
25using ::testing::_;
26
27namespace {
28
29class FakeLoginUIService: public LoginUIService {
30 public:
31  FakeLoginUIService() : LoginUIService(NULL) {}
32};
33
34class FakeLoginUI : public LoginUIService::LoginUI {
35 public:
36  FakeLoginUI() : focus_ui_call_count_(0) {}
37
38  virtual ~FakeLoginUI() {}
39
40  int focus_ui_call_count() const { return focus_ui_call_count_; }
41
42 private:
43  // Overridden from LoginUIService::LoginUI:
44  virtual void FocusUI() OVERRIDE {
45    ++focus_ui_call_count_;
46  }
47  virtual void CloseUI() OVERRIDE {}
48
49  int focus_ui_call_count_;
50};
51
52KeyedService* BuildMockLoginUIService(content::BrowserContext* profile) {
53  return new FakeLoginUIService();
54}
55
56// Same as BrowserWithTestWindowTest, but uses MockBrowser to test calls to
57// ExecuteCommand method.
58class SyncGlobalErrorTest : public BrowserWithTestWindowTest {
59 public:
60  SyncGlobalErrorTest() {}
61  virtual ~SyncGlobalErrorTest() {}
62
63  virtual void SetUp() OVERRIDE {
64    profile_.reset(ProfileSyncServiceMock::MakeSignedInTestingProfile());
65
66    BrowserWithTestWindowTest::SetUp();
67  }
68
69  Profile* profile() { return profile_.get(); }
70
71 private:
72  scoped_ptr<TestingProfile> profile_;
73
74  DISALLOW_COPY_AND_ASSIGN(SyncGlobalErrorTest);
75};
76
77// Utility function to test that SyncGlobalError behaves correctly for the given
78// error condition.
79void VerifySyncGlobalErrorResult(NiceMock<ProfileSyncServiceMock>* service,
80                                 FakeLoginUIService* login_ui_service,
81                                 Browser* browser,
82                                 SyncErrorController* error,
83                                 SyncGlobalError* global_error,
84                                 GoogleServiceAuthError::State error_state,
85                                 bool is_signed_in,
86                                 bool is_error) {
87  EXPECT_CALL(*service, HasSyncSetupCompleted())
88              .WillRepeatedly(Return(is_signed_in));
89
90  GoogleServiceAuthError auth_error(error_state);
91  EXPECT_CALL(*service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error));
92
93  error->OnStateChanged();
94  EXPECT_EQ(is_error, error->HasError());
95
96  // If there is an error then a menu item and bubble view should be shown.
97  EXPECT_EQ(is_error, global_error->HasMenuItem());
98  EXPECT_EQ(is_error, global_error->HasBubbleView());
99
100  // If there is an error then labels should not be empty.
101  EXPECT_NE(0, global_error->MenuItemCommandID());
102  EXPECT_NE(is_error, global_error->MenuItemLabel().empty());
103  EXPECT_NE(is_error, global_error->GetBubbleViewAcceptButtonLabel().empty());
104
105  // We never have a cancel button.
106  EXPECT_TRUE(global_error->GetBubbleViewCancelButtonLabel().empty());
107  // We always return a hardcoded title.
108  EXPECT_FALSE(global_error->GetBubbleViewTitle().empty());
109
110  // Test message handler.
111  if (is_error) {
112    FakeLoginUI* login_ui = static_cast<FakeLoginUI*>(
113        login_ui_service->current_login_ui());
114    global_error->ExecuteMenuItem(browser);
115    ASSERT_GT(login_ui->focus_ui_call_count(), 0);
116    global_error->BubbleViewAcceptButtonPressed(browser);
117    global_error->BubbleViewDidClose(browser);
118  }
119}
120
121} // namespace
122
123// Test that SyncGlobalError shows an error if a passphrase is required.
124TEST_F(SyncGlobalErrorTest, PassphraseGlobalError) {
125  NiceMock<ProfileSyncServiceMock> service(profile());
126
127  FakeLoginUIService* login_ui_service = static_cast<FakeLoginUIService*>(
128      LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse(
129          profile(), BuildMockLoginUIService));
130  FakeLoginUI login_ui;
131  login_ui_service->SetLoginUI(&login_ui);
132
133  SyncErrorController error(&service);
134  SyncGlobalError global_error(&error, &service);
135
136  browser_sync::SyncBackendHost::Status status;
137  EXPECT_CALL(service, QueryDetailedSyncStatus(_))
138              .WillRepeatedly(Return(false));
139
140  EXPECT_CALL(service, IsPassphraseRequired())
141              .WillRepeatedly(Return(true));
142  EXPECT_CALL(service, IsPassphraseRequiredForDecryption())
143              .WillRepeatedly(Return(true));
144  VerifySyncGlobalErrorResult(
145      &service, login_ui_service, browser(), &error, &global_error,
146      GoogleServiceAuthError::NONE, true /* signed in*/, true /* error */);
147
148  // Check that no menu item is shown if there is no error.
149  EXPECT_CALL(service, IsPassphraseRequired())
150              .WillRepeatedly(Return(false));
151  EXPECT_CALL(service, IsPassphraseRequiredForDecryption())
152              .WillRepeatedly(Return(false));
153  VerifySyncGlobalErrorResult(
154      &service, login_ui_service, browser(), &error, &global_error,
155      GoogleServiceAuthError::NONE, true /* signed in */, false /* no error */);
156
157  // Check that no menu item is shown if sync setup is not completed.
158  EXPECT_CALL(service, IsPassphraseRequired())
159              .WillRepeatedly(Return(true));
160  EXPECT_CALL(service, IsPassphraseRequiredForDecryption())
161              .WillRepeatedly(Return(true));
162  VerifySyncGlobalErrorResult(
163      &service, login_ui_service, browser(), &error, &global_error,
164      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
165      false /* not signed in */, false /* no error */);
166
167  global_error.Shutdown();
168}
169