blob: 8735a4ee296b06cbb36b5bf20315d4c0d643156f [file] [log] [blame]
// Copyright 2020 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 "components/query_tiles/internal/tile_service_impl.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/test/bind.h"
#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/query_tiles/internal/image_prefetcher.h"
#include "components/query_tiles/test/empty_logger.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "services/network/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
using testing::_;
using ::testing::Invoke;
namespace query_tiles {
namespace {
class MockTileManager : public TileManager {
public:
MockTileManager() = default;
MOCK_METHOD(void, Init, (TileGroupStatusCallback));
MOCK_METHOD(void, GetTiles, (GetTilesCallback));
MOCK_METHOD(void, GetTile, (const std::string&, TileCallback));
MOCK_METHOD(void,
SaveTiles,
(std::unique_ptr<TileGroup>, TileGroupStatusCallback));
MOCK_METHOD(void, SetAcceptLanguagesForTesting, (const std::string&));
MOCK_METHOD(TileGroupStatus, PurgeDb, ());
MOCK_METHOD(TileGroup*, GetTileGroup, ());
MOCK_METHOD(void, OnTileClicked, (const std::string&));
MOCK_METHOD(void,
OnQuerySelected,
(const base::Optional<std::string>&, const std::u16string&));
};
class MockTileServiceScheduler : public TileServiceScheduler {
public:
MockTileServiceScheduler() = default;
MOCK_METHOD(void, OnFetchStarted, ());
MOCK_METHOD(void, OnFetchCompleted, (TileInfoRequestStatus));
MOCK_METHOD(void, OnTileManagerInitialized, (TileGroupStatus));
MOCK_METHOD(void, CancelTask, ());
MOCK_METHOD(void, OnDbPurged, (TileGroupStatus));
MOCK_METHOD(void, OnGroupDataSaved, (TileGroupStatus));
MOCK_METHOD(void, SetDelegate, (TileServiceScheduler::Delegate*));
};
class MockImagePrefetcher : public ImagePrefetcher {
public:
MockImagePrefetcher() = default;
~MockImagePrefetcher() override = default;
MOCK_METHOD(void, Prefetch, (TileGroup, bool, base::OnceClosure), (override));
};
} // namespace
class TileServiceImplTest : public testing::Test {
public:
TileServiceImplTest()
: test_shared_url_loader_factory_(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_)) {}
~TileServiceImplTest() override = default;
void SetUp() override {
auto tile_manager = std::make_unique<MockTileManager>();
tile_manager_ = tile_manager.get();
auto image_prefetcher = std::make_unique<MockImagePrefetcher>();
auto scheduler = std::make_unique<MockTileServiceScheduler>();
scheduler_ = scheduler.get();
image_prefetcher_ = image_prefetcher.get();
ON_CALL(*image_prefetcher_, Prefetch(_, _, _))
.WillByDefault(Invoke([](TileGroup, bool, base::OnceClosure callback) {
std::move(callback).Run();
}));
auto tile_fetcher =
TileFetcher::Create(GURL("https://www.test.com"), "US", "en", "apikey",
"", "", test_shared_url_loader_factory_);
test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
[&](const network::ResourceRequest& request) {
EXPECT_TRUE(request.url.is_valid() && !request.url.is_empty());
last_resource_request_ = request;
}));
auto logger = std::make_unique<test::EmptyLogger>();
tile_service_impl_ = std::make_unique<TileServiceImpl>(
std::move(image_prefetcher), std::move(tile_manager),
std::move(scheduler), std::move(tile_fetcher), &clock_,
std::move(logger));
}
void Initialize(bool expected_result) {
base::RunLoop loop;
tile_service_impl_->Initialize(base::BindOnce(
&TileServiceImplTest::OnInitialized, base::Unretained(this),
loop.QuitClosure(), expected_result));
loop.Run();
}
void OnInitialized(base::RepeatingClosure closure,
bool expected_result,
bool success) {
EXPECT_EQ(expected_result, success);
std::move(closure).Run();
}
void OnGetTileDone(const std::string& expected_id,
base::Optional<Tile> actual_tile) {
EXPECT_EQ(expected_id, actual_tile->id);
}
void OnGetTilesDone(size_t expected_size, std::vector<Tile> tiles) {
EXPECT_EQ(expected_size, tiles.size());
}
void FetchForTilesSuceeded() {
EXPECT_CALL(*scheduler(),
OnFetchCompleted(TileInfoRequestStatus::kSuccess));
tile_service_impl_->StartFetchForTiles(
false, base::BindOnce(&TileServiceImplTest::OnFetchCompleted,
base::Unretained(this)));
test_url_loader_factory_.SimulateResponseForPendingRequest(
last_resource_request_.url.spec(), "", net::HTTP_OK,
network::TestURLLoaderFactory::kMostRecentMatch);
task_environment_.RunUntilIdle();
}
void FetchForTilesWithError() {
EXPECT_CALL(*scheduler(),
OnFetchCompleted(TileInfoRequestStatus::kShouldSuspend));
tile_service_impl_->StartFetchForTiles(
false, base::BindOnce(&TileServiceImplTest::OnFetchCompleted,
base::Unretained(this)));
test_url_loader_factory_.SimulateResponseForPendingRequest(
last_resource_request_.url, network::URLLoaderCompletionStatus(net::OK),
network::CreateURLResponseHead(net::HTTP_FORBIDDEN), std::string(),
network::TestURLLoaderFactory::kMostRecentMatch);
task_environment_.RunUntilIdle();
}
void OnFetchCompleted(bool reschedule) {
// Once fetch completes, no reschedule should happen.
EXPECT_FALSE(reschedule);
}
MockTileServiceScheduler* scheduler() { return scheduler_; }
MockTileManager* tile_manager() { return tile_manager_; }
MockImagePrefetcher* image_prefetcher() { return image_prefetcher_; }
TileService* query_tiles_service() { return tile_service_impl_.get(); }
private:
base::test::TaskEnvironment task_environment_;
base::SimpleTestClock clock_;
std::unique_ptr<TileServiceImpl> tile_service_impl_;
MockTileServiceScheduler* scheduler_;
MockTileManager* tile_manager_;
MockImagePrefetcher* image_prefetcher_;
network::TestURLLoaderFactory test_url_loader_factory_;
scoped_refptr<network::SharedURLLoaderFactory>
test_shared_url_loader_factory_;
network::ResourceRequest last_resource_request_;
};
// Tests that TileManager and TileServiceImpl both initialize successfully.
TEST_F(TileServiceImplTest, ManagerInitSucceeded) {
EXPECT_CALL(*tile_manager(), Init(_))
.WillOnce(Invoke([](base::OnceCallback<void(TileGroupStatus)> callback) {
std::move(callback).Run(TileGroupStatus::kSuccess);
}));
Initialize(true);
}
// Tests that TileManager and TileServiceImpl both initialize successfully with
// no tiles.
TEST_F(TileServiceImplTest, ManagerInitSucceededWithNoTiles) {
EXPECT_CALL(*scheduler(),
OnTileManagerInitialized(TileGroupStatus::kNoTiles));
EXPECT_CALL(*tile_manager(), Init(_))
.WillOnce(Invoke([](base::OnceCallback<void(TileGroupStatus)> callback) {
std::move(callback).Run(TileGroupStatus::kNoTiles);
}));
Initialize(true);
}
// Tests that TileManager fail to init, that causes TileServiceImpl to fail to
// initialize too.
TEST_F(TileServiceImplTest, ManagerInitFailed) {
EXPECT_CALL(*tile_manager(), Init(_))
.WillOnce(Invoke([](base::OnceCallback<void(TileGroupStatus)> callback) {
std::move(callback).Run(TileGroupStatus::kFailureDbOperation);
}));
Initialize(false);
}
// Tests that tiles are successfully fetched and saved.
TEST_F(TileServiceImplTest, FetchForTilesSucceeded) {
EXPECT_CALL(*tile_manager(), SaveTiles(_, _))
.WillOnce(Invoke([](std::unique_ptr<TileGroup> tile_group,
base::OnceCallback<void(TileGroupStatus)> callback) {
std::move(callback).Run(TileGroupStatus::kSuccess);
}));
EXPECT_CALL(*image_prefetcher(), Prefetch(_, _, _));
FetchForTilesSuceeded();
}
// Tests that tiles failed to fetch.
TEST_F(TileServiceImplTest, FetchForTilesFailed) {
FetchForTilesWithError();
}
TEST_F(TileServiceImplTest, CancelTask) {
EXPECT_CALL(*scheduler(), CancelTask());
query_tiles_service()->CancelTask();
}
TEST_F(TileServiceImplTest, GetTiles) {
int expected_size = 5;
EXPECT_CALL(*tile_manager(), GetTiles(_))
.WillOnce(Invoke([&](GetTilesCallback callback) {
std::vector<Tile> out = std::vector<Tile>(expected_size, Tile());
std::move(callback).Run(std::move(out));
}));
query_tiles_service()->GetQueryTiles(
base::BindOnce(&TileServiceImplTest::OnGetTilesDone,
base::Unretained(this), expected_size));
}
TEST_F(TileServiceImplTest, GetTile) {
std::string tile_id = "test-id";
EXPECT_CALL(*tile_manager(), GetTile(tile_id, _))
.WillOnce(Invoke([&](const std::string& id, TileCallback callback) {
EXPECT_EQ(id, tile_id);
Tile out;
out.id = tile_id;
std::move(callback).Run(std::move(out));
}));
query_tiles_service()->GetTile(
tile_id, base::BindOnce(&TileServiceImplTest::OnGetTileDone,
base::Unretained(this), tile_id));
}
TEST_F(TileServiceImplTest, PurgeDb) {
EXPECT_CALL(*tile_manager(), PurgeDb());
EXPECT_CALL(*tile_manager(), GetTiles(_));
EXPECT_CALL(*scheduler(), OnDbPurged(_));
query_tiles_service()->PurgeDb();
query_tiles_service()->GetQueryTiles(base::BindOnce(
&TileServiceImplTest::OnGetTilesDone, base::Unretained(this), 0));
}
} // namespace query_tiles