1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  *
7  */
8 
9 #include <quic/common/FunctionLooper.h>
10 
11 #include <gtest/gtest.h>
12 
13 using namespace std;
14 using namespace folly;
15 using namespace testing;
16 
17 namespace quic {
18 namespace test {
19 
20 class FunctionLooperTest : public Test {};
21 
TEST(FunctionLooperTest,LooperNotRunning)22 TEST(FunctionLooperTest, LooperNotRunning) {
23   EventBase evb;
24   bool called = false;
25   auto func = [&](bool) { called = true; };
26   FunctionLooper::Ptr looper(
27       new FunctionLooper(&evb, std::move(func), LooperType::ReadLooper));
28   evb.loopOnce();
29   EXPECT_FALSE(called);
30   evb.loopOnce();
31   EXPECT_FALSE(called);
32   EXPECT_FALSE(looper->isRunning());
33 }
34 
TEST(FunctionLooperTest,LooperStarted)35 TEST(FunctionLooperTest, LooperStarted) {
36   EventBase evb;
37   bool called = false;
38   auto func = [&](bool) { called = true; };
39   FunctionLooper::Ptr looper(
40       new FunctionLooper(&evb, std::move(func), LooperType::ReadLooper));
41   looper->run();
42   EXPECT_TRUE(looper->isRunning());
43   evb.loopOnce();
44   EXPECT_TRUE(called);
45   called = false;
46   evb.loopOnce();
47   EXPECT_TRUE(called);
48 }
49 
TEST(FunctionLooperTest,LooperStopped)50 TEST(FunctionLooperTest, LooperStopped) {
51   EventBase evb;
52   bool called = false;
53   auto func = [&](bool) { called = true; };
54   FunctionLooper::Ptr looper(
55       new FunctionLooper(&evb, std::move(func), LooperType::ReadLooper));
56   looper->run();
57   evb.loopOnce();
58   EXPECT_TRUE(called);
59   called = false;
60   looper->stop();
61   EXPECT_FALSE(looper->isRunning());
62   evb.loopOnce();
63   EXPECT_FALSE(called);
64 }
65 
TEST(FunctionLooperTest,LooperRestarted)66 TEST(FunctionLooperTest, LooperRestarted) {
67   EventBase evb;
68   bool called = false;
69   auto func = [&](bool) { called = true; };
70   FunctionLooper::Ptr looper(
71       new FunctionLooper(&evb, std::move(func), LooperType::ReadLooper));
72   looper->run();
73   evb.loopOnce();
74   EXPECT_TRUE(called);
75   called = false;
76   looper->stop();
77   evb.loopOnce();
78   EXPECT_FALSE(called);
79   looper->run();
80   EXPECT_TRUE(looper->isRunning());
81   evb.loopOnce();
82   EXPECT_TRUE(called);
83 }
84 
TEST(FunctionLooperTest,DestroyLooperDuringFunc)85 TEST(FunctionLooperTest, DestroyLooperDuringFunc) {
86   EventBase evb;
87   bool called = false;
88   FunctionLooper::Ptr* looperPtr = nullptr;
89 
90   auto func = [&](bool) {
91     called = true;
92     *looperPtr = nullptr;
93   };
94   FunctionLooper::Ptr looper(
95       new FunctionLooper(&evb, std::move(func), LooperType::ReadLooper));
96   looperPtr = &looper;
97 
98   looper->run();
99   evb.loopOnce();
100   EXPECT_TRUE(called);
101   EXPECT_EQ(looper, nullptr);
102 }
103 
TEST(FunctionLooperTest,StopLooperDuringFunc)104 TEST(FunctionLooperTest, StopLooperDuringFunc) {
105   EventBase evb;
106   bool called = false;
107   FunctionLooper::Ptr* looperPtr = nullptr;
108 
109   auto func = [&](bool) {
110     called = true;
111     (*looperPtr)->stop();
112   };
113   FunctionLooper::Ptr looper(
114       new FunctionLooper(&evb, std::move(func), LooperType::ReadLooper));
115   looperPtr = &looper;
116 
117   looper->run();
118   evb.loopOnce();
119   EXPECT_TRUE(called);
120   called = false;
121   evb.loopOnce();
122   EXPECT_FALSE(called);
123 }
124 
TEST(FunctionLooperTest,RunLooperDuringFunc)125 TEST(FunctionLooperTest, RunLooperDuringFunc) {
126   EventBase evb;
127   bool called = false;
128   FunctionLooper::Ptr* looperPtr = nullptr;
129 
130   auto func = [&](bool) {
131     called = true;
132     (*looperPtr)->run();
133   };
134   FunctionLooper::Ptr looper(
135       new FunctionLooper(&evb, std::move(func), LooperType::ReadLooper));
136   looperPtr = &looper;
137 
138   looper->run();
139   evb.loopOnce();
140   EXPECT_TRUE(called);
141   called = false;
142   evb.loopOnce();
143   EXPECT_TRUE(called);
144 }
145 
TEST(FunctionLooperTest,DetachStopsLooper)146 TEST(FunctionLooperTest, DetachStopsLooper) {
147   EventBase evb;
148   bool called = false;
149   auto func = [&](bool) { called = true; };
150   FunctionLooper::Ptr looper(
151       new FunctionLooper(&evb, std::move(func), LooperType::ReadLooper));
152   looper->run();
153   EXPECT_TRUE(looper->isRunning());
154   looper->detachEventBase();
155   EXPECT_FALSE(looper->isRunning());
156   looper->attachEventBase(&evb);
157   EXPECT_FALSE(looper->isRunning());
158 }
159 
TEST(FunctionLooperTest,PacingOnce)160 TEST(FunctionLooperTest, PacingOnce) {
161   EventBase evb;
162   TimerHighRes::SharedPtr pacingTimer(TimerHighRes::newTimer(&evb, 1ms));
163   std::vector<bool> fromTimerVec;
164   auto func = [&](bool fromTimer) { fromTimerVec.push_back(fromTimer); };
165   bool firstTime = true;
166   auto pacingFunc = [&]() -> auto {
167     if (firstTime) {
168       firstTime = false;
169       return 3600000ms;
170     }
171     return std::chrono::milliseconds::zero();
172   };
173   FunctionLooper::Ptr looper(
174       new FunctionLooper(&evb, std::move(func), LooperType::ReadLooper));
175   looper->setPacingTimer(std::move(pacingTimer));
176   looper->setPacingFunction(std::move(pacingFunc));
177   looper->run();
178   evb.loopOnce();
179   EXPECT_EQ(1, fromTimerVec.size());
180   EXPECT_FALSE(fromTimerVec.back());
181   EXPECT_TRUE(looper->isScheduled());
182   looper->timeoutExpired();
183   EXPECT_EQ(2, fromTimerVec.size());
184   EXPECT_TRUE(fromTimerVec.back());
185   looper->stop();
186 }
187 
TEST(FunctionLooperTest,KeepPacing)188 TEST(FunctionLooperTest, KeepPacing) {
189   EventBase evb;
190   TimerHighRes::SharedPtr pacingTimer(TimerHighRes::newTimer(&evb, 1ms));
191   std::vector<bool> fromTimerVec;
192   auto func = [&](bool fromTimer) { fromTimerVec.push_back(fromTimer); };
193   bool stopPacing = false;
194   auto pacingFunc = [&]() -> auto {
195     if (stopPacing) {
196       return std::chrono::milliseconds::zero();
197     }
198     return 3600000ms;
199   };
200   FunctionLooper::Ptr looper(
201       new FunctionLooper(&evb, std::move(func), LooperType::ReadLooper));
202   looper->setPacingTimer(std::move(pacingTimer));
203   looper->setPacingFunction(std::move(pacingFunc));
204   looper->run();
205   evb.loopOnce();
206   EXPECT_EQ(1, fromTimerVec.size());
207   EXPECT_FALSE(fromTimerVec.back());
208   EXPECT_TRUE(looper->isScheduled());
209 
210   looper->cancelTimeout();
211   EXPECT_FALSE(looper->isScheduled());
212   looper->timeoutExpired();
213   EXPECT_EQ(2, fromTimerVec.size());
214   EXPECT_TRUE(fromTimerVec.back());
215   EXPECT_TRUE(looper->isScheduled());
216 
217   looper->cancelTimeout();
218   EXPECT_FALSE(looper->isScheduled());
219   looper->timeoutExpired();
220   EXPECT_EQ(3, fromTimerVec.size());
221   EXPECT_TRUE(fromTimerVec.back());
222   EXPECT_TRUE(looper->isScheduled());
223 
224   stopPacing = true;
225   looper->cancelTimeout();
226   EXPECT_FALSE(looper->isScheduled());
227   looper->timeoutExpired();
228   EXPECT_EQ(4, fromTimerVec.size());
229   EXPECT_TRUE(fromTimerVec.back());
230   EXPECT_FALSE(looper->isScheduled());
231 
232   looper->stop();
233 }
234 
TEST(FunctionLooperTest,TimerTickSize)235 TEST(FunctionLooperTest, TimerTickSize) {
236   EventBase evb;
237   TimerHighRes::SharedPtr pacingTimer(TimerHighRes::newTimer(&evb, 123ms));
238   FunctionLooper::Ptr looper(new FunctionLooper(
239       &evb, [&](bool) {}, LooperType::ReadLooper));
240   looper->setPacingTimer(std::move(pacingTimer));
241   EXPECT_EQ(123ms, looper->getTimerTickInterval());
242 }
243 
TEST(FunctionLooperTest,TimerTickSizeAfterNewEvb)244 TEST(FunctionLooperTest, TimerTickSizeAfterNewEvb) {
245   EventBase evb;
246   TimerHighRes::SharedPtr pacingTimer(TimerHighRes::newTimer(&evb, 123ms));
247   FunctionLooper::Ptr looper(new FunctionLooper(
248       &evb, [&](bool) {}, LooperType::ReadLooper));
249   looper->setPacingTimer(std::move(pacingTimer));
250   EXPECT_EQ(123ms, looper->getTimerTickInterval());
251   looper->detachEventBase();
252   EventBase evb2;
253   looper->attachEventBase(&evb2);
254   EXPECT_EQ(123ms, looper->getTimerTickInterval());
255 }
256 
TEST(FunctionLooperTest,NoLoopCallbackInPacingMode)257 TEST(FunctionLooperTest, NoLoopCallbackInPacingMode) {
258   EventBase evb;
259   TimerHighRes::SharedPtr pacingTimer(TimerHighRes::newTimer(&evb, 1ms));
260   uint32_t loopCallbackRunCounter = 0, pacingRunCounter = 0;
261   auto runFunc = [&](bool fromTimer) {
262     if (!fromTimer) {
263       loopCallbackRunCounter++;
264     } else {
265       pacingRunCounter++;
266     }
267   };
268   auto pacingFunc = [&]() { return 3600000ms; };
269   FunctionLooper::Ptr looper(
270       new FunctionLooper(&evb, std::move(runFunc), LooperType::ReadLooper));
271   looper->setPacingTimer(std::move(pacingTimer));
272   looper->setPacingFunction(std::move(pacingFunc));
273   // bootstrap the looper
274   looper->run();
275   // this loop will schedule pacer not looper:
276   evb.loopOnce();
277   EXPECT_TRUE(looper->isScheduled());
278   EXPECT_FALSE(looper->isLoopCallbackScheduled());
279   looper->stop();
280 }
281 
TEST(FunctionLooperTest,RunConditions)282 TEST(FunctionLooperTest, RunConditions) {
283   EventBase evb;
284   TimerHighRes::SharedPtr pacingTimer(TimerHighRes::newTimer(&evb, 1ms));
285   uint32_t loopCallbackRunCounter = 0, pacingRunCounter = 0;
286   FunctionLooper::Ptr* looperPtr = nullptr;
287   auto runFunc = [&](bool fromTimer) {
288     if (!fromTimer) {
289       loopCallbackRunCounter++;
290     } else {
291       pacingRunCounter++;
292     }
293     (*looperPtr)->run();
294   };
295   auto pacingFunc = [&]() { return 3600000ms; };
296   FunctionLooper::Ptr looper(
297       new FunctionLooper(&evb, std::move(runFunc), LooperType::ReadLooper));
298   looperPtr = &looper;
299   looper->setPacingTimer(std::move(pacingTimer));
300   looper->setPacingFunction(std::move(pacingFunc));
301   // Nothing scheduled yet, this run will loop
302   looper->run();
303   evb.loopOnce();
304   EXPECT_EQ(0, pacingRunCounter);
305   EXPECT_EQ(1, loopCallbackRunCounter);
306 
307   // run() inside runFunc didn't have effect. Loop again won't run anything:
308   evb.loopOnce();
309   EXPECT_EQ(0, pacingRunCounter);
310   EXPECT_EQ(1, loopCallbackRunCounter);
311 
312   // Since pacing is scheduled, explicit run() outside of runFunc won't run
313   // either:
314   looper->run();
315   evb.loopOnce();
316   EXPECT_EQ(0, pacingRunCounter);
317   EXPECT_EQ(1, loopCallbackRunCounter);
318 
319   looper->stop();
320 }
321 } // namespace test
322 } // namespace quic
323