|  | // Copyright 2016 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 "base/task_scheduler/sequence.h" | 
|  |  | 
|  | #include "base/macros.h" | 
|  | #include "base/time/time.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace base { | 
|  | namespace internal { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class TaskSchedulerSequenceTest : public testing::Test { | 
|  | public: | 
|  | TaskSchedulerSequenceTest() | 
|  | : task_a_owned_( | 
|  | new Task(FROM_HERE, | 
|  | Closure(), | 
|  | TaskTraits().WithPriority(TaskPriority::BACKGROUND), | 
|  | TimeDelta())), | 
|  | task_b_owned_( | 
|  | new Task(FROM_HERE, | 
|  | Closure(), | 
|  | TaskTraits().WithPriority(TaskPriority::USER_VISIBLE), | 
|  | TimeDelta())), | 
|  | task_c_owned_( | 
|  | new Task(FROM_HERE, | 
|  | Closure(), | 
|  | TaskTraits().WithPriority(TaskPriority::USER_BLOCKING), | 
|  | TimeDelta())), | 
|  | task_d_owned_( | 
|  | new Task(FROM_HERE, | 
|  | Closure(), | 
|  | TaskTraits().WithPriority(TaskPriority::USER_BLOCKING), | 
|  | TimeDelta())), | 
|  | task_e_owned_( | 
|  | new Task(FROM_HERE, | 
|  | Closure(), | 
|  | TaskTraits().WithPriority(TaskPriority::BACKGROUND), | 
|  | TimeDelta())), | 
|  | task_a_(task_a_owned_.get()), | 
|  | task_b_(task_b_owned_.get()), | 
|  | task_c_(task_c_owned_.get()), | 
|  | task_d_(task_d_owned_.get()), | 
|  | task_e_(task_e_owned_.get()) {} | 
|  |  | 
|  | protected: | 
|  | // Tasks to be handed off to a Sequence for testing. | 
|  | std::unique_ptr<Task> task_a_owned_; | 
|  | std::unique_ptr<Task> task_b_owned_; | 
|  | std::unique_ptr<Task> task_c_owned_; | 
|  | std::unique_ptr<Task> task_d_owned_; | 
|  | std::unique_ptr<Task> task_e_owned_; | 
|  |  | 
|  | // Raw pointers to those same tasks for verification. This is needed because | 
|  | // the scoped_ptrs above no longer point to the tasks once they have been | 
|  | // moved into a Sequence. | 
|  | const Task* task_a_; | 
|  | const Task* task_b_; | 
|  | const Task* task_c_; | 
|  | const Task* task_d_; | 
|  | const Task* task_e_; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSequenceTest); | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | TEST_F(TaskSchedulerSequenceTest, PushPopPeek) { | 
|  | scoped_refptr<Sequence> sequence(new Sequence); | 
|  |  | 
|  | // Push task A in the sequence. Its sequenced time should be updated and it | 
|  | // should be in front of the sequence. | 
|  | EXPECT_TRUE(sequence->PushTask(std::move(task_a_owned_))); | 
|  | EXPECT_FALSE(task_a_->sequenced_time.is_null()); | 
|  | EXPECT_EQ(task_a_, sequence->PeekTask()); | 
|  |  | 
|  | // Push task B, C and D in the sequence. Their sequenced time should be | 
|  | // updated and task A should always remain in front of the sequence. | 
|  | EXPECT_FALSE(sequence->PushTask(std::move(task_b_owned_))); | 
|  | EXPECT_FALSE(task_b_->sequenced_time.is_null()); | 
|  | EXPECT_EQ(task_a_, sequence->PeekTask()); | 
|  |  | 
|  | EXPECT_FALSE(sequence->PushTask(std::move(task_c_owned_))); | 
|  | EXPECT_FALSE(task_c_->sequenced_time.is_null()); | 
|  | EXPECT_EQ(task_a_, sequence->PeekTask()); | 
|  |  | 
|  | EXPECT_FALSE(sequence->PushTask(std::move(task_d_owned_))); | 
|  | EXPECT_FALSE(task_d_->sequenced_time.is_null()); | 
|  | EXPECT_EQ(task_a_, sequence->PeekTask()); | 
|  |  | 
|  | // Pop task A. Task B should now be in front. | 
|  | EXPECT_FALSE(sequence->PopTask()); | 
|  | EXPECT_EQ(task_b_, sequence->PeekTask()); | 
|  |  | 
|  | // Pop task B. Task C should now be in front. | 
|  | EXPECT_FALSE(sequence->PopTask()); | 
|  | EXPECT_EQ(task_c_, sequence->PeekTask()); | 
|  |  | 
|  | // Pop task C. Task D should now be in front. | 
|  | EXPECT_FALSE(sequence->PopTask()); | 
|  | EXPECT_EQ(task_d_, sequence->PeekTask()); | 
|  |  | 
|  | // Push task E in the sequence. Its sequenced time should be updated and | 
|  | // task D should remain in front. | 
|  | EXPECT_FALSE(sequence->PushTask(std::move(task_e_owned_))); | 
|  | EXPECT_FALSE(task_e_->sequenced_time.is_null()); | 
|  | EXPECT_EQ(task_d_, sequence->PeekTask()); | 
|  |  | 
|  | // Pop task D. Task E should now be in front. | 
|  | EXPECT_FALSE(sequence->PopTask()); | 
|  | EXPECT_EQ(task_e_, sequence->PeekTask()); | 
|  |  | 
|  | // Pop task E. The sequence should now be empty. | 
|  | EXPECT_TRUE(sequence->PopTask()); | 
|  | EXPECT_EQ(nullptr, sequence->PeekTask()); | 
|  | } | 
|  |  | 
|  | TEST_F(TaskSchedulerSequenceTest, GetSortKey) { | 
|  | scoped_refptr<Sequence> sequence(new Sequence); | 
|  |  | 
|  | // Push task A in the sequence. The highest priority is from task A | 
|  | // (BACKGROUND). Task A is in front of the sequence. | 
|  | sequence->PushTask(std::move(task_a_owned_)); | 
|  | EXPECT_EQ(SequenceSortKey(TaskPriority::BACKGROUND, task_a_->sequenced_time), | 
|  | sequence->GetSortKey()); | 
|  |  | 
|  | // Push task B in the sequence. The highest priority is from task B | 
|  | // (USER_VISIBLE). Task A is still in front of the sequence. | 
|  | sequence->PushTask(std::move(task_b_owned_)); | 
|  | EXPECT_EQ( | 
|  | SequenceSortKey(TaskPriority::USER_VISIBLE, task_a_->sequenced_time), | 
|  | sequence->GetSortKey()); | 
|  |  | 
|  | // Push task C in the sequence. The highest priority is from task C | 
|  | // (USER_BLOCKING). Task A is still in front of the sequence. | 
|  | sequence->PushTask(std::move(task_c_owned_)); | 
|  | EXPECT_EQ( | 
|  | SequenceSortKey(TaskPriority::USER_BLOCKING, task_a_->sequenced_time), | 
|  | sequence->GetSortKey()); | 
|  |  | 
|  | // Push task D in the sequence. The highest priority is from tasks C/D | 
|  | // (USER_BLOCKING). Task A is still in front of the sequence. | 
|  | sequence->PushTask(std::move(task_d_owned_)); | 
|  | EXPECT_EQ( | 
|  | SequenceSortKey(TaskPriority::USER_BLOCKING, task_a_->sequenced_time), | 
|  | sequence->GetSortKey()); | 
|  |  | 
|  | // Pop task A. The highest priority is still USER_BLOCKING. The task in front | 
|  | // of the sequence is now task B. | 
|  | sequence->PopTask(); | 
|  | EXPECT_EQ( | 
|  | SequenceSortKey(TaskPriority::USER_BLOCKING, task_b_->sequenced_time), | 
|  | sequence->GetSortKey()); | 
|  |  | 
|  | // Pop task B. The highest priority is still USER_BLOCKING. The task in front | 
|  | // of the sequence is now task C. | 
|  | sequence->PopTask(); | 
|  | EXPECT_EQ( | 
|  | SequenceSortKey(TaskPriority::USER_BLOCKING, task_c_->sequenced_time), | 
|  | sequence->GetSortKey()); | 
|  |  | 
|  | // Pop task C. The highest priority is still USER_BLOCKING. The task in front | 
|  | // of the sequence is now task D. | 
|  | sequence->PopTask(); | 
|  | EXPECT_EQ( | 
|  | SequenceSortKey(TaskPriority::USER_BLOCKING, task_d_->sequenced_time), | 
|  | sequence->GetSortKey()); | 
|  |  | 
|  | // Push task E in the sequence. The highest priority is still USER_BLOCKING. | 
|  | // The task in front of the sequence is still task D. | 
|  | sequence->PushTask(std::move(task_e_owned_)); | 
|  | EXPECT_EQ( | 
|  | SequenceSortKey(TaskPriority::USER_BLOCKING, task_d_->sequenced_time), | 
|  | sequence->GetSortKey()); | 
|  |  | 
|  | // Pop task D. The highest priority is now from task E (BACKGROUND). The | 
|  | // task in front of the sequence is now task E. | 
|  | sequence->PopTask(); | 
|  | EXPECT_EQ(SequenceSortKey(TaskPriority::BACKGROUND, task_e_->sequenced_time), | 
|  | sequence->GetSortKey()); | 
|  | } | 
|  |  | 
|  | }  // namespace internal | 
|  | }  // namespace base |