blob: a4e62392c187bf96a4ccc33897263f33f19621ba [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/test/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/public/identity_manager/identity_test_environment.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.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(); }
bool SetAdditionalQueryParams(const std::string& value) override {
return false;
}
size_t GetCallbackCount() const { return callbacks_.size(); }
void RespondToAllCallbacks(Status status,
const absl::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() : identity_env_(&test_url_loader_factory_) {
auto loader = std::make_unique<FakeOneGoogleBarLoader>();
loader_ = loader.get();
service_ = std::make_unique<OneGoogleBarService>(
identity_env_.identity_manager(), std::move(loader));
}
FakeOneGoogleBarLoader* loader() { return loader_; }
OneGoogleBarService* service() { return service_.get(); }
void SignIn() {
AccountInfo account_info =
identity_env_.MakeAccountAvailable("test@email.com");
identity_env_.SetCookieAccounts({{account_info.email, account_info.gaia}});
}
void SignOut() { identity_env_.SetCookieAccounts({}); }
private:
base::test::TaskEnvironment task_environment_;
network::TestURLLoaderFactory test_url_loader_factory_;
signin::IdentityTestEnvironment identity_env_;
// Owned by the service.
FakeOneGoogleBarLoader* loader_;
std::unique_ptr<OneGoogleBarService> service_;
};
TEST_F(OneGoogleBarServiceTest, RefreshesOnRequest) {
ASSERT_THAT(service()->one_google_bar_data(), Eq(absl::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(absl::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,
absl::nullopt);
EXPECT_THAT(service()->one_google_bar_data(), Eq(absl::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,
absl::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,
absl::nullopt);
// Cached data should be gone now.
EXPECT_THAT(service()->one_google_bar_data(), Eq(absl::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(absl::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(absl::nullopt));
service()->RemoveObserver(&observer);
}
TEST_F(OneGoogleBarServiceTest, DoesNotNotifyObserverOnSignInIfNoCachedData) {
ASSERT_THAT(service()->one_google_bar_data(), Eq(absl::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(absl::nullopt));
service()->RemoveObserver(&observer);
}
TEST_F(OneGoogleBarServiceTest, UpdatesLanguageCode) {
ASSERT_THAT(service()->one_google_bar_data(), Eq(absl::nullopt));
// Request a refresh. That should arrive at the loader.
service()->Refresh();
EXPECT_THAT(loader()->GetCallbackCount(), Eq(1u));
// Fulfill it.
OneGoogleBarData data;
data.language_code = "en-US";
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK, data);
EXPECT_THAT(service()->one_google_bar_data(), Eq(data));
EXPECT_THAT(service()->language_code(), "en-US");
// 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));
EXPECT_THAT(service()->language_code(), "en-US");
// Fulfill the second request, the language code should now be updated.
OneGoogleBarData other_data;
other_data.language_code = "en-UK";
loader()->RespondToAllCallbacks(OneGoogleBarLoader::Status::OK, other_data);
EXPECT_THAT(service()->one_google_bar_data(), Eq(other_data));
EXPECT_THAT(service()->language_code(), "en-UK");
}