xref: /aosp_15_r20/external/perfetto/src/base/threading/spawn_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2023 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/spawn.h"
18*6dbdd20aSAndroid Build Coastguard Worker 
19*6dbdd20aSAndroid Build Coastguard Worker #include <memory>
20*6dbdd20aSAndroid Build Coastguard Worker #include <optional>
21*6dbdd20aSAndroid Build Coastguard Worker 
22*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/compiler.h"
23*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/event_fd.h"
24*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/thread_task_runner.h"
25*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/future.h"
26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/poll.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/stream.h"
28*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/util.h"
29*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/unix_task_runner.h"
30*6dbdd20aSAndroid Build Coastguard Worker #include "src/base/test/test_task_runner.h"
31*6dbdd20aSAndroid Build Coastguard Worker #include "test/gtest_and_gmock.h"
32*6dbdd20aSAndroid Build Coastguard Worker 
33*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
34*6dbdd20aSAndroid Build Coastguard Worker namespace base {
35*6dbdd20aSAndroid Build Coastguard Worker namespace {
36*6dbdd20aSAndroid Build Coastguard Worker 
37*6dbdd20aSAndroid Build Coastguard Worker using ::testing::_;
38*6dbdd20aSAndroid Build Coastguard Worker using ::testing::Return;
39*6dbdd20aSAndroid Build Coastguard Worker 
40*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
41*6dbdd20aSAndroid Build Coastguard Worker class MockFuturePollable : public FuturePollable<T> {
42*6dbdd20aSAndroid Build Coastguard Worker  public:
43*6dbdd20aSAndroid Build Coastguard Worker   MOCK_METHOD(FuturePollResult<T>, Poll, (PollContext*), (override));
44*6dbdd20aSAndroid Build Coastguard Worker };
45*6dbdd20aSAndroid Build Coastguard Worker 
46*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
47*6dbdd20aSAndroid Build Coastguard Worker class MockStreamPollable : public StreamPollable<T> {
48*6dbdd20aSAndroid Build Coastguard Worker  public:
49*6dbdd20aSAndroid Build Coastguard Worker   MOCK_METHOD(StreamPollResult<T>, PollNext, (PollContext*), (override));
50*6dbdd20aSAndroid Build Coastguard Worker };
51*6dbdd20aSAndroid Build Coastguard Worker 
52*6dbdd20aSAndroid Build Coastguard Worker class SpawnUnittest : public testing::Test {
53*6dbdd20aSAndroid Build Coastguard Worker  protected:
Drop(base::SpawnHandle)54*6dbdd20aSAndroid Build Coastguard Worker   void Drop(base::SpawnHandle) {}
Drop(base::Stream<int>)55*6dbdd20aSAndroid Build Coastguard Worker   void Drop(base::Stream<int>) {}
56*6dbdd20aSAndroid Build Coastguard Worker 
57*6dbdd20aSAndroid Build Coastguard Worker   base::TestTaskRunner task_runner_;
58*6dbdd20aSAndroid Build Coastguard Worker 
59*6dbdd20aSAndroid Build Coastguard Worker   base::FlatSet<base::PlatformHandle> interested_;
60*6dbdd20aSAndroid Build Coastguard Worker   base::FlatSet<base::PlatformHandle> ready_;
61*6dbdd20aSAndroid Build Coastguard Worker   PollContext ctx_{&interested_, &ready_};
62*6dbdd20aSAndroid Build Coastguard Worker 
63*6dbdd20aSAndroid Build Coastguard Worker   base::EventFd fd_;
64*6dbdd20aSAndroid Build Coastguard Worker   std::unique_ptr<MockFuturePollable<int>> future_pollable_ =
65*6dbdd20aSAndroid Build Coastguard Worker       std::make_unique<MockFuturePollable<int>>();
66*6dbdd20aSAndroid Build Coastguard Worker   std::unique_ptr<MockStreamPollable<int>> stream_pollable_ =
67*6dbdd20aSAndroid Build Coastguard Worker       std::make_unique<MockStreamPollable<int>>();
68*6dbdd20aSAndroid Build Coastguard Worker };
69*6dbdd20aSAndroid Build Coastguard Worker 
TEST_F(SpawnUnittest,SpawnFuture)70*6dbdd20aSAndroid Build Coastguard Worker TEST_F(SpawnUnittest, SpawnFuture) {
71*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_CALL(*future_pollable_, Poll(_))
72*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce([this](PollContext* ctx) {
73*6dbdd20aSAndroid Build Coastguard Worker         fd_.Clear();
74*6dbdd20aSAndroid Build Coastguard Worker         ctx->RegisterInterested(fd_.fd());
75*6dbdd20aSAndroid Build Coastguard Worker         return PendingPollResult();
76*6dbdd20aSAndroid Build Coastguard Worker       })
77*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(FuturePollResult<int>(1024)));
78*6dbdd20aSAndroid Build Coastguard Worker   auto [handle, future] =
79*6dbdd20aSAndroid Build Coastguard Worker       SpawnResultFuture<int>(&task_runner_, [this]() mutable {
80*6dbdd20aSAndroid Build Coastguard Worker         return base::Future<int>(std::move(future_pollable_));
81*6dbdd20aSAndroid Build Coastguard Worker       });
82*6dbdd20aSAndroid Build Coastguard Worker   base::ignore_result(handle);
83*6dbdd20aSAndroid Build Coastguard Worker 
84*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
85*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(future.Poll(&ctx_).IsPending());
86*6dbdd20aSAndroid Build Coastguard Worker 
87*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
88*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(future.Poll(&ctx_).IsPending());
89*6dbdd20aSAndroid Build Coastguard Worker 
90*6dbdd20aSAndroid Build Coastguard Worker   fd_.Notify();
91*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
92*6dbdd20aSAndroid Build Coastguard Worker 
93*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(future.Poll(&ctx_).item(), 1024);
94*6dbdd20aSAndroid Build Coastguard Worker }
95*6dbdd20aSAndroid Build Coastguard Worker 
TEST_F(SpawnUnittest,SpawnStream)96*6dbdd20aSAndroid Build Coastguard Worker TEST_F(SpawnUnittest, SpawnStream) {
97*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_CALL(*stream_pollable_, PollNext(_))
98*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce([this](PollContext* ctx) {
99*6dbdd20aSAndroid Build Coastguard Worker         fd_.Clear();
100*6dbdd20aSAndroid Build Coastguard Worker         ctx->RegisterInterested(fd_.fd());
101*6dbdd20aSAndroid Build Coastguard Worker         return PendingPollResult();
102*6dbdd20aSAndroid Build Coastguard Worker       })
103*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(1024)))
104*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce([this](PollContext* ctx) {
105*6dbdd20aSAndroid Build Coastguard Worker         fd_.Clear();
106*6dbdd20aSAndroid Build Coastguard Worker         ctx->RegisterInterested(fd_.fd());
107*6dbdd20aSAndroid Build Coastguard Worker         return PendingPollResult();
108*6dbdd20aSAndroid Build Coastguard Worker       })
109*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(2048)))
110*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(DonePollResult()));
111*6dbdd20aSAndroid Build Coastguard Worker   auto [handle, stream] =
112*6dbdd20aSAndroid Build Coastguard Worker       SpawnResultStream<int>(&task_runner_, [this]() mutable {
113*6dbdd20aSAndroid Build Coastguard Worker         return base::Stream<int>(std::move(stream_pollable_));
114*6dbdd20aSAndroid Build Coastguard Worker       });
115*6dbdd20aSAndroid Build Coastguard Worker   base::ignore_result(handle);
116*6dbdd20aSAndroid Build Coastguard Worker 
117*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
118*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(stream.PollNext(&ctx_).IsPending());
119*6dbdd20aSAndroid Build Coastguard Worker 
120*6dbdd20aSAndroid Build Coastguard Worker   fd_.Notify();
121*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
122*6dbdd20aSAndroid Build Coastguard Worker 
123*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 1024);
124*6dbdd20aSAndroid Build Coastguard Worker 
125*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
126*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(stream.PollNext(&ctx_).IsPending());
127*6dbdd20aSAndroid Build Coastguard Worker 
128*6dbdd20aSAndroid Build Coastguard Worker   fd_.Notify();
129*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
130*6dbdd20aSAndroid Build Coastguard Worker 
131*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 2048);
132*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(stream.PollNext(&ctx_).IsDone());
133*6dbdd20aSAndroid Build Coastguard Worker }
134*6dbdd20aSAndroid Build Coastguard Worker 
TEST_F(SpawnUnittest,SpawnStreamDropStream)135*6dbdd20aSAndroid Build Coastguard Worker TEST_F(SpawnUnittest, SpawnStreamDropStream) {
136*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_CALL(*stream_pollable_, PollNext(_))
137*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce([this](PollContext* ctx) {
138*6dbdd20aSAndroid Build Coastguard Worker         fd_.Clear();
139*6dbdd20aSAndroid Build Coastguard Worker         ctx->RegisterInterested(fd_.fd());
140*6dbdd20aSAndroid Build Coastguard Worker         return PendingPollResult();
141*6dbdd20aSAndroid Build Coastguard Worker       })
142*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(1)))
143*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(2)))
144*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(4)))
145*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(8)))
146*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(16)))
147*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(32)))
148*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(64)))
149*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(128)))
150*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(256)))
151*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(512)))
152*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(DonePollResult()));
153*6dbdd20aSAndroid Build Coastguard Worker 
154*6dbdd20aSAndroid Build Coastguard Worker   auto [handle, stream] =
155*6dbdd20aSAndroid Build Coastguard Worker       SpawnResultStream<int>(&task_runner_, [this]() mutable {
156*6dbdd20aSAndroid Build Coastguard Worker         return base::Stream<int>(std::move(stream_pollable_));
157*6dbdd20aSAndroid Build Coastguard Worker       });
158*6dbdd20aSAndroid Build Coastguard Worker   base::ignore_result(handle);
159*6dbdd20aSAndroid Build Coastguard Worker 
160*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
161*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(stream.PollNext(&ctx_).IsPending());
162*6dbdd20aSAndroid Build Coastguard Worker 
163*6dbdd20aSAndroid Build Coastguard Worker   fd_.Notify();
164*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
165*6dbdd20aSAndroid Build Coastguard Worker 
166*6dbdd20aSAndroid Build Coastguard Worker   // We should get the first 4 elements and then nothing more: this corresponds
167*6dbdd20aSAndroid Build Coastguard Worker   // to the internal channel buffer size being 4.
168*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 1);
169*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 2);
170*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 4);
171*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 8);
172*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(stream.PollNext(&ctx_).IsPending());
173*6dbdd20aSAndroid Build Coastguard Worker 
174*6dbdd20aSAndroid Build Coastguard Worker   // Should fill up a bunch more elements.
175*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
176*6dbdd20aSAndroid Build Coastguard Worker 
177*6dbdd20aSAndroid Build Coastguard Worker   // Drop the stream.
178*6dbdd20aSAndroid Build Coastguard Worker   Drop(std::move(stream));
179*6dbdd20aSAndroid Build Coastguard Worker 
180*6dbdd20aSAndroid Build Coastguard Worker   // This should complete the stream.
181*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
182*6dbdd20aSAndroid Build Coastguard Worker 
183*6dbdd20aSAndroid Build Coastguard Worker   // Drop the handle and ensure any resulting is completed.
184*6dbdd20aSAndroid Build Coastguard Worker   Drop(std::move(handle));
185*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilIdle();
186*6dbdd20aSAndroid Build Coastguard Worker }
187*6dbdd20aSAndroid Build Coastguard Worker 
TEST_F(SpawnUnittest,SpawnStreamDropHandle)188*6dbdd20aSAndroid Build Coastguard Worker TEST_F(SpawnUnittest, SpawnStreamDropHandle) {
189*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_CALL(*stream_pollable_, PollNext(_))
190*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce([this](PollContext* ctx) {
191*6dbdd20aSAndroid Build Coastguard Worker         fd_.Clear();
192*6dbdd20aSAndroid Build Coastguard Worker         ctx->RegisterInterested(fd_.fd());
193*6dbdd20aSAndroid Build Coastguard Worker         return PendingPollResult();
194*6dbdd20aSAndroid Build Coastguard Worker       })
195*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(1)))
196*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(2)))
197*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(4)))
198*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(8)))
199*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(16)))
200*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(32)))
201*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(64)))
202*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(StreamPollResult<int>(128)))
203*6dbdd20aSAndroid Build Coastguard Worker       .WillOnce(Return(DonePollResult()));
204*6dbdd20aSAndroid Build Coastguard Worker 
205*6dbdd20aSAndroid Build Coastguard Worker   base::TestTaskRunner task_runner;
206*6dbdd20aSAndroid Build Coastguard Worker   auto [handle, stream] =
207*6dbdd20aSAndroid Build Coastguard Worker       SpawnResultStream<int>(&task_runner, [this]() mutable {
208*6dbdd20aSAndroid Build Coastguard Worker         return base::Stream<int>(std::move(stream_pollable_));
209*6dbdd20aSAndroid Build Coastguard Worker       });
210*6dbdd20aSAndroid Build Coastguard Worker   base::ignore_result(handle);
211*6dbdd20aSAndroid Build Coastguard Worker 
212*6dbdd20aSAndroid Build Coastguard Worker   task_runner.RunUntilIdle();
213*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(stream.PollNext(&ctx_).IsPending());
214*6dbdd20aSAndroid Build Coastguard Worker 
215*6dbdd20aSAndroid Build Coastguard Worker   fd_.Notify();
216*6dbdd20aSAndroid Build Coastguard Worker   task_runner.RunUntilIdle();
217*6dbdd20aSAndroid Build Coastguard Worker 
218*6dbdd20aSAndroid Build Coastguard Worker   // We should get the first 4 elements and then nothing more: this corresponds
219*6dbdd20aSAndroid Build Coastguard Worker   // to the internal channel buffer size being 4.
220*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 1);
221*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 2);
222*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 4);
223*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 8);
224*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(stream.PollNext(&ctx_).IsPending());
225*6dbdd20aSAndroid Build Coastguard Worker 
226*6dbdd20aSAndroid Build Coastguard Worker   // Should fill up a bunch more elements.
227*6dbdd20aSAndroid Build Coastguard Worker   task_runner.RunUntilIdle();
228*6dbdd20aSAndroid Build Coastguard Worker 
229*6dbdd20aSAndroid Build Coastguard Worker   // Drop the handle.
230*6dbdd20aSAndroid Build Coastguard Worker   Drop(std::move(handle));
231*6dbdd20aSAndroid Build Coastguard Worker 
232*6dbdd20aSAndroid Build Coastguard Worker   // We should just get the next four buffered elements and the stream should
233*6dbdd20aSAndroid Build Coastguard Worker   // complete.
234*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 16);
235*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 32);
236*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 64);
237*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(stream.PollNext(&ctx_).item(), 128);
238*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(stream.PollNext(&ctx_).IsDone());
239*6dbdd20aSAndroid Build Coastguard Worker }
240*6dbdd20aSAndroid Build Coastguard Worker 
241*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
242*6dbdd20aSAndroid Build Coastguard Worker }  // namespace base
243*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
244