xref: /aosp_15_r20/external/cronet/base/task/thread_pool/worker_thread_set_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 The Chromium Authors
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/thread_pool/worker_thread_set.h"
6 
7 #include "base/check_op.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/task/thread_pool/task_source.h"
10 #include "base/task/thread_pool/task_tracker.h"
11 #include "base/task/thread_pool/worker_thread.h"
12 #include "base/task/thread_pool/worker_thread_waitable_event.h"
13 #include "base/test/gtest_util.h"
14 #include "base/threading/platform_thread.h"
15 #include "base/time/time.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 namespace base::internal {
19 
20 namespace {
21 
22 class MockWorkerThreadDelegate : public WorkerThreadWaitableEvent::Delegate {
23  public:
GetThreadLabel() const24   WorkerThread::ThreadLabel GetThreadLabel() const override {
25     return WorkerThread::ThreadLabel::DEDICATED;
26   }
OnMainEntry(WorkerThread * worker)27   void OnMainEntry(WorkerThread* worker) override {}
GetWork(WorkerThread * worker)28   RegisteredTaskSource GetWork(WorkerThread* worker) override {
29     return nullptr;
30   }
SwapProcessedTask(RegisteredTaskSource task_source,WorkerThread * worker)31   RegisteredTaskSource SwapProcessedTask(RegisteredTaskSource task_source,
32                                          WorkerThread* worker) override {
33     ADD_FAILURE() << "Unexpected call to SwapProcessedTask()";
34     return nullptr;
35   }
GetSleepTimeout()36   TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); }
37 };
38 
39 class ThreadPoolWorkerSetTest : public testing::Test {
40  protected:
SetUp()41   void SetUp() override {
42     worker_a_ = MakeRefCounted<WorkerThreadWaitableEvent>(
43         ThreadType::kDefault, std::make_unique<MockWorkerThreadDelegate>(),
44         task_tracker_.GetTrackedRef(), 0);
45     ASSERT_TRUE(worker_a_);
46     worker_b_ = MakeRefCounted<WorkerThreadWaitableEvent>(
47         ThreadType::kDefault, std::make_unique<MockWorkerThreadDelegate>(),
48         task_tracker_.GetTrackedRef(), 1);
49     ASSERT_TRUE(worker_b_);
50     worker_c_ = MakeRefCounted<WorkerThreadWaitableEvent>(
51         ThreadType::kDefault, std::make_unique<MockWorkerThreadDelegate>(),
52         task_tracker_.GetTrackedRef(), 2);
53     ASSERT_TRUE(worker_c_);
54   }
55 
56  private:
57   TaskTracker task_tracker_;
58 
59  protected:
60   scoped_refptr<WorkerThreadWaitableEvent> worker_a_;
61   scoped_refptr<WorkerThreadWaitableEvent> worker_b_;
62   scoped_refptr<WorkerThreadWaitableEvent> worker_c_;
63 };
64 
65 }  // namespace
66 
67 // Verify that Insert() and Take() add/remove values in FIFO order.
TEST_F(ThreadPoolWorkerSetTest,InsertTake)68 TEST_F(ThreadPoolWorkerSetTest, InsertTake) {
69   WorkerThreadSet set;
70   EXPECT_EQ(nullptr, set.Take());
71 
72   EXPECT_TRUE(set.IsEmpty());
73   EXPECT_EQ(0U, set.Size());
74 
75   set.Insert(worker_a_.get());
76   EXPECT_FALSE(set.IsEmpty());
77   EXPECT_EQ(1U, set.Size());
78 
79   set.Insert(worker_b_.get());
80   EXPECT_FALSE(set.IsEmpty());
81   EXPECT_EQ(2U, set.Size());
82 
83   set.Insert(worker_c_.get());
84   EXPECT_FALSE(set.IsEmpty());
85   EXPECT_EQ(3U, set.Size());
86 
87   WorkerThreadWaitableEvent* idle_worker = set.Take();
88   EXPECT_EQ(idle_worker, worker_a_.get());
89   EXPECT_FALSE(set.IsEmpty());
90   EXPECT_EQ(2U, set.Size());
91 
92   set.Insert(idle_worker);
93   EXPECT_FALSE(set.IsEmpty());
94   EXPECT_EQ(3U, set.Size());
95 
96   EXPECT_EQ(idle_worker, set.Take());
97   EXPECT_FALSE(set.IsEmpty());
98   EXPECT_EQ(2U, set.Size());
99 
100   EXPECT_TRUE(set.Take());
101   EXPECT_FALSE(set.IsEmpty());
102   EXPECT_EQ(1U, set.Size());
103 
104   EXPECT_TRUE(set.Take());
105   EXPECT_TRUE(set.IsEmpty());
106   EXPECT_EQ(0U, set.Size());
107 
108   EXPECT_EQ(nullptr, set.Take());
109 }
110 
111 // Verify that Peek() returns the correct values in FIFO order.
TEST_F(ThreadPoolWorkerSetTest,PeekPop)112 TEST_F(ThreadPoolWorkerSetTest, PeekPop) {
113   WorkerThreadSet set;
114   EXPECT_EQ(nullptr, set.Peek());
115 
116   EXPECT_TRUE(set.IsEmpty());
117   EXPECT_EQ(0U, set.Size());
118 
119   set.Insert(worker_a_.get());
120   EXPECT_EQ(worker_a_.get(), set.Peek());
121   EXPECT_FALSE(set.IsEmpty());
122   EXPECT_EQ(1U, set.Size());
123 
124   set.Insert(worker_b_.get());
125   EXPECT_FALSE(set.IsEmpty());
126   EXPECT_EQ(2U, set.Size());
127 
128   set.Insert(worker_c_.get());
129   EXPECT_FALSE(set.IsEmpty());
130   EXPECT_EQ(3U, set.Size());
131 
132   WorkerThreadWaitableEvent* idle_worker = set.Take();
133   EXPECT_EQ(worker_a_.get(), idle_worker);
134   EXPECT_EQ(worker_b_.get(), set.Peek());
135   EXPECT_FALSE(set.IsEmpty());
136   EXPECT_EQ(2U, set.Size());
137 
138   EXPECT_EQ(worker_b_.get(), set.Take());
139   EXPECT_EQ(worker_c_.get(), set.Peek());
140   EXPECT_FALSE(set.IsEmpty());
141   EXPECT_EQ(1U, set.Size());
142 
143   EXPECT_EQ(worker_c_.get(), set.Take());
144   EXPECT_TRUE(set.IsEmpty());
145   EXPECT_EQ(0U, set.Size());
146 
147   EXPECT_EQ(nullptr, set.Peek());
148 }
149 
150 // Verify that Contains() returns true for workers on the set.
TEST_F(ThreadPoolWorkerSetTest,Contains)151 TEST_F(ThreadPoolWorkerSetTest, Contains) {
152   WorkerThreadSet set;
153   EXPECT_FALSE(set.Contains(worker_a_.get()));
154   EXPECT_FALSE(set.Contains(worker_b_.get()));
155   EXPECT_FALSE(set.Contains(worker_c_.get()));
156 
157   set.Insert(worker_a_.get());
158   EXPECT_TRUE(set.Contains(worker_a_.get()));
159   EXPECT_FALSE(set.Contains(worker_b_.get()));
160   EXPECT_FALSE(set.Contains(worker_c_.get()));
161 
162   set.Insert(worker_b_.get());
163   EXPECT_TRUE(set.Contains(worker_a_.get()));
164   EXPECT_TRUE(set.Contains(worker_b_.get()));
165   EXPECT_FALSE(set.Contains(worker_c_.get()));
166 
167   set.Insert(worker_c_.get());
168   EXPECT_TRUE(set.Contains(worker_a_.get()));
169   EXPECT_TRUE(set.Contains(worker_b_.get()));
170   EXPECT_TRUE(set.Contains(worker_c_.get()));
171 
172   WorkerThreadWaitableEvent* idle_worker = set.Take();
173   EXPECT_EQ(idle_worker, worker_a_.get());
174   EXPECT_FALSE(set.Contains(worker_a_.get()));
175   EXPECT_TRUE(set.Contains(worker_b_.get()));
176   EXPECT_TRUE(set.Contains(worker_c_.get()));
177 
178   set.Take();
179 
180   set.Take();
181   EXPECT_FALSE(set.Contains(worker_a_.get()));
182   EXPECT_FALSE(set.Contains(worker_b_.get()));
183   EXPECT_FALSE(set.Contains(worker_c_.get()));
184 }
185 
186 // Verify that a value can be removed by Remove().
TEST_F(ThreadPoolWorkerSetTest,Remove)187 TEST_F(ThreadPoolWorkerSetTest, Remove) {
188   WorkerThreadSet set;
189   EXPECT_TRUE(set.IsEmpty());
190   EXPECT_EQ(0U, set.Size());
191 
192   set.Insert(worker_a_.get());
193   EXPECT_FALSE(set.IsEmpty());
194   EXPECT_EQ(1U, set.Size());
195 
196   set.Insert(worker_b_.get());
197   EXPECT_FALSE(set.IsEmpty());
198   EXPECT_EQ(2U, set.Size());
199 
200   set.Insert(worker_c_.get());
201   EXPECT_FALSE(set.IsEmpty());
202   EXPECT_EQ(3U, set.Size());
203 
204   set.Remove(worker_b_.get());
205   EXPECT_FALSE(set.IsEmpty());
206   EXPECT_EQ(2U, set.Size());
207 
208   EXPECT_EQ(worker_a_.get(), set.Take());
209   EXPECT_FALSE(set.IsEmpty());
210   EXPECT_EQ(1U, set.Size());
211 
212   EXPECT_EQ(worker_c_.get(), set.Take());
213   EXPECT_TRUE(set.IsEmpty());
214   EXPECT_EQ(0U, set.Size());
215 }
216 
217 // Verify that a value can be pushed again after it has been removed.
TEST_F(ThreadPoolWorkerSetTest,PushAfterRemove)218 TEST_F(ThreadPoolWorkerSetTest, PushAfterRemove) {
219   WorkerThreadSet set;
220   EXPECT_EQ(0U, set.Size());
221 
222   set.Insert(worker_a_.get());
223   EXPECT_EQ(1U, set.Size());
224 
225   // Need to also push worker B for this test as it's illegal to Remove() the
226   // front of the set.
227   set.Insert(worker_b_.get());
228   EXPECT_EQ(2U, set.Size());
229 
230   set.Remove(worker_b_.get());
231   worker_b_->EndUnusedPeriod();
232   EXPECT_EQ(1U, set.Size());
233 
234   set.Insert(worker_b_.get());
235   EXPECT_EQ(2U, set.Size());
236 }
237 
238 // Verify that Insert() DCHECKs when a value is inserted twice.
TEST_F(ThreadPoolWorkerSetTest,PushTwice)239 TEST_F(ThreadPoolWorkerSetTest, PushTwice) {
240   WorkerThreadSet set;
241   set.Insert(worker_a_.get());
242   EXPECT_DCHECK_DEATH({ set.Insert(worker_a_.get()); });
243 }
244 
245 }  // namespace base::internal
246