| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 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 |
| 5 #include "components/offline_pages/core/task_queue.h" |
| 6 |
| 7 #include <memory> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/test/test_simple_task_runner.h" |
| 11 #include "base/threading/thread_task_runner_handle.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 |
| 14 namespace offline_pages { |
| 15 |
| 16 namespace { |
| 17 |
| 18 enum class TaskState { NOT_STARTED, STEP_1, STEP_2, COMPLETED }; |
| 19 |
| 20 // Sample resource consumed by the task during execution. In this set of tests |
| 21 // used to provide the capability to continue the task. |
| 22 class ConsumedResource { |
| 23 public: |
| 24 void Step(const base::Closure& step_callback) { next_step_ = step_callback; } |
| 25 void CompleteStep() { |
| 26 base::Closure temp_ = next_step_; |
| 27 next_step_.Reset(); |
| 28 temp_.Run(); |
| 29 } |
| 30 bool HasNextStep() const { return !next_step_.is_null(); } |
| 31 |
| 32 private: |
| 33 base::Closure next_step_; |
| 34 }; |
| 35 |
| 36 // Sample test task. This should not be used as a example of task implementation |
| 37 // with respect to callback safety. Otherwise it captures the idea of splitting |
| 38 // the work into multiple steps separated by potentially asynchronous calls |
| 39 // spanning multiple threads. |
| 40 class TestTask : public TaskQueue::Task { |
| 41 public: |
| 42 explicit TestTask(ConsumedResource* resource) |
| 43 : resource_(resource), |
| 44 state_(TaskState::NOT_STARTED), |
| 45 leave_early_(false) {} |
| 46 TestTask(ConsumedResource* resource, bool leave_early) |
| 47 : resource_(resource), |
| 48 state_(TaskState::NOT_STARTED), |
| 49 leave_early_(leave_early) {} |
| 50 ~TestTask() override {} |
| 51 |
| 52 // Run is Step 1 in our case. |
| 53 void Run() override { |
| 54 state_ = TaskState::STEP_1; |
| 55 resource_->Step(base::Bind(&TestTask::Step2, base::Unretained(this))); |
| 56 } |
| 57 |
| 58 void Step2() { |
| 59 if (leave_early_) { |
| 60 LastStep(); |
| 61 return; |
| 62 } |
| 63 state_ = TaskState::STEP_2; |
| 64 resource_->Step(base::Bind(&TestTask::LastStep, base::Unretained(this))); |
| 65 } |
| 66 |
| 67 // This is step 3, but we conclude here. |
| 68 void LastStep() { |
| 69 state_ = TaskState::COMPLETED; |
| 70 Complete(); |
| 71 } |
| 72 |
| 73 TaskState state() const { return state_; } |
| 74 |
| 75 private: |
| 76 ConsumedResource* resource_; |
| 77 TaskState state_; |
| 78 bool leave_early_; |
| 79 }; |
| 80 |
| 81 } // namespace |
| 82 |
| 83 class OfflineTaskQueueTest : public testing::Test { |
| 84 public: |
| 85 OfflineTaskQueueTest(); |
| 86 |
| 87 void TaskCompleted(TaskQueue::Task* task); |
| 88 void PumpLoop(); |
| 89 |
| 90 TaskQueue::Task* completed_task() const { return completed_task_; } |
| 91 |
| 92 private: |
| 93 TaskQueue::Task* completed_task_; |
| 94 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; |
| 95 base::ThreadTaskRunnerHandle task_runner_handle_; |
| 96 }; |
| 97 |
| 98 OfflineTaskQueueTest::OfflineTaskQueueTest() |
| 99 : completed_task_(nullptr), |
| 100 task_runner_(new base::TestSimpleTaskRunner), |
| 101 task_runner_handle_(task_runner_) {} |
| 102 |
| 103 void OfflineTaskQueueTest::PumpLoop() { |
| 104 task_runner_->RunUntilIdle(); |
| 105 } |
| 106 |
| 107 void OfflineTaskQueueTest::TaskCompleted(TaskQueue::Task* task) { |
| 108 completed_task_ = task; |
| 109 } |
| 110 |
| 111 TEST_F(OfflineTaskQueueTest, RunTaskStepByStep) { |
| 112 ConsumedResource resource; |
| 113 TestTask task(&resource); |
| 114 task.SetCompletionCallback( |
| 115 base::ThreadTaskRunnerHandle::Get(), |
| 116 base::Bind(&OfflineTaskQueueTest::TaskCompleted, base::Unretained(this))); |
| 117 |
| 118 EXPECT_EQ(TaskState::NOT_STARTED, task.state()); |
| 119 task.Run(); |
| 120 EXPECT_EQ(TaskState::STEP_1, task.state()); |
| 121 EXPECT_TRUE(resource.HasNextStep()); |
| 122 resource.CompleteStep(); |
| 123 EXPECT_EQ(TaskState::STEP_2, task.state()); |
| 124 EXPECT_TRUE(resource.HasNextStep()); |
| 125 resource.CompleteStep(); |
| 126 EXPECT_EQ(TaskState::COMPLETED, task.state()); |
| 127 PumpLoop(); |
| 128 EXPECT_EQ(completed_task(), &task); |
| 129 } |
| 130 |
| 131 TEST_F(OfflineTaskQueueTest, AddAndRunSingleTask) { |
| 132 ConsumedResource resource; |
| 133 std::unique_ptr<TestTask> task(new TestTask(&resource)); |
| 134 TestTask* task_ptr = task.get(); |
| 135 TaskQueue queue; |
| 136 EXPECT_EQ(TaskState::NOT_STARTED, task_ptr->state()); |
| 137 queue.AddTask(std::move(task)); |
| 138 EXPECT_TRUE(queue.HasTasks()); |
| 139 EXPECT_TRUE(queue.CurrentlyRunning()); |
| 140 EXPECT_EQ(TaskState::STEP_1, task_ptr->state()); |
| 141 EXPECT_TRUE(resource.HasNextStep()); |
| 142 resource.CompleteStep(); |
| 143 |
| 144 EXPECT_EQ(TaskState::STEP_2, task_ptr->state()); |
| 145 EXPECT_TRUE(resource.HasNextStep()); |
| 146 resource.CompleteStep(); |
| 147 |
| 148 EXPECT_EQ(TaskState::COMPLETED, task_ptr->state()); |
| 149 EXPECT_FALSE(resource.HasNextStep()); |
| 150 PumpLoop(); // Deletes task, task_ptr is invalid after that. |
| 151 |
| 152 EXPECT_FALSE(queue.CurrentlyRunning()); |
| 153 EXPECT_FALSE(queue.HasTasks()); |
| 154 } |
| 155 |
| 156 TEST_F(OfflineTaskQueueTest, AddAndRunMultipleTasks) { |
| 157 ConsumedResource resource; |
| 158 std::unique_ptr<TestTask> task_1(new TestTask(&resource)); |
| 159 TestTask* task_1_ptr = task_1.get(); |
| 160 std::unique_ptr<TestTask> task_2(new TestTask(&resource)); |
| 161 TestTask* task_2_ptr = task_2.get(); |
| 162 |
| 163 TaskQueue queue; |
| 164 EXPECT_EQ(TaskState::NOT_STARTED, task_1_ptr->state()); |
| 165 EXPECT_EQ(TaskState::NOT_STARTED, task_2_ptr->state()); |
| 166 queue.AddTask(std::move(task_1)); |
| 167 queue.AddTask(std::move(task_2)); |
| 168 EXPECT_TRUE(queue.HasTasks()); |
| 169 EXPECT_TRUE(queue.CurrentlyRunning()); |
| 170 EXPECT_EQ(TaskState::STEP_1, task_1_ptr->state()); |
| 171 EXPECT_EQ(TaskState::NOT_STARTED, task_2_ptr->state()); |
| 172 resource.CompleteStep(); |
| 173 |
| 174 EXPECT_EQ(TaskState::STEP_2, task_1_ptr->state()); |
| 175 EXPECT_EQ(TaskState::NOT_STARTED, task_2_ptr->state()); |
| 176 resource.CompleteStep(); |
| 177 |
| 178 EXPECT_EQ(TaskState::COMPLETED, task_1_ptr->state()); |
| 179 EXPECT_EQ(TaskState::NOT_STARTED, task_2_ptr->state()); |
| 180 PumpLoop(); // Deletes task_1, task_1_ptr is invalid after that. |
| 181 EXPECT_EQ(TaskState::STEP_1, task_2_ptr->state()); |
| 182 } |
| 183 |
| 184 TEST_F(OfflineTaskQueueTest, LeaveEearly) { |
| 185 ConsumedResource resource; |
| 186 std::unique_ptr<TestTask> task(new TestTask(&resource, true)); |
| 187 TestTask* task_ptr = task.get(); |
| 188 TaskQueue queue; |
| 189 EXPECT_EQ(TaskState::NOT_STARTED, task_ptr->state()); |
| 190 queue.AddTask(std::move(task)); |
| 191 EXPECT_TRUE(queue.HasTasks()); |
| 192 EXPECT_TRUE(queue.CurrentlyRunning()); |
| 193 EXPECT_EQ(TaskState::STEP_1, task_ptr->state()); |
| 194 EXPECT_TRUE(resource.HasNextStep()); |
| 195 resource.CompleteStep(); |
| 196 |
| 197 EXPECT_EQ(TaskState::COMPLETED, task_ptr->state()); |
| 198 EXPECT_FALSE(resource.HasNextStep()); |
| 199 PumpLoop(); // Deletes task, task_ptr is invalid after that. |
| 200 |
| 201 EXPECT_FALSE(queue.CurrentlyRunning()); |
| 202 EXPECT_FALSE(queue.HasTasks()); |
| 203 } |
| 204 |
| 205 } // namespace offline_pages |
| OLD | NEW |