blob: 6d51bf14992f057b265a578e2240d161de6534d1 [file] [log] [blame]
// 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/signin/signin_error_notifier_ash.h"
#include <stddef.h>
#include <memory>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/users/mock_user_manager.h"
#include "chrome/browser/notifications/notification_display_service_tester.h"
#include "chrome/browser/signin/fake_signin_manager_builder.h"
#include "chrome/browser/signin/signin_error_controller_factory.h"
#include "chrome/browser/signin/signin_error_notifier_factory_ash.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/signin/core/browser/fake_auth_status_provider.h"
#include "components/signin/core/browser/signin_error_controller.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/message_center/public/cpp/notification.h"
namespace {
static const char kTestAccountId[] = "testing_profile";
// Notification ID corresponding to kProfileSigninNotificationId +
// kTestAccountId.
static const char kNotificationId[] =
"chrome://settings/signin/testing_profile";
class SigninErrorNotifierTest : public BrowserWithTestWindowTest {
public:
void SetUp() override {
BrowserWithTestWindowTest::SetUp();
mock_user_manager_ = new chromeos::MockUserManager();
user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
base::WrapUnique(mock_user_manager_));
error_controller_ =
SigninErrorControllerFactory::GetForProfile(GetProfile());
SigninErrorNotifierFactory::GetForProfile(GetProfile());
display_service_ =
std::make_unique<NotificationDisplayServiceTester>(profile());
}
TestingProfile::TestingFactories GetTestingFactories() override {
return {{SigninManagerFactory::GetInstance(), BuildFakeSigninManagerBase}};
}
protected:
SigninErrorController* error_controller_;
std::unique_ptr<NotificationDisplayServiceTester> display_service_;
chromeos::MockUserManager* mock_user_manager_; // Not owned.
std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
};
TEST_F(SigninErrorNotifierTest, NoErrorAuthStatusProviders) {
EXPECT_FALSE(display_service_->GetNotification(kNotificationId));
{
// Add a provider (removes itself on exiting this scope).
FakeAuthStatusProvider provider(error_controller_);
EXPECT_FALSE(display_service_->GetNotification(kNotificationId));
}
EXPECT_FALSE(display_service_->GetNotification(kNotificationId));
}
TEST_F(SigninErrorNotifierTest, ErrorAuthStatusProvider) {
{
FakeAuthStatusProvider provider(error_controller_);
EXPECT_FALSE(display_service_->GetNotification(kNotificationId));
{
FakeAuthStatusProvider error_provider(error_controller_);
error_provider.SetAuthError(
kTestAccountId,
GoogleServiceAuthError(
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
EXPECT_TRUE(display_service_->GetNotification(kNotificationId));
}
// error_provider is removed now that we've left that scope.
EXPECT_FALSE(display_service_->GetNotification(kNotificationId));
}
// All providers should be removed now.
EXPECT_FALSE(display_service_->GetNotification(kNotificationId));
}
TEST_F(SigninErrorNotifierTest, AuthStatusProviderErrorTransition) {
{
FakeAuthStatusProvider provider0(error_controller_);
FakeAuthStatusProvider provider1(error_controller_);
provider0.SetAuthError(
kTestAccountId,
GoogleServiceAuthError(
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
base::Optional<message_center::Notification> notification =
display_service_->GetNotification(kNotificationId);
ASSERT_TRUE(notification);
base::string16 message = notification->message();
EXPECT_FALSE(message.empty());
// Now set another auth error and clear the original.
provider1.SetAuthError(
kTestAccountId,
GoogleServiceAuthError(
GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE));
provider0.SetAuthError(
kTestAccountId,
GoogleServiceAuthError::AuthErrorNone());
notification = display_service_->GetNotification(kNotificationId);
ASSERT_TRUE(notification);
base::string16 new_message = notification->message();
EXPECT_FALSE(new_message.empty());
ASSERT_NE(new_message, message);
provider1.SetAuthError(
kTestAccountId, GoogleServiceAuthError::AuthErrorNone());
EXPECT_FALSE(display_service_->GetNotification(kNotificationId));
}
}
// Verify that SigninErrorNotifier ignores certain errors.
TEST_F(SigninErrorNotifierTest, AuthStatusEnumerateAllErrors) {
typedef struct {
GoogleServiceAuthError::State error_state;
bool is_error;
} ErrorTableEntry;
ErrorTableEntry table[] = {
{ GoogleServiceAuthError::NONE, false },
{ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, true },
{ GoogleServiceAuthError::USER_NOT_SIGNED_UP, true },
{ GoogleServiceAuthError::CONNECTION_FAILED, false },
{ GoogleServiceAuthError::CAPTCHA_REQUIRED, true },
{ GoogleServiceAuthError::ACCOUNT_DELETED, true },
{ GoogleServiceAuthError::ACCOUNT_DISABLED, true },
{ GoogleServiceAuthError::SERVICE_UNAVAILABLE, false },
{ GoogleServiceAuthError::TWO_FACTOR, true },
{ GoogleServiceAuthError::REQUEST_CANCELED, false },
{ GoogleServiceAuthError::HOSTED_NOT_ALLOWED_DEPRECATED, false },
{ GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE, true },
{ GoogleServiceAuthError::SERVICE_ERROR, true },
{ GoogleServiceAuthError::WEB_LOGIN_REQUIRED, true },
};
static_assert(arraysize(table) == GoogleServiceAuthError::NUM_STATES,
"table size should match number of auth error types");
for (size_t i = 0; i < arraysize(table); ++i) {
if (GoogleServiceAuthError::IsDeprecated(table[i].error_state))
continue;
FakeAuthStatusProvider provider(error_controller_);
provider.SetAuthError(kTestAccountId,
GoogleServiceAuthError(table[i].error_state));
base::Optional<message_center::Notification> notification =
display_service_->GetNotification(kNotificationId);
ASSERT_EQ(table[i].is_error, !!notification);
if (table[i].is_error) {
EXPECT_FALSE(notification->title().empty());
EXPECT_FALSE(notification->message().empty());
EXPECT_EQ((size_t)1, notification->buttons().size());
}
}
}
} // namespace