Commit 6c61190e authored by Hesen Zhang's avatar Hesen Zhang Committed by Commit Bot

[Query Tiles]: bug fix and unit test for scheduler and fetcher.

- Fixed fetcher crash because ResourceRequest was null if a second
request was asked but it was build in ctor.
- Fixed a wrong usage of OneOffTaskInfo window.
- Added unit test to verify the start/end window and backoff delay
in task info.

- If debug switch instant fetch on, we always schedule a fetch task
on service startup once, don't do recurring fetching task.

Bug: 1083532
Change-Id: I8c1a29bc7c7692b6c59a2de958589b41ca7957c1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2207616
Commit-Queue: Hesen Zhang <hesen@chromium.org>
Auto-Submit: Hesen Zhang <hesen@chromium.org>
Reviewed-by: default avatarXing Liu <xingliu@chromium.org>
Reviewed-by: default avatarShakti Sahu <shaktisahu@chromium.org>
Reviewed-by: default avatarMin Qin <qinmin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#769910}
parent 776c3374
...@@ -55,20 +55,21 @@ class TileFetcherImpl : public TileFetcher { ...@@ -55,20 +55,21 @@ class TileFetcherImpl : public TileFetcher {
const std::string& experiment_tag, const std::string& experiment_tag,
const std::string& client_version, const std::string& client_version,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: url_loader_factory_(url_loader_factory) { : url_loader_factory_(url_loader_factory),
tile_info_request_status_ = TileInfoRequestStatus::kInit; url_(url),
auto resource_request = country_code_(country_code),
BuildGetRequest(url, country_code, accept_languages, api_key, accept_languages_(accept_languages),
experiment_tag, client_version); api_key_(api_key),
url_loader_ = network::SimpleURLLoader::Create( experiment_tag_(experiment_tag),
std::move(resource_request), kQueryTilesFetcherTrafficAnnotation); client_version_(client_version),
} tile_info_request_status_(TileInfoRequestStatus::kInit) {}
private: private:
// TileFetcher implementation. // TileFetcher implementation.
void StartFetchForTiles(FinishedCallback callback) override { void StartFetchForTiles(FinishedCallback callback) override {
// TODO(hesen): Estimate max size of response then replace to auto resource_request = BuildGetRequest();
// DownloadToString method. url_loader_ = network::SimpleURLLoader::Create(
std::move(resource_request), kQueryTilesFetcherTrafficAnnotation);
url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
url_loader_factory_.get(), url_loader_factory_.get(),
base::BindOnce(&TileFetcherImpl::OnDownloadComplete, base::BindOnce(&TileFetcherImpl::OnDownloadComplete,
...@@ -76,28 +77,22 @@ class TileFetcherImpl : public TileFetcher { ...@@ -76,28 +77,22 @@ class TileFetcherImpl : public TileFetcher {
} }
// Build the request to get tile info. // Build the request to get tile info.
std::unique_ptr<network::ResourceRequest> BuildGetRequest( std::unique_ptr<network::ResourceRequest> BuildGetRequest() {
const GURL& url,
const std::string& country_code,
const std::string& accept_languages,
const std::string& api_key,
const std::string& experiment_tag,
const std::string& client_version) {
auto request = std::make_unique<network::ResourceRequest>(); auto request = std::make_unique<network::ResourceRequest>();
request->method = net::HttpRequestHeaders::kGetMethod; request->method = net::HttpRequestHeaders::kGetMethod;
request->headers.SetHeader("x-goog-api-key", api_key); request->headers.SetHeader("x-goog-api-key", api_key_);
request->headers.SetHeader("X-Client-Version", client_version); request->headers.SetHeader("X-Client-Version", client_version_);
request->headers.SetHeader(net::HttpRequestHeaders::kContentType, request->headers.SetHeader(net::HttpRequestHeaders::kContentType,
kRequestContentType); kRequestContentType);
request->url = request->url =
net::AppendOrReplaceQueryParameter(url, "country_code", country_code); net::AppendOrReplaceQueryParameter(url_, "country_code", country_code_);
if (!experiment_tag.empty()) { if (!experiment_tag_.empty()) {
request->url = net::AppendOrReplaceQueryParameter( request->url = net::AppendOrReplaceQueryParameter(
request->url, "experiment_tag", experiment_tag); request->url, "experiment_tag", experiment_tag_);
} }
if (!accept_languages.empty()) { if (!accept_languages_.empty()) {
request->headers.SetHeader(net::HttpRequestHeaders::kAcceptLanguage, request->headers.SetHeader(net::HttpRequestHeaders::kAcceptLanguage,
accept_languages); accept_languages_);
} }
return request; return request;
} }
...@@ -142,6 +137,7 @@ class TileFetcherImpl : public TileFetcher { ...@@ -142,6 +137,7 @@ class TileFetcherImpl : public TileFetcher {
std::move(callback).Run(tile_info_request_status_, std::move(callback).Run(tile_info_request_status_,
std::move(response_body)); std::move(response_body));
tile_info_request_status_ = TileInfoRequestStatus::kInit; tile_info_request_status_ = TileInfoRequestStatus::kInit;
url_loader_.reset();
} }
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
...@@ -149,6 +145,14 @@ class TileFetcherImpl : public TileFetcher { ...@@ -149,6 +145,14 @@ class TileFetcherImpl : public TileFetcher {
// Simple URL loader to fetch proto from network. // Simple URL loader to fetch proto from network.
std::unique_ptr<network::SimpleURLLoader> url_loader_; std::unique_ptr<network::SimpleURLLoader> url_loader_;
// Params of resource request.
GURL url_;
std::string country_code_;
std::string accept_languages_;
std::string api_key_;
std::string experiment_tag_;
std::string client_version_;
// Status of the tile info request. // Status of the tile info request.
TileInfoRequestStatus tile_info_request_status_; TileInfoRequestStatus tile_info_request_status_;
......
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
namespace query_tiles { namespace query_tiles {
namespace { namespace {
// Schedule window params in instant schedule mode.
const int kInstantScheduleWindowStartMs = 10 * 1000; // 10 seconds
const int kInstantScheduleWindowEndMs = 20 * 1000; // 20 seconds
class TileServiceSchedulerImpl : public TileServiceScheduler { class TileServiceSchedulerImpl : public TileServiceScheduler {
public: public:
TileServiceSchedulerImpl( TileServiceSchedulerImpl(
...@@ -42,6 +46,9 @@ class TileServiceSchedulerImpl : public TileServiceScheduler { ...@@ -42,6 +46,9 @@ class TileServiceSchedulerImpl : public TileServiceScheduler {
} }
void OnFetchCompleted(TileInfoRequestStatus status) override { void OnFetchCompleted(TileInfoRequestStatus status) override {
if (IsInstantFetchMode())
return;
if (status == TileInfoRequestStatus::kShouldSuspend) { if (status == TileInfoRequestStatus::kShouldSuspend) {
MaximizeBackoff(); MaximizeBackoff();
ScheduleTask(false); ScheduleTask(false);
...@@ -56,6 +63,12 @@ class TileServiceSchedulerImpl : public TileServiceScheduler { ...@@ -56,6 +63,12 @@ class TileServiceSchedulerImpl : public TileServiceScheduler {
} }
void OnTileManagerInitialized(TileGroupStatus status) override { void OnTileManagerInitialized(TileGroupStatus status) override {
if (IsInstantFetchMode()) {
ResetBackoff();
ScheduleTask(true);
return;
}
if (status == TileGroupStatus::kNoTiles && !is_suspend_) { if (status == TileGroupStatus::kNoTiles && !is_suspend_) {
ResetBackoff(); ResetBackoff();
ScheduleTask(true); ScheduleTask(true);
...@@ -68,9 +81,7 @@ class TileServiceSchedulerImpl : public TileServiceScheduler { ...@@ -68,9 +81,7 @@ class TileServiceSchedulerImpl : public TileServiceScheduler {
void ScheduleTask(bool is_init_schedule) { void ScheduleTask(bool is_init_schedule) {
background_task::OneOffInfo one_off_task_info; background_task::OneOffInfo one_off_task_info;
bool instant_fetch_task = base::CommandLine::ForCurrentProcess()->HasSwitch( if (IsInstantFetchMode()) {
switches::kQueryTilesInstantBackgroundTask);
if (instant_fetch_task) {
GetInstantTaskWindow(&one_off_task_info.window_start_time_ms, GetInstantTaskWindow(&one_off_task_info.window_start_time_ms,
&one_off_task_info.window_end_time_ms, &one_off_task_info.window_end_time_ms,
is_init_schedule); is_init_schedule);
...@@ -119,22 +130,20 @@ class TileServiceSchedulerImpl : public TileServiceScheduler { ...@@ -119,22 +130,20 @@ class TileServiceSchedulerImpl : public TileServiceScheduler {
void GetInstantTaskWindow(int64_t* start_time_ms, void GetInstantTaskWindow(int64_t* start_time_ms,
int64_t* end_time_ms, int64_t* end_time_ms,
bool is_init_schedule) { bool is_init_schedule) {
auto now = clock_->Now().ToDeltaSinceWindowsEpoch().InMilliseconds();
if (is_init_schedule) { if (is_init_schedule) {
*start_time_ms = now + 10 * 1000; *start_time_ms = kInstantScheduleWindowStartMs;
} else { } else {
*start_time_ms = GetDelaysFromBackoff(); *start_time_ms = GetDelaysFromBackoff();
} }
*end_time_ms = now + 20 * 1000; *end_time_ms = kInstantScheduleWindowEndMs;
} }
void GetTaskWindow(int64_t* start_time_ms, void GetTaskWindow(int64_t* start_time_ms,
int64_t* end_time_ms, int64_t* end_time_ms,
bool is_init_schedule) { bool is_init_schedule) {
auto now = clock_->Now().ToDeltaSinceWindowsEpoch().InMilliseconds();
if (is_init_schedule) { if (is_init_schedule) {
*start_time_ms = *start_time_ms =
now + TileConfig::GetScheduleIntervalInMs() + TileConfig::GetScheduleIntervalInMs() +
base::RandGenerator(TileConfig::GetMaxRandomWindowInMs()); base::RandGenerator(TileConfig::GetMaxRandomWindowInMs());
} else { } else {
*start_time_ms = GetDelaysFromBackoff(); *start_time_ms = GetDelaysFromBackoff();
...@@ -162,6 +171,11 @@ class TileServiceSchedulerImpl : public TileServiceScheduler { ...@@ -162,6 +171,11 @@ class TileServiceSchedulerImpl : public TileServiceScheduler {
prefs_->Set(kBackoffEntryKey, *value); prefs_->Set(kBackoffEntryKey, *value);
} }
bool IsInstantFetchMode() const {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kQueryTilesInstantBackgroundTask);
}
// Native Background Scheduler instance. // Native Background Scheduler instance.
background_task::BackgroundTaskScheduler* scheduler_; background_task::BackgroundTaskScheduler* scheduler_;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/scoped_command_line.h"
#include "base/test/simple_test_clock.h" #include "base/test/simple_test_clock.h"
#include "base/test/simple_test_tick_clock.h" #include "base/test/simple_test_tick_clock.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
#include "components/prefs/testing_pref_service.h" #include "components/prefs/testing_pref_service.h"
#include "components/query_tiles/internal/tile_config.h" #include "components/query_tiles/internal/tile_config.h"
#include "components/query_tiles/internal/tile_store.h" #include "components/query_tiles/internal/tile_store.h"
#include "components/query_tiles/switches.h"
#include "components/query_tiles/test/test_utils.h" #include "components/query_tiles/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -34,8 +36,6 @@ class MockBackgroundTaskScheduler ...@@ -34,8 +36,6 @@ class MockBackgroundTaskScheduler
MOCK_METHOD1(Cancel, void(int)); MOCK_METHOD1(Cancel, void(int));
}; };
// TODO(crbug.com/1082529): Verify the schedule timing range matches task_info,
// also add more cross status situation tests.
class TileServiceSchedulerTest : public testing::Test { class TileServiceSchedulerTest : public testing::Test {
public: public:
TileServiceSchedulerTest() = default; TileServiceSchedulerTest() = default;
...@@ -57,11 +57,13 @@ class TileServiceSchedulerTest : public testing::Test { ...@@ -57,11 +57,13 @@ class TileServiceSchedulerTest : public testing::Test {
tile_service_scheduler_ = tile_service_scheduler_ =
TileServiceScheduler::Create(&mocked_native_scheduler_, &prefs_, TileServiceScheduler::Create(&mocked_native_scheduler_, &prefs_,
&clock_, &tick_clock_, std::move(policy)); &clock_, &tick_clock_, std::move(policy));
EXPECT_CALL(
*native_scheduler(),
Cancel(static_cast<int>(background_task::TaskIds::QUERY_TILE_JOB_ID)));
tile_service_scheduler()->CancelTask();
} }
protected: protected:
base::Clock* clock() { return &clock_; }
base::TickClock* tick_clock() { return &tick_clock_; }
MockBackgroundTaskScheduler* native_scheduler() { MockBackgroundTaskScheduler* native_scheduler() {
return &mocked_native_scheduler_; return &mocked_native_scheduler_;
} }
...@@ -81,27 +83,65 @@ class TileServiceSchedulerTest : public testing::Test { ...@@ -81,27 +83,65 @@ class TileServiceSchedulerTest : public testing::Test {
std::unique_ptr<TileServiceScheduler> tile_service_scheduler_; std::unique_ptr<TileServiceScheduler> tile_service_scheduler_;
}; };
TEST_F(TileServiceSchedulerTest, CancelTask) { MATCHER_P2(TaskInfoEq,
EXPECT_CALL( min_window_start_time_ms,
*native_scheduler(), max_window_start_time_ms,
Cancel(static_cast<int>(background_task::TaskIds::QUERY_TILE_JOB_ID))); "Verify window range in TaskInfo.") {
tile_service_scheduler()->CancelTask(); EXPECT_TRUE(arg.one_off_info.has_value());
EXPECT_GE(arg.one_off_info->window_start_time_ms, min_window_start_time_ms);
EXPECT_LE(arg.one_off_info->window_start_time_ms, max_window_start_time_ms)
<< "Actual window start time in ms: "
<< arg.one_off_info->window_start_time_ms;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kQueryTilesInstantBackgroundTask)) {
EXPECT_EQ(arg.one_off_info->window_end_time_ms -
arg.one_off_info->window_start_time_ms,
10 * 1000)
<< "Actual window end time in ms: "
<< arg.one_off_info->window_end_time_ms;
} else {
EXPECT_EQ(arg.one_off_info->window_end_time_ms -
arg.one_off_info->window_start_time_ms,
TileConfig::GetOneoffTaskWindowInMs())
<< "Actual window end time in ms: "
<< arg.one_off_info->window_end_time_ms;
}
return true;
} }
TEST_F(TileServiceSchedulerTest, OnFetchCompletedSuccess) { TEST_F(TileServiceSchedulerTest, OnFetchCompletedSuccess) {
EXPECT_CALL(*native_scheduler(), Schedule(_)); auto expected_range_start = TileConfig::GetScheduleIntervalInMs();
auto expected_range_end =
expected_range_start + TileConfig::GetMaxRandomWindowInMs();
EXPECT_CALL(*native_scheduler(),
Schedule(TaskInfoEq(expected_range_start, expected_range_end)));
tile_service_scheduler()->OnFetchCompleted(TileInfoRequestStatus::kSuccess);
}
TEST_F(TileServiceSchedulerTest, OnFetchCompletedSuccessInstantFetchOn) {
base::test::ScopedCommandLine scoped_command_line;
scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
query_tiles::switches::kQueryTilesInstantBackgroundTask, "true");
EXPECT_CALL(*native_scheduler(), Schedule(_)).Times(0);
tile_service_scheduler()->OnFetchCompleted(TileInfoRequestStatus::kSuccess); tile_service_scheduler()->OnFetchCompleted(TileInfoRequestStatus::kSuccess);
} }
TEST_F(TileServiceSchedulerTest, OnFetchCompletedSuspend) { TEST_F(TileServiceSchedulerTest, OnFetchCompletedSuspend) {
EXPECT_CALL(*native_scheduler(), Schedule(_)); EXPECT_CALL(*native_scheduler(), Schedule(TaskInfoEq(4000, 4000)));
tile_service_scheduler()->OnFetchCompleted( tile_service_scheduler()->OnFetchCompleted(
TileInfoRequestStatus::kShouldSuspend); TileInfoRequestStatus::kShouldSuspend);
} }
// Verify the failure will add delay that using test backoff policy.
TEST_F(TileServiceSchedulerTest, OnFetchCompletedFailure) { TEST_F(TileServiceSchedulerTest, OnFetchCompletedFailure) {
EXPECT_CALL(*native_scheduler(), Schedule(_)); for (int i = 0; i <= 2; i++) {
tile_service_scheduler()->OnFetchCompleted(TileInfoRequestStatus::kFailure); EXPECT_CALL(*native_scheduler(),
Schedule(TaskInfoEq(1000 * pow(2, i), 1000 * pow(2, i))));
tile_service_scheduler()->OnFetchCompleted(TileInfoRequestStatus::kFailure);
}
} }
TEST_F(TileServiceSchedulerTest, OnFetchCompletedOtherStatus) { TEST_F(TileServiceSchedulerTest, OnFetchCompletedOtherStatus) {
...@@ -114,12 +154,24 @@ TEST_F(TileServiceSchedulerTest, OnFetchCompletedOtherStatus) { ...@@ -114,12 +154,24 @@ TEST_F(TileServiceSchedulerTest, OnFetchCompletedOtherStatus) {
} }
TEST_F(TileServiceSchedulerTest, OnTileGroupLoadedWithNoTiles) { TEST_F(TileServiceSchedulerTest, OnTileGroupLoadedWithNoTiles) {
EXPECT_CALL(*native_scheduler(), Schedule(_)); auto expected_range_start = TileConfig::GetScheduleIntervalInMs();
auto expected_range_end =
expected_range_start + TileConfig::GetMaxRandomWindowInMs();
EXPECT_CALL(*native_scheduler(),
Schedule(TaskInfoEq(expected_range_start, expected_range_end)));
tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kNoTiles); tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kNoTiles);
} }
TEST_F(TileServiceSchedulerTest, OnTileGroupLoadedInstantFetchOn) {
base::test::ScopedCommandLine scoped_command_line;
scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
query_tiles::switches::kQueryTilesInstantBackgroundTask, "true");
EXPECT_CALL(*native_scheduler(), Schedule(TaskInfoEq(10 * 1000, 10 * 1000)));
tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kSuccess);
}
TEST_F(TileServiceSchedulerTest, OnTileGroupLoadedWithFailure) { TEST_F(TileServiceSchedulerTest, OnTileGroupLoadedWithFailure) {
EXPECT_CALL(*native_scheduler(), Schedule(_)); EXPECT_CALL(*native_scheduler(), Schedule(TaskInfoEq(4000, 4000)));
tile_service_scheduler()->OnTileManagerInitialized( tile_service_scheduler()->OnTileManagerInitialized(
TileGroupStatus::kFailureDbOperation); TileGroupStatus::kFailureDbOperation);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment