d4b24e0974cf567cb838d9620494ce3efac2232c
[folly.git] / folly / futures / test / ExecutorTest.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/Baton.h>
18 #include <folly/futures/Future.h>
19 #include <folly/futures/InlineExecutor.h>
20 #include <folly/futures/ManualExecutor.h>
21 #include <folly/futures/QueuedImmediateExecutor.h>
22 #include <folly/portability/GTest.h>
23
24 using namespace folly;
25
26 TEST(ManualExecutor, runIsStable) {
27   ManualExecutor x;
28   size_t count = 0;
29   auto f1 = [&]() { count++; };
30   auto f2 = [&]() { x.add(f1); x.add(f1); };
31   x.add(f2);
32   x.run();
33 }
34
35 TEST(ManualExecutor, scheduleDur) {
36   ManualExecutor x;
37   size_t count = 0;
38   std::chrono::milliseconds dur {10};
39   x.schedule([&]{ count++; }, dur);
40   EXPECT_EQ(count, 0);
41   x.run();
42   EXPECT_EQ(count, 0);
43   x.advance(dur/2);
44   EXPECT_EQ(count, 0);
45   x.advance(dur/2);
46   EXPECT_EQ(count, 1);
47 }
48
49 TEST(ManualExecutor, laterThingsDontBlockEarlierOnes) {
50   ManualExecutor x;
51   auto first = false;
52   std::chrono::milliseconds dur{10};
53   x.schedule([&] { first = true; }, dur);
54   x.schedule([] {}, 2 * dur);
55   EXPECT_FALSE(first);
56   x.advance(dur);
57   EXPECT_TRUE(first);
58 }
59
60 TEST(ManualExecutor, orderWillNotBeQuestioned) {
61   ManualExecutor x;
62   auto first = false;
63   auto second = false;
64   std::chrono::milliseconds dur{10};
65   x.schedule([&] { first = true; }, dur);
66   x.schedule([&] { second = true; }, 2 * dur);
67   EXPECT_FALSE(first);
68   EXPECT_FALSE(second);
69   x.advance(dur);
70   EXPECT_TRUE(first);
71   EXPECT_FALSE(second);
72   x.advance(dur);
73   EXPECT_TRUE(first);
74   EXPECT_TRUE(second);
75 }
76
77 TEST(ManualExecutor, evenWhenYouSkipAheadEventsRunInProperOrder) {
78   ManualExecutor x;
79   auto counter = 0;
80   auto first = 0;
81   auto second = 0;
82   std::chrono::milliseconds dur{10};
83   x.schedule([&] { first = ++counter; }, dur);
84   x.schedule([&] { second = ++counter; }, 2 * dur);
85   EXPECT_EQ(first, 0);
86   EXPECT_EQ(second, 0);
87   x.advance(3 * dur);
88   EXPECT_EQ(first, 1);
89   EXPECT_EQ(second, 2);
90 }
91
92 TEST(ManualExecutor, clockStartsAt0) {
93   ManualExecutor x;
94   EXPECT_EQ(x.now(), x.now().min());
95 }
96
97 TEST(ManualExecutor, scheduleAbs) {
98   ManualExecutor x;
99   size_t count = 0;
100   x.scheduleAt([&]{ count++; }, x.now() + std::chrono::milliseconds(10));
101   EXPECT_EQ(count, 0);
102   x.advance(std::chrono::milliseconds(10));
103   EXPECT_EQ(count, 1);
104 }
105
106 TEST(ManualExecutor, advanceTo) {
107   ManualExecutor x;
108   size_t count = 0;
109   x.scheduleAt([&]{ count++; }, std::chrono::steady_clock::now());
110   EXPECT_EQ(count, 0);
111   x.advanceTo(std::chrono::steady_clock::now());
112   EXPECT_EQ(count, 1);
113 }
114
115 TEST(ManualExecutor, advanceBack) {
116   ManualExecutor x;
117   size_t count = 0;
118   x.advance(std::chrono::microseconds(5));
119   x.schedule([&]{ count++; }, std::chrono::microseconds(6));
120   EXPECT_EQ(count, 0);
121   x.advanceTo(x.now() - std::chrono::microseconds(1));
122   EXPECT_EQ(count, 0);
123 }
124
125 TEST(ManualExecutor, advanceNeg) {
126   ManualExecutor x;
127   size_t count = 0;
128   x.advance(std::chrono::microseconds(5));
129   x.schedule([&]{ count++; }, std::chrono::microseconds(6));
130   EXPECT_EQ(count, 0);
131   x.advance(std::chrono::microseconds(-1));
132   EXPECT_EQ(count, 0);
133 }
134
135 TEST(ManualExecutor, waitForDoesNotDeadlock) {
136   ManualExecutor east, west;
137   folly::Baton<> baton;
138   auto f = makeFuture()
139     .via(&east)
140     .then([](Try<Unit>){ return makeFuture(); })
141     .via(&west);
142   std::thread t([&]{
143     baton.post();
144     west.waitFor(f);
145   });
146   baton.wait();
147   east.run();
148   t.join();
149 }
150
151 TEST(ManualExecutor, getViaDoesNotDeadlock) {
152   ManualExecutor east, west;
153   folly::Baton<> baton;
154   auto f = makeFuture().via(&east).then([](Try<Unit>) {
155     return makeFuture();
156   }).via(&west);
157   std::thread t([&] {
158     baton.post();
159     f.getVia(&west);
160   });
161   baton.wait();
162   east.run();
163   t.join();
164 }
165
166 TEST(ManualExecutor, clear) {
167   ManualExecutor x;
168   size_t count = 0;
169   x.add([&] { ++count; });
170   x.scheduleAt([&] { ++count; }, x.now() + std::chrono::milliseconds(10));
171   EXPECT_EQ(0, count);
172
173   x.clear();
174   x.advance(std::chrono::milliseconds(10));
175   x.run();
176   EXPECT_EQ(0, count);
177 }
178
179 TEST(Executor, InlineExecutor) {
180   InlineExecutor x;
181   size_t counter = 0;
182   x.add([&]{
183     x.add([&]{
184       EXPECT_EQ(counter, 0);
185       counter++;
186     });
187     EXPECT_EQ(counter, 1);
188     counter++;
189   });
190   EXPECT_EQ(counter, 2);
191 }
192
193 TEST(Executor, QueuedImmediateExecutor) {
194   QueuedImmediateExecutor x;
195   size_t counter = 0;
196   x.add([&]{
197     x.add([&]{
198       EXPECT_EQ(1, counter);
199       counter++;
200     });
201     EXPECT_EQ(0, counter);
202     counter++;
203   });
204   EXPECT_EQ(2, counter);
205 }
206
207 TEST(Executor, Runnable) {
208   InlineExecutor x;
209   size_t counter = 0;
210   struct Runnable {
211     std::function<void()> fn;
212     void operator()() { fn(); }
213   };
214   Runnable f;
215   f.fn = [&]{ counter++; };
216   x.add(f);
217   EXPECT_EQ(counter, 1);
218 }
219
220 TEST(Executor, RunnablePtr) {
221   InlineExecutor x;
222   struct Runnable {
223     std::function<void()> fn;
224     void operator()() { fn(); }
225   };
226   size_t counter = 0;
227   auto fnp = std::make_shared<Runnable>();
228   fnp->fn = [&]{ counter++; };
229   x.addPtr(fnp);
230   EXPECT_EQ(counter, 1);
231 }
232
233 TEST(Executor, ThrowableThen) {
234   InlineExecutor x;
235   auto f = Future<Unit>().via(&x).then([](){
236     throw std::runtime_error("Faildog");
237   });
238   EXPECT_THROW(f.value(), std::exception);
239 }
240
241 class CrappyExecutor : public Executor {
242  public:
243   void add(Func /* f */) override { throw std::runtime_error("bad"); }
244 };
245
246 TEST(Executor, CrappyExecutor) {
247   CrappyExecutor x;
248   bool flag = false;
249   auto f = folly::via(&x).onError([&](std::runtime_error& e) {
250     EXPECT_STREQ("bad", e.what());
251     flag = true;
252   });
253   EXPECT_TRUE(flag);
254 }
255
256 class DoNothingExecutor : public Executor {
257  public:
258   void add(Func f) override {
259     storedFunc_ = std::move(f);
260   }
261
262  private:
263   Func storedFunc_;
264 };
265
266 TEST(Executor, DoNothingExecutor) {
267   DoNothingExecutor x;
268
269   // Submit future callback to DoNothingExecutor
270   auto f = folly::via(&x).then([] { return 42; });
271
272   // Callback function is stored in DoNothingExecutor, but not executed.
273   EXPECT_FALSE(f.isReady());
274
275   // Destroy the function stored in DoNothingExecutor. The future callback
276   // will never get executed.
277   x.add({});
278
279   EXPECT_TRUE(f.isReady());
280   EXPECT_THROW(f.get(), folly::BrokenPromise);
281 }