1 // Copyright 2014 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 "chrome/browser/sync/sync_error_notifier_ash.h"
7 #include "ash/test/ash_test_base.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/notifications/notification.h"
11 #include "chrome/browser/notifications/notification_ui_manager.h"
12 #include "chrome/browser/sync/profile_sync_service_mock.h"
13 #include "chrome/browser/sync/sync_error_controller.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
16 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
17 #include "chrome/test/base/testing_browser_process.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "chrome/test/base/testing_profile_manager.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "ui/message_center/notification.h"
25 #include "chrome/browser/ui/ash/ash_util.h"
26 #include "ui/aura/test/test_screen.h"
27 #include "ui/gfx/screen.h"
28 #include "ui/gfx/screen_type_delegate.h"
31 using ::testing::NiceMock
;
32 using ::testing::Return
;
33 using ::testing::ReturnRef
;
41 static const char kTestAccountId
[] = "testuser@test.com";
43 // Notification ID corresponding to kProfileSyncNotificationId + kTestAccountId.
44 static const std::string kNotificationId
=
45 "chrome://settings/sync/testuser@test.com";
48 class ScreenTypeDelegateDesktop
: public gfx::ScreenTypeDelegate
{
50 ScreenTypeDelegateDesktop() {}
51 virtual ~ScreenTypeDelegateDesktop() {}
52 virtual gfx::ScreenType
GetScreenTypeForNativeView(
53 gfx::NativeView view
) override
{
54 return chrome::IsNativeViewInAsh(view
) ?
55 gfx::SCREEN_TYPE_ALTERNATE
:
56 gfx::SCREEN_TYPE_NATIVE
;
60 DISALLOW_COPY_AND_ASSIGN(ScreenTypeDelegateDesktop
);
64 class FakeLoginUIService
: public LoginUIService
{
66 FakeLoginUIService() : LoginUIService(NULL
) {}
67 ~FakeLoginUIService() override
{}
70 class FakeLoginUI
: public LoginUIService::LoginUI
{
72 FakeLoginUI() : focus_ui_call_count_(0) {}
74 ~FakeLoginUI() override
{}
76 int focus_ui_call_count() const { return focus_ui_call_count_
; }
79 // LoginUIService::LoginUI:
80 void FocusUI() override
{ ++focus_ui_call_count_
; }
81 void CloseUI() override
{}
83 int focus_ui_call_count_
;
86 KeyedService
* BuildMockLoginUIService(
87 content::BrowserContext
* profile
) {
88 return new FakeLoginUIService();
91 class SyncErrorNotifierTest
: public AshTestBase
{
93 SyncErrorNotifierTest() {}
94 ~SyncErrorNotifierTest() override
{}
96 void SetUp() override
{
97 profile_manager_
.reset(
98 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
99 ASSERT_TRUE(profile_manager_
->SetUp());
101 profile_
= profile_manager_
->CreateTestingProfile(kTestAccountId
);
103 TestingBrowserProcess::GetGlobal();
104 AshTestBase::SetUp();
106 // Set up a desktop screen for Windows to hold native widgets, used when
107 // adding desktop widgets (i.e., message center notifications).
109 test_screen_
.reset(aura::TestScreen::Create(gfx::Size()));
110 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
, test_screen_
.get());
111 gfx::Screen::SetScreenTypeDelegate(&screen_type_delegate_
);
114 service_
.reset(new NiceMock
<ProfileSyncServiceMock
>(profile_
));
116 FakeLoginUIService
* login_ui_service
= static_cast<FakeLoginUIService
*>(
117 LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse(
118 profile_
, BuildMockLoginUIService
));
119 login_ui_service
->SetLoginUI(&login_ui_
);
121 error_controller_
.reset(new SyncErrorController(service_
.get()));
122 error_notifier_
.reset(new SyncErrorNotifier(error_controller_
.get(),
125 notification_ui_manager_
= g_browser_process
->notification_ui_manager();
128 void TearDown() override
{
129 error_notifier_
->Shutdown();
132 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
, nullptr);
133 gfx::Screen::SetScreenTypeDelegate(nullptr);
134 test_screen_
.reset();
136 profile_manager_
.reset();
138 AshTestBase::TearDown();
142 // Utility function to test that SyncErrorNotifier behaves correctly for the
143 // given error condition.
144 void VerifySyncErrorNotifierResult(GoogleServiceAuthError::State error_state
,
147 EXPECT_CALL(*service_
, HasSyncSetupCompleted())
148 .WillRepeatedly(Return(is_signed_in
));
150 GoogleServiceAuthError
auth_error(error_state
);
151 EXPECT_CALL(*service_
, GetAuthError()).WillRepeatedly(
152 ReturnRef(auth_error
));
154 error_controller_
->OnStateChanged();
155 EXPECT_EQ(is_error
, error_controller_
->HasError());
157 // If there is an error we should see a notification.
158 const Notification
* notification
= notification_ui_manager_
->FindById(
159 kNotificationId
, NotificationUIManager::GetProfileID(profile_
));
161 ASSERT_TRUE(notification
);
162 ASSERT_FALSE(notification
->title().empty());
163 ASSERT_FALSE(notification
->title().empty());
164 ASSERT_EQ((size_t)1, notification
->buttons().size());
166 ASSERT_FALSE(notification
);
171 ScreenTypeDelegateDesktop screen_type_delegate_
;
172 scoped_ptr
<gfx::Screen
> test_screen_
;
174 scoped_ptr
<TestingProfileManager
> profile_manager_
;
175 scoped_ptr
<SyncErrorController
> error_controller_
;
176 scoped_ptr
<SyncErrorNotifier
> error_notifier_
;
177 scoped_ptr
<NiceMock
<ProfileSyncServiceMock
> > service_
;
178 TestingProfile
* profile_
;
179 FakeLoginUI login_ui_
;
180 NotificationUIManager
* notification_ui_manager_
;
182 DISALLOW_COPY_AND_ASSIGN(SyncErrorNotifierTest
);
187 // Test that SyncErrorNotifier shows an notification if a passphrase is
189 // Disabled on Windows: http://crbug.com/373238
191 #define MAYBE_PassphraseNotification DISABLED_PassphraseNotification
193 #define MAYBE_PassphraseNotification PassphraseNotification
195 TEST_F(SyncErrorNotifierTest
, MAYBE_PassphraseNotification
) {
196 ASSERT_FALSE(notification_ui_manager_
->FindById(
197 kNotificationId
, NotificationUIManager::GetProfileID(profile_
)));
199 browser_sync::SyncBackendHost::Status status
;
200 EXPECT_CALL(*service_
, QueryDetailedSyncStatus(_
))
201 .WillRepeatedly(Return(false));
203 EXPECT_CALL(*service_
, IsPassphraseRequired())
204 .WillRepeatedly(Return(true));
205 EXPECT_CALL(*service_
, IsPassphraseRequiredForDecryption())
206 .WillRepeatedly(Return(true));
208 SCOPED_TRACE("Expected a notification for passphrase error");
209 VerifySyncErrorNotifierResult(GoogleServiceAuthError::NONE
,
210 true /* signed in */,
214 // Check that no notification is shown if there is no error.
215 EXPECT_CALL(*service_
, IsPassphraseRequired())
216 .WillRepeatedly(Return(false));
217 EXPECT_CALL(*service_
, IsPassphraseRequiredForDecryption())
218 .WillRepeatedly(Return(false));
220 SCOPED_TRACE("Not expecting notification since no error exists");
221 VerifySyncErrorNotifierResult(GoogleServiceAuthError::NONE
,
222 true /* signed in */,
223 false /* no error */);
226 // Check that no notification is shown if sync setup is not completed.
227 EXPECT_CALL(*service_
, IsPassphraseRequired())
228 .WillRepeatedly(Return(true));
229 EXPECT_CALL(*service_
, IsPassphraseRequiredForDecryption())
230 .WillRepeatedly(Return(true));
232 SCOPED_TRACE("Not expecting notification since sync setup is incomplete");
233 VerifySyncErrorNotifierResult(
234 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
,
235 false /* not signed in */,
236 false /* no error */);