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 "base/task_scheduler/sequence.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/test/gtest_util.h"
13 #include "base/time/time.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace base {
18 namespace internal {
19
20 namespace {
21
22 class MockTask {
23 public:
24 MOCK_METHOD0(Run, void());
25 };
26
CreateTask(MockTask * mock_task)27 Task CreateTask(MockTask* mock_task) {
28 return Task(FROM_HERE, BindOnce(&MockTask::Run, Unretained(mock_task)),
29 {TaskPriority::BACKGROUND}, TimeDelta());
30 }
31
ExpectMockTask(MockTask * mock_task,Task * task)32 void ExpectMockTask(MockTask* mock_task, Task* task) {
33 EXPECT_CALL(*mock_task, Run());
34 std::move(task->task).Run();
35 testing::Mock::VerifyAndClear(mock_task);
36 }
37
38 } // namespace
39
TEST(TaskSchedulerSequenceTest,PushTakeRemove)40 TEST(TaskSchedulerSequenceTest, PushTakeRemove) {
41 testing::StrictMock<MockTask> mock_task_a;
42 testing::StrictMock<MockTask> mock_task_b;
43 testing::StrictMock<MockTask> mock_task_c;
44 testing::StrictMock<MockTask> mock_task_d;
45 testing::StrictMock<MockTask> mock_task_e;
46
47 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>();
48
49 // Push task A in the sequence. PushTask() should return true since it's the
50 // first task->
51 EXPECT_TRUE(sequence->PushTask(CreateTask(&mock_task_a)));
52
53 // Push task B, C and D in the sequence. PushTask() should return false since
54 // there is already a task in a sequence.
55 EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_b)));
56 EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_c)));
57 EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_d)));
58
59 // Take the task in front of the sequence. It should be task A.
60 Optional<Task> task = sequence->TakeTask();
61 ExpectMockTask(&mock_task_a, &task.value());
62 EXPECT_FALSE(task->sequenced_time.is_null());
63
64 // Remove the empty slot. Task B should now be in front.
65 EXPECT_FALSE(sequence->Pop());
66 task = sequence->TakeTask();
67 ExpectMockTask(&mock_task_b, &task.value());
68 EXPECT_FALSE(task->sequenced_time.is_null());
69
70 // Remove the empty slot. Task C should now be in front.
71 EXPECT_FALSE(sequence->Pop());
72 task = sequence->TakeTask();
73 ExpectMockTask(&mock_task_c, &task.value());
74 EXPECT_FALSE(task->sequenced_time.is_null());
75
76 // Remove the empty slot.
77 EXPECT_FALSE(sequence->Pop());
78
79 // Push task E in the sequence.
80 EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_e)));
81
82 // Task D should be in front.
83 task = sequence->TakeTask();
84 ExpectMockTask(&mock_task_d, &task.value());
85 EXPECT_FALSE(task->sequenced_time.is_null());
86
87 // Remove the empty slot. Task E should now be in front.
88 EXPECT_FALSE(sequence->Pop());
89 task = sequence->TakeTask();
90 ExpectMockTask(&mock_task_e, &task.value());
91 EXPECT_FALSE(task->sequenced_time.is_null());
92
93 // Remove the empty slot. The sequence should now be empty.
94 EXPECT_TRUE(sequence->Pop());
95 }
96
97 // Verifies the sort key of a sequence that contains one BACKGROUND task.
TEST(TaskSchedulerSequenceTest,GetSortKeyBackground)98 TEST(TaskSchedulerSequenceTest, GetSortKeyBackground) {
99 // Create a sequence with a BACKGROUND task.
100 Task background_task(FROM_HERE, DoNothing(), {TaskPriority::BACKGROUND},
101 TimeDelta());
102 scoped_refptr<Sequence> background_sequence = MakeRefCounted<Sequence>();
103 background_sequence->PushTask(std::move(background_task));
104
105 // Get the sort key.
106 const SequenceSortKey background_sort_key = background_sequence->GetSortKey();
107
108 // Take the task from the sequence, so that its sequenced time is available
109 // for the check below.
110 auto take_background_task = background_sequence->TakeTask();
111
112 // Verify the sort key.
113 EXPECT_EQ(TaskPriority::BACKGROUND, background_sort_key.priority());
114 EXPECT_EQ(take_background_task->sequenced_time,
115 background_sort_key.next_task_sequenced_time());
116
117 // Pop for correctness.
118 background_sequence->Pop();
119 }
120
121 // Same as TaskSchedulerSequenceTest.GetSortKeyBackground, but with a
122 // USER_VISIBLE task.
TEST(TaskSchedulerSequenceTest,GetSortKeyForeground)123 TEST(TaskSchedulerSequenceTest, GetSortKeyForeground) {
124 // Create a sequence with a USER_VISIBLE task.
125 Task foreground_task(FROM_HERE, DoNothing(), {TaskPriority::USER_VISIBLE},
126 TimeDelta());
127 scoped_refptr<Sequence> foreground_sequence = MakeRefCounted<Sequence>();
128 foreground_sequence->PushTask(std::move(foreground_task));
129
130 // Get the sort key.
131 const SequenceSortKey foreground_sort_key = foreground_sequence->GetSortKey();
132
133 // Take the task from the sequence, so that its sequenced time is available
134 // for the check below.
135 auto take_foreground_task = foreground_sequence->TakeTask();
136
137 // Verify the sort key.
138 EXPECT_EQ(TaskPriority::USER_VISIBLE, foreground_sort_key.priority());
139 EXPECT_EQ(take_foreground_task->sequenced_time,
140 foreground_sort_key.next_task_sequenced_time());
141
142 // Pop for correctness.
143 foreground_sequence->Pop();
144 }
145
146 // Verify that a DCHECK fires if Pop() is called on a sequence whose front slot
147 // isn't empty.
TEST(TaskSchedulerSequenceTest,PopNonEmptyFrontSlot)148 TEST(TaskSchedulerSequenceTest, PopNonEmptyFrontSlot) {
149 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>();
150 sequence->PushTask(Task(FROM_HERE, DoNothing(), TaskTraits(), TimeDelta()));
151
152 EXPECT_DCHECK_DEATH({ sequence->Pop(); });
153 }
154
155 // Verify that a DCHECK fires if TakeTask() is called on a sequence whose front
156 // slot is empty.
TEST(TaskSchedulerSequenceTest,TakeEmptyFrontSlot)157 TEST(TaskSchedulerSequenceTest, TakeEmptyFrontSlot) {
158 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>();
159 sequence->PushTask(Task(FROM_HERE, DoNothing(), TaskTraits(), TimeDelta()));
160
161 EXPECT_TRUE(sequence->TakeTask());
162 EXPECT_DCHECK_DEATH({ sequence->TakeTask(); });
163 }
164
165 // Verify that a DCHECK fires if TakeTask() is called on an empty sequence.
TEST(TaskSchedulerSequenceTest,TakeEmptySequence)166 TEST(TaskSchedulerSequenceTest, TakeEmptySequence) {
167 scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>();
168 EXPECT_DCHECK_DEATH({ sequence->TakeTask(); });
169 }
170
171 } // namespace internal
172 } // namespace base
173