• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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