tile_service_scheduler_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/query_tiles/internal/tile_service_scheduler_impl.h"
  5. #include <utility>
  6. #include <vector>
  7. #include "base/bind.h"
  8. #include "base/command_line.h"
  9. #include "base/run_loop.h"
  10. #include "base/test/scoped_command_line.h"
  11. #include "base/test/simple_test_clock.h"
  12. #include "base/test/simple_test_tick_clock.h"
  13. #include "base/test/task_environment.h"
  14. #include "base/test/test_mock_time_task_runner.h"
  15. #include "base/time/time.h"
  16. #include "components/prefs/pref_service.h"
  17. #include "components/prefs/testing_pref_service.h"
  18. #include "components/query_tiles/internal/black_hole_log_sink.h"
  19. #include "components/query_tiles/internal/tile_config.h"
  20. #include "components/query_tiles/internal/tile_store.h"
  21. #include "components/query_tiles/switches.h"
  22. #include "components/query_tiles/test/test_utils.h"
  23. #include "components/query_tiles/tile_service_prefs.h"
  24. #include "net/base/backoff_entry_serializer.h"
  25. #include "testing/gmock/include/gmock/gmock.h"
  26. #include "testing/gtest/include/gtest/gtest.h"
  27. using testing::_;
  28. using ::testing::Invoke;
  29. namespace query_tiles {
  30. namespace {
  31. constexpr net::BackoffEntry::Policy kTestPolicy = {
  32. 0 /*num_errors_to_ignore*/,
  33. 1000 /*init_delay_ms*/,
  34. 2 /*multiply_factor*/,
  35. 0 /*jitter_factor*/,
  36. 4000 /*max_backoff_ms*/,
  37. -1 /*entry_lifetime_ms*/,
  38. false /*always_use_init_delay*/};
  39. class MockBackgroundTaskScheduler
  40. : public background_task::BackgroundTaskScheduler {
  41. public:
  42. MockBackgroundTaskScheduler() = default;
  43. ~MockBackgroundTaskScheduler() override = default;
  44. MOCK_METHOD1(Schedule, bool(const background_task::TaskInfo& task_info));
  45. MOCK_METHOD1(Cancel, void(int));
  46. };
  47. class TileServiceSchedulerTest : public testing::Test {
  48. public:
  49. TileServiceSchedulerTest() = default;
  50. ~TileServiceSchedulerTest() override = default;
  51. void SetUp() override {
  52. base::Time fake_now;
  53. EXPECT_TRUE(base::Time::FromString("05/18/20 01:00:00 AM", &fake_now));
  54. clock_.SetNow(fake_now);
  55. query_tiles::RegisterPrefs(prefs()->registry());
  56. log_sink_ = std::make_unique<test::BlackHoleLogSink>();
  57. auto policy = std::make_unique<net::BackoffEntry::Policy>(kTestPolicy);
  58. tile_service_scheduler_ = std::make_unique<TileServiceSchedulerImpl>(
  59. &mocked_native_scheduler_, &prefs_, &clock_, &tick_clock_,
  60. std::move(policy), log_sink_.get());
  61. EXPECT_CALL(
  62. *native_scheduler(),
  63. Cancel(static_cast<int>(background_task::TaskIds::QUERY_TILE_JOB_ID)));
  64. tile_service_scheduler()->CancelTask();
  65. }
  66. protected:
  67. MockBackgroundTaskScheduler* native_scheduler() {
  68. return &mocked_native_scheduler_;
  69. }
  70. TileServiceScheduler* tile_service_scheduler() {
  71. return tile_service_scheduler_.get();
  72. }
  73. TestingPrefServiceSimple* prefs() { return &prefs_; }
  74. base::SimpleTestClock* clock() { return &clock_; }
  75. base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
  76. std::unique_ptr<net::BackoffEntry> GetBackoffPolicy() {
  77. const base::Value::List& value = prefs()->GetValueList(kBackoffEntryKey);
  78. return net::BackoffEntrySerializer::DeserializeFromList(
  79. value, &kTestPolicy, tick_clock(), clock()->Now());
  80. }
  81. void ResetTileServiceScheduler() {
  82. auto policy = std::make_unique<net::BackoffEntry::Policy>(kTestPolicy);
  83. tile_service_scheduler_ = std::make_unique<TileServiceSchedulerImpl>(
  84. &mocked_native_scheduler_, &prefs_, &clock_, &tick_clock_,
  85. std::move(policy), log_sink_.get());
  86. }
  87. private:
  88. base::test::TaskEnvironment task_environment_;
  89. base::SimpleTestClock clock_;
  90. base::SimpleTestTickClock tick_clock_;
  91. TestingPrefServiceSimple prefs_;
  92. MockBackgroundTaskScheduler mocked_native_scheduler_;
  93. std::unique_ptr<LogSink> log_sink_;
  94. std::unique_ptr<TileServiceScheduler> tile_service_scheduler_;
  95. };
  96. MATCHER_P2(TaskInfoEq,
  97. min_window_start_time_ms,
  98. max_window_start_time_ms,
  99. "Verify window range in TaskInfo.") {
  100. EXPECT_TRUE(arg.one_off_info.has_value());
  101. EXPECT_GE(arg.one_off_info->window_start_time_ms, min_window_start_time_ms);
  102. EXPECT_LE(arg.one_off_info->window_start_time_ms, max_window_start_time_ms)
  103. << "Actual window start time in ms: "
  104. << arg.one_off_info->window_start_time_ms;
  105. if (base::CommandLine::ForCurrentProcess()->HasSwitch(
  106. switches::kQueryTilesInstantBackgroundTask)) {
  107. EXPECT_EQ(arg.one_off_info->window_end_time_ms -
  108. arg.one_off_info->window_start_time_ms,
  109. 10 * 1000)
  110. << "Actual window end time in ms: "
  111. << arg.one_off_info->window_end_time_ms;
  112. } else {
  113. EXPECT_EQ(arg.one_off_info->window_end_time_ms -
  114. arg.one_off_info->window_start_time_ms,
  115. TileConfig::GetOneoffTaskWindowInMs())
  116. << "Actual window end time in ms: "
  117. << arg.one_off_info->window_end_time_ms;
  118. }
  119. return true;
  120. }
  121. TEST_F(TileServiceSchedulerTest, OnFetchCompletedSuccess) {
  122. auto expected_range_start = TileConfig::GetScheduleIntervalInMs();
  123. auto expected_range_end =
  124. expected_range_start + TileConfig::GetMaxRandomWindowInMs();
  125. EXPECT_CALL(*native_scheduler(),
  126. Schedule(TaskInfoEq(expected_range_start, expected_range_end)));
  127. tile_service_scheduler()->OnFetchCompleted(TileInfoRequestStatus::kSuccess);
  128. }
  129. TEST_F(TileServiceSchedulerTest, OnFetchCompletedSuccessInstantFetchOn) {
  130. base::test::ScopedCommandLine scoped_command_line;
  131. scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
  132. query_tiles::switches::kQueryTilesInstantBackgroundTask, "true");
  133. EXPECT_CALL(*native_scheduler(), Schedule(_)).Times(0);
  134. tile_service_scheduler()->OnFetchCompleted(TileInfoRequestStatus::kSuccess);
  135. }
  136. TEST_F(TileServiceSchedulerTest, OnFetchCompletedSuspend) {
  137. EXPECT_CALL(*native_scheduler(), Schedule(_)).Times(0);
  138. tile_service_scheduler()->OnFetchCompleted(
  139. TileInfoRequestStatus::kShouldSuspend);
  140. auto backoff = GetBackoffPolicy();
  141. EXPECT_EQ(backoff->GetTimeUntilRelease().InMilliseconds(), 0);
  142. // Scheduler is in a suspended state, initializing the tile manager will not
  143. // schedule any tasks.
  144. tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kNoTiles);
  145. ResetTileServiceScheduler();
  146. // A task is rescheduled when scheduler is recreated.
  147. auto expected_range_start = TileConfig::GetScheduleIntervalInMs();
  148. auto expected_range_end =
  149. expected_range_start + TileConfig::GetMaxRandomWindowInMs();
  150. EXPECT_CALL(*native_scheduler(),
  151. Schedule(TaskInfoEq(expected_range_start, expected_range_end)));
  152. tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kNoTiles);
  153. }
  154. // Verify the failure will add delay that using test backoff policy.
  155. TEST_F(TileServiceSchedulerTest, OnFetchCompletedFailure) {
  156. for (int i = 0; i <= 2; i++) {
  157. EXPECT_CALL(*native_scheduler(),
  158. Schedule(TaskInfoEq(1000 * pow(2, i), 1000 * pow(2, i))));
  159. tile_service_scheduler()->OnFetchCompleted(TileInfoRequestStatus::kFailure);
  160. auto backoff = GetBackoffPolicy();
  161. EXPECT_EQ(backoff->GetTimeUntilRelease().InMilliseconds(),
  162. 1000 * pow(2, i));
  163. }
  164. }
  165. TEST_F(TileServiceSchedulerTest, OnFetchCompletedOtherStatus) {
  166. std::vector<TileInfoRequestStatus> other_status = {
  167. TileInfoRequestStatus::kInit};
  168. EXPECT_CALL(*native_scheduler(), Schedule(_)).Times(0);
  169. for (const auto& status : other_status) {
  170. tile_service_scheduler()->OnFetchCompleted(status);
  171. }
  172. }
  173. TEST_F(TileServiceSchedulerTest, OnTileGroupLoadedWithNoTiles) {
  174. auto expected_range_start = TileConfig::GetScheduleIntervalInMs();
  175. auto expected_range_end =
  176. expected_range_start + TileConfig::GetMaxRandomWindowInMs();
  177. EXPECT_CALL(*native_scheduler(),
  178. Schedule(TaskInfoEq(expected_range_start, expected_range_end)));
  179. tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kNoTiles);
  180. }
  181. TEST_F(TileServiceSchedulerTest, OnTileGroupLoadedInstantFetchOn) {
  182. base::test::ScopedCommandLine scoped_command_line;
  183. scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
  184. query_tiles::switches::kQueryTilesInstantBackgroundTask, "true");
  185. EXPECT_CALL(*native_scheduler(), Schedule(TaskInfoEq(10 * 1000, 10 * 1000)));
  186. tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kSuccess);
  187. }
  188. TEST_F(TileServiceSchedulerTest, OnTileGroupLoadedWithFailure) {
  189. EXPECT_CALL(*native_scheduler(), Schedule(_)).Times(0);
  190. tile_service_scheduler()->OnTileManagerInitialized(
  191. TileGroupStatus::kFailureDbOperation);
  192. // A task is rescheduled when scheduler is recreated.
  193. ResetTileServiceScheduler();
  194. auto expected_range_start = TileConfig::GetScheduleIntervalInMs();
  195. auto expected_range_end =
  196. expected_range_start + TileConfig::GetMaxRandomWindowInMs();
  197. EXPECT_CALL(*native_scheduler(),
  198. Schedule(TaskInfoEq(expected_range_start, expected_range_end)));
  199. tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kNoTiles);
  200. }
  201. TEST_F(TileServiceSchedulerTest, OnTileGroupLoadedWithOtherStatus) {
  202. std::vector<TileGroupStatus> other_status = {TileGroupStatus::kUninitialized,
  203. TileGroupStatus ::kSuccess};
  204. EXPECT_CALL(*native_scheduler(), Schedule(_)).Times(0);
  205. for (const auto status : other_status) {
  206. tile_service_scheduler()->OnTileManagerInitialized(status);
  207. }
  208. }
  209. // OnTileManagerInitialized(NoTiles) could be called many time before the first
  210. // fetch task started. Ensure only the first one actually schedules the task,
  211. // other calls should not override the existing task until it is executed and
  212. // marked finished.
  213. TEST_F(TileServiceSchedulerTest, FirstKickoffNotOverride) {
  214. // Verifying only schedule once also implying only the first schedule
  215. // call works.
  216. EXPECT_CALL(*native_scheduler(), Schedule(_)).Times(1);
  217. auto now = clock()->Now();
  218. tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kNoTiles);
  219. EXPECT_EQ(prefs()->GetTime(kFirstScheduleTimeKey), now);
  220. auto two_hours_later = now + base::Hours(2);
  221. clock()->SetNow(two_hours_later);
  222. tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kNoTiles);
  223. tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kNoTiles);
  224. EXPECT_EQ(prefs()->GetTime(kFirstScheduleTimeKey), now);
  225. EXPECT_CALL(*native_scheduler(), Schedule(_)).Times(1);
  226. tile_service_scheduler()->OnFetchCompleted(TileInfoRequestStatus::kSuccess);
  227. EXPECT_EQ(prefs()->GetTime(kFirstScheduleTimeKey), base::Time());
  228. }
  229. TEST_F(TileServiceSchedulerTest, FirstRunFinishedAfterInstantFetchComplete) {
  230. base::test::ScopedCommandLine scoped_command_line;
  231. auto now = clock()->Now();
  232. EXPECT_CALL(*native_scheduler(), Schedule(_)).Times(1);
  233. tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kNoTiles);
  234. EXPECT_EQ(prefs()->GetTime(kFirstScheduleTimeKey), now);
  235. // Set instant-fetch flag to true after first-kickoff flow was marked and
  236. // scheduled, expecting the mark of first flow also being reset.
  237. scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
  238. query_tiles::switches::kQueryTilesInstantBackgroundTask, "true");
  239. EXPECT_CALL(*native_scheduler(), Schedule(_)).Times(0);
  240. tile_service_scheduler()->OnFetchCompleted(TileInfoRequestStatus::kSuccess);
  241. EXPECT_EQ(prefs()->GetTime(kFirstScheduleTimeKey), base::Time());
  242. // Set instant-fetch flag to false after 2 hours. Chrome restarts with no
  243. // tiles, the scheduler should start a new first kickoff flow.
  244. scoped_command_line.GetProcessCommandLine()->RemoveSwitch(
  245. query_tiles::switches::kQueryTilesInstantBackgroundTask);
  246. auto two_hours_later = now + base::Hours(2);
  247. clock()->SetNow(two_hours_later);
  248. EXPECT_CALL(*native_scheduler(), Schedule(_)).Times(1);
  249. tile_service_scheduler()->OnTileManagerInitialized(TileGroupStatus::kNoTiles);
  250. EXPECT_EQ(prefs()->GetTime(kFirstScheduleTimeKey), two_hours_later);
  251. }
  252. } // namespace
  253. } // namespace query_tiles