Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(301)

Side by Side Diff: base/task_scheduler/priority_queue_unittest.cc

Issue 1709713002: TaskScheduler [4/9] Priority Queue (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@s_2_sequence_and_task
Patch Set: self review Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 "base/task_scheduler/priority_queue.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/macros.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/task_scheduler/sequence.h"
14 #include "base/task_scheduler/task.h"
15 #include "base/task_scheduler/task_traits.h"
16 #include "base/task_scheduler/test_utils.h"
17 #include "base/threading/platform_thread.h"
18 #include "base/threading/simple_thread.h"
19 #include "base/time/time.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace base {
24 namespace internal {
25
26 namespace {
27
28 class PriorityQueueCallbackMock {
29 public:
30 PriorityQueueCallbackMock() = default;
31 MOCK_METHOD0(SequenceInsertedInPriorityQueue, void());
32
33 private:
34 DISALLOW_COPY_AND_ASSIGN(PriorityQueueCallbackMock);
35 };
36
37 class ThreadBeginningTransaction : public SimpleThread {
38 public:
39 explicit ThreadBeginningTransaction(PriorityQueue* priority_queue)
40 : SimpleThread("ThreadBeginningTransaction"),
41 priority_queue_(priority_queue),
42 transaction_began_(true, false) {}
43
44 // SimpleThread:
45 void Run() override {
46 scoped_ptr<PriorityQueue::Transaction> transaction =
47 priority_queue_->BeginTransaction();
48 transaction_began_.Signal();
49 }
50
51 bool transaction_began() { return transaction_began_.IsSignaled(); }
52
53 private:
54 PriorityQueue* const priority_queue_;
55 WaitableEvent transaction_began_;
56
57 DISALLOW_COPY_AND_ASSIGN(ThreadBeginningTransaction);
58 };
59
60 void ExpectSequenceAndSortKeyEq(
61 const PriorityQueue::SequenceAndSortKey& expected,
62 const PriorityQueue::SequenceAndSortKey& actual) {
63 EXPECT_EQ(expected.sequence, actual.sequence);
64 EXPECT_EQ(expected.sort_key.priority, actual.sort_key.priority);
65 EXPECT_EQ(expected.sort_key.next_task_sequenced_time,
66 actual.sort_key.next_task_sequenced_time);
67 }
68
69 #define EXPECT_SEQUENCE_AND_SORT_KEY_EQ(expected, actual) \
70 { \
danakj 2016/03/18 20:24:05 oh, I remembered another common trick, you can do:
fdoray 2016/03/18 21:22:18 Done.
71 SCOPED_TRACE(""); \
72 ExpectSequenceAndSortKeyEq(expected, actual); \
73 }
74
75 } // namespace
76
77 TEST(TaskSchedulerPriorityQueueTest, PushPopPeek) {
78 // Create test sequences.
79 scoped_refptr<Sequence> sequence_a(new Sequence);
80 sequence_a->PushTask(make_scoped_ptr(
81 new Task(FROM_HERE, Closure(),
82 TaskTraits().WithPriority(TaskPriority::USER_VISIBLE))));
83 SequenceSortKey sort_key_a = sequence_a->GetSortKey();
84
85 scoped_refptr<Sequence> sequence_b(new Sequence);
86 sequence_b->PushTask(make_scoped_ptr(
87 new Task(FROM_HERE, Closure(),
88 TaskTraits().WithPriority(TaskPriority::USER_BLOCKING))));
89 SequenceSortKey sort_key_b = sequence_b->GetSortKey();
90
91 scoped_refptr<Sequence> sequence_c(new Sequence);
92 sequence_c->PushTask(make_scoped_ptr(
93 new Task(FROM_HERE, Closure(),
94 TaskTraits().WithPriority(TaskPriority::USER_BLOCKING))));
95 SequenceSortKey sort_key_c = sequence_c->GetSortKey();
96
97 scoped_refptr<Sequence> sequence_d(new Sequence);
98 sequence_d->PushTask(make_scoped_ptr(
99 new Task(FROM_HERE, Closure(),
100 TaskTraits().WithPriority(TaskPriority::BACKGROUND))));
101 SequenceSortKey sort_key_d = sequence_d->GetSortKey();
102
103 // Create a PriorityQueue and a Transaction.
104 testing::StrictMock<PriorityQueueCallbackMock> mock;
105 PriorityQueue pq(
106 Bind(&PriorityQueueCallbackMock::SequenceInsertedInPriorityQueue,
107 Unretained(&mock)));
108 scoped_ptr<PriorityQueue::Transaction> transaction(pq.BeginTransaction());
109 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(PriorityQueue::SequenceAndSortKey(),
110 transaction->Peek());
111
112 // Push |sequence_a| in the PriorityQueue. It becomes the sequence with the
113 // highest priority.
114 transaction->Push(make_scoped_ptr(
115 new PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a)));
116 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(
117 PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a),
118 transaction->Peek());
119
120 // Push |sequence_b| in the PriorityQueue. It becomes the sequence with the
121 // highest priority.
122 transaction->Push(make_scoped_ptr(
123 new PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b)));
124 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(
125 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b),
126 transaction->Peek());
127
128 // Push |sequence_c| in the PriorityQueue. |sequence_b| is still the sequence
129 // with the highest priority.
130 transaction->Push(make_scoped_ptr(
131 new PriorityQueue::SequenceAndSortKey(sequence_c, sort_key_c)));
132 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(
133 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b),
134 transaction->Peek());
135
136 // Push |sequence_d| in the PriorityQueue. |sequence_b| is still the sequence
137 // with the highest priority.
138 transaction->Push(make_scoped_ptr(
139 new PriorityQueue::SequenceAndSortKey(sequence_d, sort_key_d)));
140 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(
141 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b),
142 transaction->Peek());
143
144 // Pop |sequence_b| from the PriorityQueue. |sequence_c| becomes the sequence
145 // with the highest priority.
146 transaction->Pop();
147 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(
148 PriorityQueue::SequenceAndSortKey(sequence_c, sort_key_c),
149 transaction->Peek());
150
151 // Pop |sequence_c| from the PriorityQueue. |sequence_a| becomes the sequence
152 // with the highest priority.
153 transaction->Pop();
154 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(
155 PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a),
156 transaction->Peek());
157
158 // Pop |sequence_a| from the PriorityQueue. |sequence_d| becomes the sequence
159 // with the highest priority.
160 transaction->Pop();
161 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(
162 PriorityQueue::SequenceAndSortKey(sequence_d, sort_key_d),
163 transaction->Peek());
164
165 // Pop |sequence_d| from the PriorityQueue. It is now empty.
166 transaction->Pop();
167 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(PriorityQueue::SequenceAndSortKey(),
168 transaction->Peek());
169
170 // Expect 4 calls to mock.SequenceInsertedInPriorityQueue() when the
171 // Transaction is destroyed.
172 EXPECT_CALL(mock, SequenceInsertedInPriorityQueue()).Times(4);
173 transaction.reset();
174 }
175
176 // Check that creating Transactions on the same thread for 2 unrelated
177 // PriorityQueues causes a crash.
178 TEST(TaskSchedulerPriorityQueueTest, IllegalTwoTransactionsSameThread) {
179 PriorityQueue pq_a(Bind(&DoNothing));
180 PriorityQueue pq_b(Bind(&DoNothing));
181
182 EXPECT_DCHECK_DEATH({
183 scoped_ptr<PriorityQueue::Transaction> transaction_a =
184 pq_a.BeginTransaction();
185 scoped_ptr<PriorityQueue::Transaction> transaction_b =
186 pq_b.BeginTransaction();
187 }, "");
188 }
189
190 // Check that there is no crash when Transactions are created on the same thread
191 // for 2 PriorityQueues which have a predecessor relationship.
192 TEST(TaskSchedulerPriorityQueueTest, LegalTwoTransactionsSameThread) {
193 PriorityQueue pq_a(Bind(&DoNothing));
194 PriorityQueue pq_b(Bind(&DoNothing), &pq_a);
195
196 // This shouldn't crash.
197 scoped_ptr<PriorityQueue::Transaction> transaction_a =
198 pq_a.BeginTransaction();
199 scoped_ptr<PriorityQueue::Transaction> transaction_b =
200 pq_b.BeginTransaction();
201 }
202
203 // Check that it is possible to begin multiple Transactions for the same
204 // PriorityQueue on different threads. The call to BeginTransaction() on the
205 // second thread should block until the Transaction has ended on the first
206 // thread.
207 TEST(TaskSchedulerPriorityQueueTest, TwoTransactionsTwoThreads) {
208 PriorityQueue pq(Bind(&DoNothing));
209
210 // Call BeginTransaction() on this thread and keep the Transaction alive.
211 scoped_ptr<PriorityQueue::Transaction> transaction = pq.BeginTransaction();
212
213 // Call BeginTransaction() on another thread.
214 ThreadBeginningTransaction thread_beginning_transaction(&pq);
215 thread_beginning_transaction.Start();
216
217 // After a few milliseconds, the call to BeginTransaction() on the other
218 // thread should not have returned.
219 PlatformThread::Sleep(TimeDelta::FromMilliseconds(200));
220 EXPECT_FALSE(thread_beginning_transaction.transaction_began());
danakj 2016/03/18 20:24:05 Instead of a Sleep you could use TimedWait() on th
fdoray 2016/03/18 21:22:18 Done.
221
222 // End the Transaction on the current thread.
223 transaction.reset();
224
225 // The other thread should exit after its call to BeginTransaction() returns.
226 thread_beginning_transaction.Join();
227 EXPECT_TRUE(thread_beginning_transaction.transaction_began());
228 }
229
230 TEST(TaskSchedulerPriorityQueueTest, SequenceAndSortKeyIsNull) {
231 EXPECT_TRUE(PriorityQueue::SequenceAndSortKey().is_null());
232
233 const PriorityQueue::SequenceAndSortKey non_null_sequence_andsort_key(
234 make_scoped_refptr(new Sequence),
235 SequenceSortKey(TaskPriority::USER_VISIBLE, TimeTicks()));
236 EXPECT_FALSE(non_null_sequence_andsort_key.is_null());
237 }
238
239 } // namespace internal
240 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698