| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/sync/sync_error_notifier_ash.h" |
| |
| #include "ash/test/ash_test_base.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/notifications/notification.h" |
| #include "chrome/browser/notifications/notification_ui_manager.h" |
| #include "chrome/browser/sync/profile_sync_service_mock.h" |
| #include "chrome/browser/sync/sync_error_controller.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/webui/signin/login_ui_service.h" |
| #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/test/base/testing_browser_process.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "chrome/test/base/testing_profile_manager.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/message_center/notification.h" |
| |
| #if !defined(OS_CHROMEOS) |
| #include "chrome/browser/ui/ash/ash_util.h" |
| #include "ui/aura/test/test_screen.h" |
| #include "ui/gfx/screen.h" |
| #include "ui/gfx/screen_type_delegate.h" |
| #endif |
| |
| using ::testing::NiceMock; |
| using ::testing::Return; |
| using ::testing::ReturnRef; |
| using ::testing::_; |
| |
| namespace ash { |
| namespace test { |
| |
| namespace { |
| |
| static const char kTestAccountId[] = "testuser@test.com"; |
| |
| // Notification ID corresponding to kProfileSyncNotificationId + kTestAccountId. |
| static const std::string kNotificationId = |
| "chrome://settings/sync/testuser@test.com"; |
| |
| #if !defined(OS_CHROMEOS) |
| class ScreenTypeDelegateDesktop : public gfx::ScreenTypeDelegate { |
| public: |
| ScreenTypeDelegateDesktop() {} |
| virtual ~ScreenTypeDelegateDesktop() {} |
| virtual gfx::ScreenType GetScreenTypeForNativeView( |
| gfx::NativeView view) OVERRIDE { |
| return chrome::IsNativeViewInAsh(view) ? |
| gfx::SCREEN_TYPE_ALTERNATE : |
| gfx::SCREEN_TYPE_NATIVE; |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ScreenTypeDelegateDesktop); |
| }; |
| #endif |
| |
| class FakeLoginUIService: public LoginUIService { |
| public: |
| FakeLoginUIService() : LoginUIService(NULL) {} |
| virtual ~FakeLoginUIService() {} |
| }; |
| |
| class FakeLoginUI : public LoginUIService::LoginUI { |
| public: |
| FakeLoginUI() : focus_ui_call_count_(0) {} |
| |
| virtual ~FakeLoginUI() {} |
| |
| int focus_ui_call_count() const { return focus_ui_call_count_; } |
| |
| private: |
| // LoginUIService::LoginUI: |
| virtual void FocusUI() OVERRIDE { |
| ++focus_ui_call_count_; |
| } |
| virtual void CloseUI() OVERRIDE {} |
| |
| int focus_ui_call_count_; |
| }; |
| |
| KeyedService* BuildMockLoginUIService( |
| content::BrowserContext* profile) { |
| return new FakeLoginUIService(); |
| } |
| |
| class SyncErrorNotifierTest : public AshTestBase { |
| public: |
| SyncErrorNotifierTest() {} |
| virtual ~SyncErrorNotifierTest() {} |
| |
| virtual void SetUp() OVERRIDE { |
| profile_manager_.reset( |
| new TestingProfileManager(TestingBrowserProcess::GetGlobal())); |
| ASSERT_TRUE(profile_manager_->SetUp()); |
| |
| profile_ = profile_manager_->CreateTestingProfile(kTestAccountId); |
| |
| TestingBrowserProcess::GetGlobal(); |
| AshTestBase::SetUp(); |
| |
| // Set up a desktop screen for Windows to hold native widgets, used when |
| // adding desktop widgets (i.e., message center notifications). |
| #if defined(OS_WIN) |
| aura::TestScreen* test_screen = aura::TestScreen::Create(); |
| gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen); |
| gfx::Screen::SetScreenTypeDelegate(new ScreenTypeDelegateDesktop); |
| #endif |
| |
| service_.reset(new NiceMock<ProfileSyncServiceMock>(profile_)); |
| |
| FakeLoginUIService* login_ui_service = static_cast<FakeLoginUIService*>( |
| LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse( |
| profile_, BuildMockLoginUIService)); |
| login_ui_service->SetLoginUI(&login_ui_); |
| |
| error_controller_.reset(new SyncErrorController(service_.get())); |
| error_notifier_.reset(new SyncErrorNotifier(error_controller_.get(), |
| profile_)); |
| |
| notification_ui_manager_ = g_browser_process->notification_ui_manager(); |
| } |
| |
| virtual void TearDown() OVERRIDE { |
| error_notifier_->Shutdown(); |
| service_.reset(); |
| profile_manager_.reset(); |
| |
| AshTestBase::TearDown(); |
| } |
| |
| protected: |
| // Utility function to test that SyncErrorNotifier behaves correctly for the |
| // given error condition. |
| void VerifySyncErrorNotifierResult(GoogleServiceAuthError::State error_state, |
| bool is_signed_in, |
| bool is_error) { |
| EXPECT_CALL(*service_, HasSyncSetupCompleted()) |
| .WillRepeatedly(Return(is_signed_in)); |
| |
| GoogleServiceAuthError auth_error(error_state); |
| EXPECT_CALL(*service_, GetAuthError()).WillRepeatedly( |
| ReturnRef(auth_error)); |
| |
| error_controller_->OnStateChanged(); |
| EXPECT_EQ(is_error, error_controller_->HasError()); |
| |
| // If there is an error we should see a notification. |
| const Notification* notification = notification_ui_manager_-> |
| FindById(kNotificationId); |
| if (is_error) { |
| ASSERT_TRUE(notification); |
| ASSERT_FALSE(notification->title().empty()); |
| ASSERT_FALSE(notification->title().empty()); |
| ASSERT_EQ((size_t)1, notification->buttons().size()); |
| } else { |
| ASSERT_FALSE(notification); |
| } |
| } |
| |
| scoped_ptr<TestingProfileManager> profile_manager_; |
| scoped_ptr<SyncErrorController> error_controller_; |
| scoped_ptr<SyncErrorNotifier> error_notifier_; |
| scoped_ptr<NiceMock<ProfileSyncServiceMock> > service_; |
| TestingProfile* profile_; |
| FakeLoginUI login_ui_; |
| NotificationUIManager* notification_ui_manager_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SyncErrorNotifierTest); |
| }; |
| |
| } // namespace |
| |
| // Test that SyncErrorNotifier shows an notification if a passphrase is |
| // required. |
| // Disabled on Windows: http://crbug.com/373238 |
| #if defined(OS_WIN) |
| #define MAYBE_PassphraseNotification DISABLED_PassphraseNotification |
| #else |
| #define MAYBE_PassphraseNotification PassphraseNotification |
| #endif |
| TEST_F(SyncErrorNotifierTest, MAYBE_PassphraseNotification) { |
| ASSERT_FALSE(notification_ui_manager_->FindById(kNotificationId)); |
| |
| browser_sync::SyncBackendHost::Status status; |
| EXPECT_CALL(*service_, QueryDetailedSyncStatus(_)) |
| .WillRepeatedly(Return(false)); |
| |
| EXPECT_CALL(*service_, IsPassphraseRequired()) |
| .WillRepeatedly(Return(true)); |
| EXPECT_CALL(*service_, IsPassphraseRequiredForDecryption()) |
| .WillRepeatedly(Return(true)); |
| { |
| SCOPED_TRACE("Expected a notification for passphrase error"); |
| VerifySyncErrorNotifierResult(GoogleServiceAuthError::NONE, |
| true /* signed in */, |
| true /* error */); |
| } |
| |
| // Check that no notification is shown if there is no error. |
| EXPECT_CALL(*service_, IsPassphraseRequired()) |
| .WillRepeatedly(Return(false)); |
| EXPECT_CALL(*service_, IsPassphraseRequiredForDecryption()) |
| .WillRepeatedly(Return(false)); |
| { |
| SCOPED_TRACE("Not expecting notification since no error exists"); |
| VerifySyncErrorNotifierResult(GoogleServiceAuthError::NONE, |
| true /* signed in */, |
| false /* no error */); |
| } |
| |
| // Check that no notification is shown if sync setup is not completed. |
| EXPECT_CALL(*service_, IsPassphraseRequired()) |
| .WillRepeatedly(Return(true)); |
| EXPECT_CALL(*service_, IsPassphraseRequiredForDecryption()) |
| .WillRepeatedly(Return(true)); |
| { |
| SCOPED_TRACE("Not expecting notification since sync setup is incomplete"); |
| VerifySyncErrorNotifierResult( |
| GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, |
| false /* not signed in */, |
| false /* no error */); |
| } |
| } |
| |
| } // namespace test |
| } // namespace ash |