Index: base/task_scheduler/scheduler_worker_thread_unittest.cc |
diff --git a/base/task_scheduler/scheduler_worker_thread_unittest.cc b/base/task_scheduler/scheduler_worker_thread_unittest.cc |
index 63e1cf6e6d69543cdff118b3a7708d58f74f1805..f3512a8da58baa266eeeb402ccf3125aeae17afc 100644 |
--- a/base/task_scheduler/scheduler_worker_thread_unittest.cc |
+++ b/base/task_scheduler/scheduler_worker_thread_unittest.cc |
@@ -26,13 +26,13 @@ namespace { |
const size_t kNumSequencesPerTest = 150; |
-class TaskSchedulerWorkerThreadTest : public testing::Test, |
+// The test parameter is the number of Tasks per Sequence returned by GetWork(). |
+class TaskSchedulerWorkerThreadTest : public testing::TestWithParam<size_t>, |
public SchedulerWorkerThread::Delegate { |
protected: |
TaskSchedulerWorkerThreadTest() |
: main_entry_called_(true, false), |
- num_get_work_cv_(lock_.CreateConditionVariable()), |
- run_sequences_cv_(lock_.CreateConditionVariable()) {} |
+ num_get_work_cv_(lock_.CreateConditionVariable()) {} |
void SetUp() override { |
worker_thread_ = SchedulerWorkerThread::CreateSchedulerWorkerThread( |
@@ -53,6 +53,8 @@ class TaskSchedulerWorkerThreadTest : public testing::Test, |
EXPECT_TRUE(main_exit_called_); |
} |
+ size_t TasksPerSequence() const { return GetParam(); } |
+ |
// Wait until GetWork() has been called |num_get_work| times. |
void WaitForNumGetWork(size_t num_get_work) { |
AutoSchedulerLock auto_lock(lock_); |
@@ -60,23 +62,9 @@ class TaskSchedulerWorkerThreadTest : public testing::Test, |
num_get_work_cv_->Wait(); |
} |
- // Wait until there are no more Sequences to create and RanTaskFromSequence() |
- // has been invoked once for each Sequence returned by GetWork(). |
- void WaitForAllSequencesToRun() { |
+ void SetMaxGetWork(size_t max_get_work) { |
AutoSchedulerLock auto_lock(lock_); |
- |
- while (num_sequences_to_create_ > 0 || |
- run_sequences_.size() < created_sequences_.size()) { |
- run_sequences_cv_->Wait(); |
- } |
- |
- // Verify that RanTaskFromSequence() has been invoked with the same |
- // Sequences that were returned by GetWork(). |
- EXPECT_EQ(created_sequences_, run_sequences_); |
- |
- // Verify that RunTaskCallback() has been invoked once for each Sequence |
- // returned by GetWork(). |
- EXPECT_EQ(created_sequences_.size(), num_run_tasks_); |
+ max_get_work_ = max_get_work; |
} |
void SetNumSequencesToCreate(size_t num_sequences_to_create) { |
@@ -85,9 +73,19 @@ class TaskSchedulerWorkerThreadTest : public testing::Test, |
num_sequences_to_create_ = num_sequences_to_create; |
} |
- void SetMaxGetWork(size_t max_get_work) { |
+ size_t NumRunTasks() { |
AutoSchedulerLock auto_lock(lock_); |
- max_get_work_ = max_get_work; |
+ return num_run_tasks_; |
+ } |
+ |
+ std::vector<scoped_refptr<Sequence>> CreatedSequences() { |
+ AutoSchedulerLock auto_lock(lock_); |
+ return created_sequences_; |
+ } |
+ |
+ std::vector<scoped_refptr<Sequence>> EnqueuedSequences() { |
+ AutoSchedulerLock auto_lock(lock_); |
+ return enqueued_sequences_; |
} |
std::unique_ptr<SchedulerWorkerThread> worker_thread_; |
@@ -128,14 +126,16 @@ class TaskSchedulerWorkerThreadTest : public testing::Test, |
--num_sequences_to_create_; |
} |
- // Create a Sequence that contains one Task. |
+ // Create a Sequence with TasksPerSequence() Tasks. |
scoped_refptr<Sequence> sequence(new Sequence); |
- std::unique_ptr<Task> task(new Task( |
- FROM_HERE, |
- Bind(&TaskSchedulerWorkerThreadTest::RunTaskCallback, Unretained(this)), |
- TaskTraits())); |
- EXPECT_TRUE(task_tracker_.WillPostTask(task.get())); |
- sequence->PushTask(std::move(task)); |
+ for (size_t i = 0; i < TasksPerSequence(); ++i) { |
+ std::unique_ptr<Task> task(new Task( |
+ FROM_HERE, Bind(&TaskSchedulerWorkerThreadTest::RunTaskCallback, |
+ Unretained(this)), |
+ TaskTraits())); |
+ EXPECT_TRUE(task_tracker_.WillPostTask(task.get())); |
+ sequence->PushTask(std::move(task)); |
+ } |
{ |
// Add the Sequence to the vector of created Sequences. |
@@ -146,11 +146,24 @@ class TaskSchedulerWorkerThreadTest : public testing::Test, |
return sequence; |
} |
- void RanTaskFromSequence(scoped_refptr<Sequence> sequence) override { |
+ // This override verifies that |sequence| contains the expected number of |
+ // Tasks and adds it to |enqueued_sequences_|. Unlike a normal EnqueueSequence |
+ // implementation, it doesn't reinsert |sequence| into a queue for further |
+ // execution. |
+ void EnqueueSequence(scoped_refptr<Sequence> sequence) override { |
+ EXPECT_GT(TasksPerSequence(), 1U); |
+ |
+ // Verify that |sequence| contains TasksPerSequence() - 1 Tasks. |
+ for (size_t i = 0; i < TasksPerSequence() - 1; ++i) { |
+ EXPECT_TRUE(sequence->PeekTask()); |
+ sequence->PopTask(); |
+ } |
+ EXPECT_FALSE(sequence->PeekTask()); |
+ |
+ // Add |sequence| to |enqueued_sequences_|. |
AutoSchedulerLock auto_lock(lock_); |
- run_sequences_.push_back(std::move(sequence)); |
- EXPECT_LE(run_sequences_.size(), created_sequences_.size()); |
- run_sequences_cv_->Signal(); |
+ enqueued_sequences_.push_back(std::move(sequence)); |
+ EXPECT_LE(enqueued_sequences_.size(), created_sequences_.size()); |
} |
void RunTaskCallback() { |
@@ -186,11 +199,8 @@ class TaskSchedulerWorkerThreadTest : public testing::Test, |
// Sequences created by GetWork(). |
std::vector<scoped_refptr<Sequence>> created_sequences_; |
- // Sequences passed to RanTaskFromSequence(). |
- std::vector<scoped_refptr<Sequence>> run_sequences_; |
- |
- // Condition variable signaled when a Sequence is added to |run_sequences_|. |
- std::unique_ptr<ConditionVariable> run_sequences_cv_; |
+ // Sequences passed to EnqueueSequence(). |
+ std::vector<scoped_refptr<Sequence>> enqueued_sequences_; |
// Number of times that RunTaskCallback() has been called. |
size_t num_run_tasks_ = 0; |
@@ -200,7 +210,7 @@ class TaskSchedulerWorkerThreadTest : public testing::Test, |
// Verify that when GetWork() continuously returns Sequences, all Tasks in these |
// Sequences run successfully. The test wakes up the SchedulerWorkerThread once. |
-TEST_F(TaskSchedulerWorkerThreadTest, ContinuousWork) { |
+TEST_P(TaskSchedulerWorkerThreadTest, ContinuousWork) { |
// Set GetWork() to return |kNumSequencesPerTest| Sequences before starting to |
// return nullptr. |
SetNumSequencesToCreate(kNumSequencesPerTest); |
@@ -210,17 +220,27 @@ TEST_F(TaskSchedulerWorkerThreadTest, ContinuousWork) { |
const size_t kExpectedNumGetWork = kNumSequencesPerTest + 1; |
SetMaxGetWork(kExpectedNumGetWork); |
- // Wake up |worker_thread_| and wait until it has run all the Tasks returned |
- // by GetWork(). |
+ // Wake up |worker_thread_| and wait until GetWork() has been invoked the |
+ // expected amount of times. |
worker_thread_->WakeUp(); |
- WaitForAllSequencesToRun(); |
WaitForNumGetWork(kExpectedNumGetWork); |
+ |
+ // All tasks should have run. |
+ EXPECT_EQ(kNumSequencesPerTest, NumRunTasks()); |
+ |
+ // If Sequences returned by GetWork() contain more than one Task, they aren't |
+ // empty after the worker thread pops Tasks from them and thus should be |
+ // returned to EnqueueSequence(). |
+ if (TasksPerSequence() > 1) |
+ EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); |
+ else |
+ EXPECT_TRUE(EnqueuedSequences().empty()); |
} |
// Verify that when GetWork() alternates between returning a Sequence and |
// returning nullptr, all Tasks in the returned Sequences run successfully. The |
// test wakes up the SchedulerWorkerThread once for each Sequence. |
-TEST_F(TaskSchedulerWorkerThreadTest, IntermittentWork) { |
+TEST_P(TaskSchedulerWorkerThreadTest, IntermittentWork) { |
for (size_t i = 0; i < kNumSequencesPerTest; ++i) { |
// Set GetWork() to return 1 Sequence before starting to return |
// nullptr. |
@@ -231,14 +251,31 @@ TEST_F(TaskSchedulerWorkerThreadTest, IntermittentWork) { |
const size_t expected_num_get_work = 2 * (i + 1); |
SetMaxGetWork(expected_num_get_work); |
- // Wake up |worker_thread_| and wait until it has run the Task returned by |
- // GetWork(). |
+ // Wake up |worker_thread_| and wait until GetWork() has been invoked |
+ // the expected amount of times. |
worker_thread_->WakeUp(); |
- WaitForAllSequencesToRun(); |
WaitForNumGetWork(expected_num_get_work); |
+ |
+ // The Task should have run |
+ EXPECT_EQ(i + 1, NumRunTasks()); |
+ |
+ // If Sequences returned by GetWork() contain more than one Task, they |
+ // aren't empty after the worker thread pops Tasks from them and thus should |
+ // be returned to EnqueueSequence(). |
+ if (TasksPerSequence() > 1) |
+ EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); |
+ else |
+ EXPECT_TRUE(EnqueuedSequences().empty()); |
} |
} |
+INSTANTIATE_TEST_CASE_P(OneTaskPerSequence, |
+ TaskSchedulerWorkerThreadTest, |
+ ::testing::Values(1)); |
+INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, |
+ TaskSchedulerWorkerThreadTest, |
+ ::testing::Values(2)); |
+ |
} // namespace |
} // namespace internal |
} // namespace base |