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