xref: /aosp_15_r20/external/pigweed/pw_async/fake_dispatcher_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2022 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker #include "pw_async/fake_dispatcher.h"
15*61c4878aSAndroid Build Coastguard Worker 
16*61c4878aSAndroid Build Coastguard Worker #include "pw_chrono/system_clock.h"
17*61c4878aSAndroid Build Coastguard Worker #include "pw_containers/vector.h"
18*61c4878aSAndroid Build Coastguard Worker #include "pw_string/to_string.h"
19*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
20*61c4878aSAndroid Build Coastguard Worker 
21*61c4878aSAndroid Build Coastguard Worker #define ASSERT_CANCELLED(status) ASSERT_EQ(Status::Cancelled(), status)
22*61c4878aSAndroid Build Coastguard Worker 
23*61c4878aSAndroid Build Coastguard Worker using namespace std::chrono_literals;
24*61c4878aSAndroid Build Coastguard Worker 
25*61c4878aSAndroid Build Coastguard Worker struct CallCounts {
26*61c4878aSAndroid Build Coastguard Worker   int ok = 0;
27*61c4878aSAndroid Build Coastguard Worker   int cancelled = 0;
operator ==CallCounts28*61c4878aSAndroid Build Coastguard Worker   bool operator==(const CallCounts& other) const {
29*61c4878aSAndroid Build Coastguard Worker     return ok == other.ok && cancelled == other.cancelled;
30*61c4878aSAndroid Build Coastguard Worker   }
31*61c4878aSAndroid Build Coastguard Worker };
32*61c4878aSAndroid Build Coastguard Worker 
33*61c4878aSAndroid Build Coastguard Worker namespace pw {
34*61c4878aSAndroid Build Coastguard Worker template <>
ToString(const CallCounts & value,span<char> buffer)35*61c4878aSAndroid Build Coastguard Worker StatusWithSize ToString<CallCounts>(const CallCounts& value,
36*61c4878aSAndroid Build Coastguard Worker                                     span<char> buffer) {
37*61c4878aSAndroid Build Coastguard Worker   return string::Format(buffer,
38*61c4878aSAndroid Build Coastguard Worker                         "CallCounts {.ok = %d, .cancelled = %d}",
39*61c4878aSAndroid Build Coastguard Worker                         value.ok,
40*61c4878aSAndroid Build Coastguard Worker                         value.cancelled);
41*61c4878aSAndroid Build Coastguard Worker }
42*61c4878aSAndroid Build Coastguard Worker }  // namespace pw
43*61c4878aSAndroid Build Coastguard Worker 
44*61c4878aSAndroid Build Coastguard Worker namespace pw::async::test {
45*61c4878aSAndroid Build Coastguard Worker namespace {
46*61c4878aSAndroid Build Coastguard Worker 
47*61c4878aSAndroid Build Coastguard Worker struct CallCounter {
48*61c4878aSAndroid Build Coastguard Worker   CallCounts counts;
fnpw::async::test::__anon3d08e71e0111::CallCounter49*61c4878aSAndroid Build Coastguard Worker   auto fn() {
50*61c4878aSAndroid Build Coastguard Worker     return [this](Context&, Status status) {
51*61c4878aSAndroid Build Coastguard Worker       if (status.ok()) {
52*61c4878aSAndroid Build Coastguard Worker         this->counts.ok++;
53*61c4878aSAndroid Build Coastguard Worker       } else if (status.IsCancelled()) {
54*61c4878aSAndroid Build Coastguard Worker         this->counts.cancelled++;
55*61c4878aSAndroid Build Coastguard Worker       }
56*61c4878aSAndroid Build Coastguard Worker     };
57*61c4878aSAndroid Build Coastguard Worker   }
58*61c4878aSAndroid Build Coastguard Worker };
59*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,UnpostedTasksDontRun)60*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, UnpostedTasksDontRun) {
61*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
62*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
63*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
64*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
65*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{});
66*61c4878aSAndroid Build Coastguard Worker }
67*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,PostedTaskRunsOnce)68*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, PostedTaskRunsOnce) {
69*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
70*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
71*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
72*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
73*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
74*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.ok = 1});
75*61c4878aSAndroid Build Coastguard Worker }
76*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,TaskPostedTwiceBeforeRunningRunsOnce)77*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, TaskPostedTwiceBeforeRunningRunsOnce) {
78*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
79*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
80*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
81*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
82*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
83*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
84*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.ok = 1});
85*61c4878aSAndroid Build Coastguard Worker }
86*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,TaskRepostedAfterRunningRunsTwice)87*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, TaskRepostedAfterRunningRunsTwice) {
88*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
89*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
90*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
91*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
92*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
93*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.ok = 1});
94*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
95*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
96*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.ok = 2});
97*61c4878aSAndroid Build Coastguard Worker }
98*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,TwoPostedTasksEachRunOnce)99*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, TwoPostedTasksEachRunOnce) {
100*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
101*61c4878aSAndroid Build Coastguard Worker   CallCounter counter_1;
102*61c4878aSAndroid Build Coastguard Worker   Task task_1(counter_1.fn());
103*61c4878aSAndroid Build Coastguard Worker   CallCounter counter_2;
104*61c4878aSAndroid Build Coastguard Worker   Task task_2(counter_2.fn());
105*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task_1);
106*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task_2);
107*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
108*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter_1.counts, CallCounts{.ok = 1});
109*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter_2.counts, CallCounts{.ok = 1});
110*61c4878aSAndroid Build Coastguard Worker }
111*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,PostedTasksRunInOrderForFairness)112*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, PostedTasksRunInOrderForFairness) {
113*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
114*61c4878aSAndroid Build Coastguard Worker   pw::Vector<uint8_t, 3> task_run_order;
115*61c4878aSAndroid Build Coastguard Worker   Task task_1([&task_run_order](auto...) { task_run_order.push_back(1); });
116*61c4878aSAndroid Build Coastguard Worker   Task task_2([&task_run_order](auto...) { task_run_order.push_back(2); });
117*61c4878aSAndroid Build Coastguard Worker   Task task_3([&task_run_order](auto...) { task_run_order.push_back(3); });
118*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task_1);
119*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task_2);
120*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task_3);
121*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
122*61c4878aSAndroid Build Coastguard Worker   pw::Vector<uint8_t, 3> expected_run_order({1, 2, 3});
123*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(task_run_order, expected_run_order);
124*61c4878aSAndroid Build Coastguard Worker }
125*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,RequestStopQueuesPreviouslyPostedTaskWithCancel)126*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, RequestStopQueuesPreviouslyPostedTaskWithCancel) {
127*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
128*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
129*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
130*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
131*61c4878aSAndroid Build Coastguard Worker   dispatcher.RequestStop();
132*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
133*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.cancelled = 1});
134*61c4878aSAndroid Build Coastguard Worker }
135*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,RequestStopQueuesNewlyPostedTaskWithCancel)136*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, RequestStopQueuesNewlyPostedTaskWithCancel) {
137*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
138*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
139*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
140*61c4878aSAndroid Build Coastguard Worker   dispatcher.RequestStop();
141*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
142*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
143*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.cancelled = 1});
144*61c4878aSAndroid Build Coastguard Worker }
145*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,RunUntilIdleDoesNotRunFutureTask)146*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, RunUntilIdleDoesNotRunFutureTask) {
147*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
148*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
149*61c4878aSAndroid Build Coastguard Worker   // Should not run; RunUntilIdle() does not advance time.
150*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
151*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task, chrono::SystemClock::for_at_least(1ms));
152*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
153*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{});
154*61c4878aSAndroid Build Coastguard Worker }
155*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,PostAfterRunsTasksInSequence)156*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, PostAfterRunsTasksInSequence) {
157*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
158*61c4878aSAndroid Build Coastguard Worker   pw::Vector<uint8_t, 3> task_run_order;
159*61c4878aSAndroid Build Coastguard Worker   Task task_1([&task_run_order](auto...) { task_run_order.push_back(1); });
160*61c4878aSAndroid Build Coastguard Worker   Task task_2([&task_run_order](auto...) { task_run_order.push_back(2); });
161*61c4878aSAndroid Build Coastguard Worker   Task task_3([&task_run_order](auto...) { task_run_order.push_back(3); });
162*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task_1, chrono::SystemClock::for_at_least(50ms));
163*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task_2, chrono::SystemClock::for_at_least(25ms));
164*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task_3, chrono::SystemClock::for_at_least(100ms));
165*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunFor(chrono::SystemClock::for_at_least(125ms));
166*61c4878aSAndroid Build Coastguard Worker   pw::Vector<uint8_t, 3> expected_run_order({2, 1, 3});
167*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(task_run_order, expected_run_order);
168*61c4878aSAndroid Build Coastguard Worker }
169*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,PostAfterWithEarlierTimeRunsSooner)170*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, PostAfterWithEarlierTimeRunsSooner) {
171*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
172*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
173*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
174*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task, chrono::SystemClock::for_at_least(100ms));
175*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task, chrono::SystemClock::for_at_least(50ms));
176*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunFor(chrono::SystemClock::for_at_least(60ms));
177*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.ok = 1});
178*61c4878aSAndroid Build Coastguard Worker }
179*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,PostAfterWithLaterTimeRunsSooner)180*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, PostAfterWithLaterTimeRunsSooner) {
181*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
182*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
183*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
184*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task, chrono::SystemClock::for_at_least(50ms));
185*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task, chrono::SystemClock::for_at_least(100ms));
186*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunFor(chrono::SystemClock::for_at_least(60ms));
187*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.ok = 1});
188*61c4878aSAndroid Build Coastguard Worker }
189*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,PostThenPostAfterRunsImmediately)190*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, PostThenPostAfterRunsImmediately) {
191*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
192*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
193*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
194*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
195*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task, chrono::SystemClock::for_at_least(50ms));
196*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
197*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.ok = 1});
198*61c4878aSAndroid Build Coastguard Worker }
199*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,PostAfterThenPostRunsImmediately)200*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, PostAfterThenPostRunsImmediately) {
201*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
202*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
203*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
204*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task, chrono::SystemClock::for_at_least(50ms));
205*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
206*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
207*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.ok = 1});
208*61c4878aSAndroid Build Coastguard Worker }
209*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,CancelAfterPostStopsTaskFromRunning)210*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, CancelAfterPostStopsTaskFromRunning) {
211*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
212*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
213*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
214*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
215*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(dispatcher.Cancel(task));
216*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
217*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{});
218*61c4878aSAndroid Build Coastguard Worker }
219*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,CancelAfterPostAfterStopsTaskFromRunning)220*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, CancelAfterPostAfterStopsTaskFromRunning) {
221*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
222*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
223*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
224*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task, chrono::SystemClock::for_at_least(50ms));
225*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(dispatcher.Cancel(task));
226*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunFor(chrono::SystemClock::for_at_least(60ms));
227*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{});
228*61c4878aSAndroid Build Coastguard Worker }
229*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,CancelAfterPostAndPostAfterStopsTaskFromRunning)230*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, CancelAfterPostAndPostAfterStopsTaskFromRunning) {
231*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
232*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
233*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
234*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
235*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task, chrono::SystemClock::for_at_least(50ms));
236*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(dispatcher.Cancel(task));
237*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunFor(chrono::SystemClock::for_at_least(60ms));
238*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{});
239*61c4878aSAndroid Build Coastguard Worker }
240*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,PostAgainAfterCancelRuns)241*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, PostAgainAfterCancelRuns) {
242*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
243*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
244*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
245*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
246*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(dispatcher.Cancel(task));
247*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
248*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
249*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.ok = 1});
250*61c4878aSAndroid Build Coastguard Worker }
251*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,CancelWithoutPostReturnsFalse)252*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, CancelWithoutPostReturnsFalse) {
253*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
254*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
255*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
256*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(dispatcher.Cancel(task));
257*61c4878aSAndroid Build Coastguard Worker }
258*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,CancelAfterRunningReturnsFalse)259*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, CancelAfterRunningReturnsFalse) {
260*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
261*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
262*61c4878aSAndroid Build Coastguard Worker   Task task(counter.fn());
263*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
264*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
265*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(counter.counts, CallCounts{.ok = 1});
266*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(dispatcher.Cancel(task));
267*61c4878aSAndroid Build Coastguard Worker }
268*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,CancelInsideOtherTaskCancelsTaskWithoutRunningIt)269*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, CancelInsideOtherTaskCancelsTaskWithoutRunningIt) {
270*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
271*61c4878aSAndroid Build Coastguard Worker 
272*61c4878aSAndroid Build Coastguard Worker   CallCounter cancelled_task_counter;
273*61c4878aSAndroid Build Coastguard Worker   Task cancelled_task(cancelled_task_counter.fn());
274*61c4878aSAndroid Build Coastguard Worker 
275*61c4878aSAndroid Build Coastguard Worker   Task canceling_task([&cancelled_task](Context& c, Status status) {
276*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(status);
277*61c4878aSAndroid Build Coastguard Worker     ASSERT_TRUE(c.dispatcher->Cancel(cancelled_task));
278*61c4878aSAndroid Build Coastguard Worker   });
279*61c4878aSAndroid Build Coastguard Worker 
280*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(canceling_task);
281*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(cancelled_task);
282*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
283*61c4878aSAndroid Build Coastguard Worker 
284*61c4878aSAndroid Build Coastguard Worker   // NOTE:  the cancelled task is *not* run with `Cancel`.
285*61c4878aSAndroid Build Coastguard Worker   // This is likely to produce strange behavior, and this contract should
286*61c4878aSAndroid Build Coastguard Worker   // be revisited and carefully documented.
287*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(cancelled_task_counter.counts, CallCounts{});
288*61c4878aSAndroid Build Coastguard Worker }
289*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,CancelInsideCurrentTaskFails)290*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, CancelInsideCurrentTaskFails) {
291*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
292*61c4878aSAndroid Build Coastguard Worker 
293*61c4878aSAndroid Build Coastguard Worker   Task self_cancel_task;
294*61c4878aSAndroid Build Coastguard Worker   self_cancel_task.set_function([&self_cancel_task](Context& c, Status status) {
295*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(status);
296*61c4878aSAndroid Build Coastguard Worker     ASSERT_FALSE(c.dispatcher->Cancel(self_cancel_task));
297*61c4878aSAndroid Build Coastguard Worker   });
298*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(self_cancel_task);
299*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
300*61c4878aSAndroid Build Coastguard Worker }
301*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,RequestStopInsideOtherTaskCancelsOtherTask)302*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, RequestStopInsideOtherTaskCancelsOtherTask) {
303*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
304*61c4878aSAndroid Build Coastguard Worker 
305*61c4878aSAndroid Build Coastguard Worker   // This task is never executed and is cleaned up in RequestStop().
306*61c4878aSAndroid Build Coastguard Worker   CallCounter task_counter;
307*61c4878aSAndroid Build Coastguard Worker   Task task(task_counter.fn());
308*61c4878aSAndroid Build Coastguard Worker 
309*61c4878aSAndroid Build Coastguard Worker   int stop_count = 0;
310*61c4878aSAndroid Build Coastguard Worker   Task stop_task([&stop_count]([[maybe_unused]] Context& c, Status status) {
311*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(status);
312*61c4878aSAndroid Build Coastguard Worker     stop_count++;
313*61c4878aSAndroid Build Coastguard Worker     static_cast<FakeDispatcher*>(c.dispatcher)->RequestStop();
314*61c4878aSAndroid Build Coastguard Worker   });
315*61c4878aSAndroid Build Coastguard Worker 
316*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(stop_task);
317*61c4878aSAndroid Build Coastguard Worker   dispatcher.Post(task);
318*61c4878aSAndroid Build Coastguard Worker 
319*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunUntilIdle();
320*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(stop_count, 1);
321*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(task_counter.counts, CallCounts{.cancelled = 1});
322*61c4878aSAndroid Build Coastguard Worker }
323*61c4878aSAndroid Build Coastguard Worker 
TEST(FakeDispatcher,TasksCancelledByDispatcherDestructor)324*61c4878aSAndroid Build Coastguard Worker TEST(FakeDispatcher, TasksCancelledByDispatcherDestructor) {
325*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
326*61c4878aSAndroid Build Coastguard Worker   Task task0(counter.fn()), task1(counter.fn()), task2(counter.fn());
327*61c4878aSAndroid Build Coastguard Worker 
328*61c4878aSAndroid Build Coastguard Worker   {
329*61c4878aSAndroid Build Coastguard Worker     FakeDispatcher dispatcher;
330*61c4878aSAndroid Build Coastguard Worker     dispatcher.PostAfter(task0, chrono::SystemClock::for_at_least(10s));
331*61c4878aSAndroid Build Coastguard Worker     dispatcher.PostAfter(task1, chrono::SystemClock::for_at_least(10s));
332*61c4878aSAndroid Build Coastguard Worker     dispatcher.PostAfter(task2, chrono::SystemClock::for_at_least(10s));
333*61c4878aSAndroid Build Coastguard Worker   }
334*61c4878aSAndroid Build Coastguard Worker 
335*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(counter.counts, CallCounts{.cancelled = 3});
336*61c4878aSAndroid Build Coastguard Worker }
337*61c4878aSAndroid Build Coastguard Worker 
TEST(DispatcherBasic,TasksCancelledByRunFor)338*61c4878aSAndroid Build Coastguard Worker TEST(DispatcherBasic, TasksCancelledByRunFor) {
339*61c4878aSAndroid Build Coastguard Worker   FakeDispatcher dispatcher;
340*61c4878aSAndroid Build Coastguard Worker   CallCounter counter;
341*61c4878aSAndroid Build Coastguard Worker   Task task0(counter.fn()), task1(counter.fn()), task2(counter.fn());
342*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task0, chrono::SystemClock::for_at_least(10s));
343*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task1, chrono::SystemClock::for_at_least(10s));
344*61c4878aSAndroid Build Coastguard Worker   dispatcher.PostAfter(task2, chrono::SystemClock::for_at_least(10s));
345*61c4878aSAndroid Build Coastguard Worker 
346*61c4878aSAndroid Build Coastguard Worker   dispatcher.RequestStop();
347*61c4878aSAndroid Build Coastguard Worker   dispatcher.RunFor(chrono::SystemClock::for_at_least(5s));
348*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(counter.counts, CallCounts{.cancelled = 3});
349*61c4878aSAndroid Build Coastguard Worker }
350*61c4878aSAndroid Build Coastguard Worker 
351*61c4878aSAndroid Build Coastguard Worker }  // namespace
352*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::async::test
353