blob: 7b3d502254d24616310ce0f7e0445713115fdcba [file] [log] [blame]
// Copyright 2017 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/search/one_google_bar/one_google_bar_service.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/macros.h"
#include "base/optional.h"
#include "base/test/scoped_task_environment.h"
#include "chrome/browser/search/one_google_bar/one_google_bar_data.h"
#include "chrome/browser/search/one_google_bar/one_google_bar_loader.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
#include "components/signin/core/browser/test_signin_client.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "google_apis/gaia/fake_oauth2_token_service.h"
#include "google_apis/gaia/gaia_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::Eq;
using testing::InSequence;
using testing::StrictMock;
class FakeOneGoogleBarLoader : public OneGoogleBarLoader {
public:
void Load(OneGoogleCallback callback) override {
callbacks_.push_back(std::move(callback));
}
GURL GetLoadURLForTesting() const override { return GURL(); }
size_t GetCallbackCount() const { return callbacks_.size(); }
void RespondToAllCallbacks(Status status,
const base::Optional<OneGoogleBarData>& data) {
for (OneGoogleCallback& callback : callbacks_) {
std::move(callback).Run(status, data);
}
callbacks_.clear();
}
private:
std::vector<OneGoogleCallback> callbacks_;
};
class MockOneGoogleBarServiceObserver : public OneGoogleBarServiceObserver {
public:
MOCK_METHOD0(OnOneGoogleBarDataUpdated, void());
};
class OneGoogleBarServiceTest : public testing::Test {
public:
OneGoogleBarServiceTest()
: signin_client_(&pref_service_),
cookie_service_(&token_service_,
GaiaConstants::kChromeSource,
&signin_client_) {
// GaiaCookieManagerService calls static methods of AccountTrackerService
// which access prefs.
AccountTrackerService::RegisterPrefs(pref_service_.registry());
auto loader = std::make_unique<FakeOneGoogleBarLoader>();
loader_ = loader.get();
service_ = std::make_unique<OneGoogleBarService>(&cookie_service_,
std::move(loader));
}
FakeOneGoogleBarLoader* loader() { return loader_; }
OneGoogleBarService* service() { return service_.get(); }
void SignIn() {
cookie_service_.SetListAccountsResponseOneAccount("user@gmail.com",
"gaia_id");
cookie_service_.TriggerListAccounts(GaiaConstants::kChromeSource);
task_environment_.RunUntilIdle();
}
void SignOut() {
cookie_service_.SetListAccountsResponseNoAccounts();
cookie_service_.TriggerListAccounts(GaiaConstants::kChromeSource);
task_environment_.RunUntilIdle();
}
private:
base::test::ScopedTaskEnvironment task_environment_;
sync_preferences::TestingPrefServiceSyncable pref_service_;
TestSigninClient signin_client_;
FakeOAuth2TokenService token_service_;
FakeGaiaCookieManagerService cookie_service_;
// Owned by the service.
FakeOneGoogleBarLoader* loader_;
std::unique_ptr<OneGoogleBarService> service_;
};
TEST_F(OneGoogleBarServiceTest, RefreshesOnRequest) {
ASSERT_THAT(service()->one_google_bar_data(), Eq(base::nullopt));
// Request a refresh. That should arrive at the loader.
service()->Refresh();
EXPECT_THAT(loader()->GetCallbackCount(), Eq(1u));
// Fulfill it.
OneGoogleBarData data;
data.bar_html = "<div></div>";
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK, data);
EXPECT_THAT(service()->one_google_bar_data(), Eq(data));
// Request another refresh.
service()->Refresh();
EXPECT_THAT(loader()->GetCallbackCount(), Eq(1u));
// For now, the old data should still be there.
EXPECT_THAT(service()->one_google_bar_data(), Eq(data));
// Fulfill the second request.
OneGoogleBarData other_data;
other_data.bar_html = "<div>Different!</div>";
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK, other_data);
EXPECT_THAT(service()->one_google_bar_data(), Eq(other_data));
}
TEST_F(OneGoogleBarServiceTest, NotifiesObserverOnChanges) {
InSequence s;
ASSERT_THAT(service()->one_google_bar_data(), Eq(base::nullopt));
StrictMock<MockOneGoogleBarServiceObserver> observer;
service()->AddObserver(&observer);
// Empty result from a fetch should result in a notification.
service()->Refresh();
EXPECT_CALL(observer, OnOneGoogleBarDataUpdated());
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK,
base::nullopt);
EXPECT_THAT(service()->one_google_bar_data(), Eq(base::nullopt));
// Non-empty response should result in a notification.
service()->Refresh();
OneGoogleBarData data;
data.bar_html = "<div></div>";
EXPECT_CALL(observer, OnOneGoogleBarDataUpdated());
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK, data);
EXPECT_THAT(service()->one_google_bar_data(), Eq(data));
// Identical response should still result in a notification.
service()->Refresh();
OneGoogleBarData identical_data = data;
EXPECT_CALL(observer, OnOneGoogleBarDataUpdated());
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK,
identical_data);
EXPECT_THAT(service()->one_google_bar_data(), Eq(data));
// Different response should result in a notification.
service()->Refresh();
OneGoogleBarData other_data;
data.bar_html = "<div>Different</div>";
EXPECT_CALL(observer, OnOneGoogleBarDataUpdated());
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK, other_data);
EXPECT_THAT(service()->one_google_bar_data(), Eq(other_data));
service()->RemoveObserver(&observer);
}
TEST_F(OneGoogleBarServiceTest, KeepsCacheOnTransientError) {
// Load some data.
service()->Refresh();
OneGoogleBarData data;
data.bar_html = "<div></div>";
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK, data);
ASSERT_THAT(service()->one_google_bar_data(), Eq(data));
StrictMock<MockOneGoogleBarServiceObserver> observer;
service()->AddObserver(&observer);
// Request a refresh and respond with a transient error.
service()->Refresh();
EXPECT_CALL(observer, OnOneGoogleBarDataUpdated());
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::TRANSIENT_ERROR,
base::nullopt);
// Cached data should still be there.
EXPECT_THAT(service()->one_google_bar_data(), Eq(data));
service()->RemoveObserver(&observer);
}
TEST_F(OneGoogleBarServiceTest, ClearsCacheOnFatalError) {
// Load some data.
service()->Refresh();
OneGoogleBarData data;
data.bar_html = "<div></div>";
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK, data);
ASSERT_THAT(service()->one_google_bar_data(), Eq(data));
StrictMock<MockOneGoogleBarServiceObserver> observer;
service()->AddObserver(&observer);
// Request a refresh and respond with a fatal error.
service()->Refresh();
EXPECT_CALL(observer, OnOneGoogleBarDataUpdated());
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::FATAL_ERROR,
base::nullopt);
// Cached data should be gone now.
EXPECT_THAT(service()->one_google_bar_data(), Eq(base::nullopt));
service()->RemoveObserver(&observer);
}
TEST_F(OneGoogleBarServiceTest, ResetsOnSignIn) {
// Load some data.
service()->Refresh();
OneGoogleBarData data;
data.bar_html = "<div></div>";
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK, data);
ASSERT_THAT(service()->one_google_bar_data(), Eq(data));
StrictMock<MockOneGoogleBarServiceObserver> observer;
service()->AddObserver(&observer);
// Sign in. This should clear the cached data and notify the observer.
EXPECT_CALL(observer, OnOneGoogleBarDataUpdated());
SignIn();
EXPECT_THAT(service()->one_google_bar_data(), Eq(base::nullopt));
service()->RemoveObserver(&observer);
}
TEST_F(OneGoogleBarServiceTest, ResetsOnSignOut) {
SignIn();
// Load some data.
service()->Refresh();
OneGoogleBarData data;
data.bar_html = "<div></div>";
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK, data);
ASSERT_THAT(service()->one_google_bar_data(), Eq(data));
StrictMock<MockOneGoogleBarServiceObserver> observer;
service()->AddObserver(&observer);
// Sign in. This should clear the cached data and notify the observer.
EXPECT_CALL(observer, OnOneGoogleBarDataUpdated());
SignOut();
EXPECT_THAT(service()->one_google_bar_data(), Eq(base::nullopt));
service()->RemoveObserver(&observer);
}
TEST_F(OneGoogleBarServiceTest, DoesNotNotifyObserverOnSignInIfNoCachedData) {
ASSERT_THAT(service()->one_google_bar_data(), Eq(base::nullopt));
StrictMock<MockOneGoogleBarServiceObserver> observer;
service()->AddObserver(&observer);
// Sign in. This should *not* notify the observer, since there was no cached
// data before.
SignIn();
EXPECT_THAT(service()->one_google_bar_data(), Eq(base::nullopt));
service()->RemoveObserver(&observer);
}