1755a2fc9e210fdcb37a50291b33de6b83c6c38a
[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/executors/InlineExecutor.h>
19 #include <folly/executors/ManualExecutor.h>
20 #include <folly/executors/QueuedImmediateExecutor.h>
21 #include <folly/futures/Future.h>
22 #include <folly/portability/GTest.h>
23
24 // TODO(jsedgwick) move this test to executors/test/ once the tested executors
25 // have all moved
26
27 using namespace folly;
28
29 TEST(ManualExecutor, runIsStable) {
30   ManualExecutor x;
31   size_t count = 0;
32   auto f1 = [&]() { count++; };
33   auto f2 = [&]() { x.add(f1); x.add(f1); };
34   x.add(f2);
35   x.run();
36 }
37
38 TEST(ManualExecutor, scheduleDur) {
39   ManualExecutor x;
40   size_t count = 0;
41   std::chrono::milliseconds dur {10};
42   x.schedule([&]{ count++; }, dur);
43   EXPECT_EQ(count, 0);
44   x.run();
45   EXPECT_EQ(count, 0);
46   x.advance(dur/2);
47   EXPECT_EQ(count, 0);
48   x.advance(dur/2);
49   EXPECT_EQ(count, 1);
50 }
51
52 TEST(ManualExecutor, laterThingsDontBlockEarlierOnes) {
53   ManualExecutor x;
54   auto first = false;
55   std::chrono::milliseconds dur{10};
56   x.schedule([&] { first = true; }, dur);
57   x.schedule([] {}, 2 * dur);
58   EXPECT_FALSE(first);
59   x.advance(dur);
60   EXPECT_TRUE(first);
61 }
62
63 TEST(ManualExecutor, orderWillNotBeQuestioned) {
64   ManualExecutor x;
65   auto first = false;
66   auto second = false;
67   std::chrono::milliseconds dur{10};
68   x.schedule([&] { first = true; }, dur);
69   x.schedule([&] { second = true; }, 2 * dur);
70   EXPECT_FALSE(first);
71   EXPECT_FALSE(second);
72   x.advance(dur);
73   EXPECT_TRUE(first);
74   EXPECT_FALSE(second);
75   x.advance(dur);
76   EXPECT_TRUE(first);
77   EXPECT_TRUE(second);
78 }
79
80 TEST(ManualExecutor, evenWhenYouSkipAheadEventsRunInProperOrder) {
81   ManualExecutor x;
82   auto counter = 0;
83   auto first = 0;
84   auto second = 0;
85   std::chrono::milliseconds dur{10};
86   x.schedule([&] { first = ++counter; }, dur);
87   x.schedule([&] { second = ++counter; }, 2 * dur);
88   EXPECT_EQ(first, 0);
89   EXPECT_EQ(second, 0);
90   x.advance(3 * dur);
91   EXPECT_EQ(first, 1);
92   EXPECT_EQ(second, 2);
93 }
94
95 TEST(ManualExecutor, clockStartsAt0) {
96   ManualExecutor x;
97   EXPECT_EQ(x.now(), x.now().min());
98 }
99
100 TEST(ManualExecutor, scheduleAbs) {
101   ManualExecutor x;
102   size_t count = 0;
103   x.scheduleAt([&]{ count++; }, x.now() + std::chrono::milliseconds(10));
104   EXPECT_EQ(count, 0);
105   x.advance(std::chrono::milliseconds(10));
106   EXPECT_EQ(count, 1);
107 }
108
109 TEST(ManualExecutor, advanceTo) {
110   ManualExecutor x;
111   size_t count = 0;
112   x.scheduleAt([&]{ count++; }, std::chrono::steady_clock::now());
113   EXPECT_EQ(count, 0);
114   x.advanceTo(std::chrono::steady_clock::now());
115   EXPECT_EQ(count, 1);
116 }
117
118 TEST(ManualExecutor, advanceBack) {
119   ManualExecutor x;
120   size_t count = 0;
121   x.advance(std::chrono::microseconds(5));
122   x.schedule([&]{ count++; }, std::chrono::microseconds(6));
123   EXPECT_EQ(count, 0);
124   x.advanceTo(x.now() - std::chrono::microseconds(1));
125   EXPECT_EQ(count, 0);
126 }
127
128 TEST(ManualExecutor, advanceNeg) {
129   ManualExecutor x;
130   size_t count = 0;
131   x.advance(std::chrono::microseconds(5));
132   x.schedule([&]{ count++; }, std::chrono::microseconds(6));
133   EXPECT_EQ(count, 0);
134   x.advance(std::chrono::microseconds(-1));
135   EXPECT_EQ(count, 0);
136 }
137
138 TEST(ManualExecutor, waitForDoesNotDeadlock) {
139   ManualExecutor east, west;
140   folly::Baton<> baton;
141   auto f = makeFuture()
142     .via(&east)
143     .then([](Try<Unit>){ return makeFuture(); })
144     .via(&west);
145   std::thread t([&]{
146     baton.post();
147     west.waitFor(f);
148   });
149   baton.wait();
150   east.run();
151   t.join();
152 }
153
154 TEST(ManualExecutor, getViaDoesNotDeadlock) {
155   ManualExecutor east, west;
156   folly::Baton<> baton;
157   auto f = makeFuture().via(&east).then([](Try<Unit>) {
158     return makeFuture();
159   }).via(&west);
160   std::thread t([&] {
161     baton.post();
162     f.getVia(&west);
163   });
164   baton.wait();
165   east.run();
166   t.join();
167 }
168
169 TEST(ManualExecutor, clear) {
170   ManualExecutor x;
171   size_t count = 0;
172   x.add([&] { ++count; });
173   x.scheduleAt([&] { ++count; }, x.now() + std::chrono::milliseconds(10));
174   EXPECT_EQ(0, count);
175
176   x.clear();
177   x.advance(std::chrono::milliseconds(10));
178   x.run();
179   EXPECT_EQ(0, count);
180 }
181
182 TEST(Executor, InlineExecutor) {
183   InlineExecutor x;
184   size_t counter = 0;
185   x.add([&]{
186     x.add([&]{
187       EXPECT_EQ(counter, 0);
188       counter++;
189     });
190     EXPECT_EQ(counter, 1);
191     counter++;
192   });
193   EXPECT_EQ(counter, 2);
194 }
195
196 TEST(Executor, QueuedImmediateExecutor) {
197   QueuedImmediateExecutor x;
198   size_t counter = 0;
199   x.add([&]{
200     x.add([&]{
201       EXPECT_EQ(1, counter);
202       counter++;
203     });
204     EXPECT_EQ(0, counter);
205     counter++;
206   });
207   EXPECT_EQ(2, counter);
208 }
209
210 TEST(Executor, Runnable) {
211   InlineExecutor x;
212   size_t counter = 0;
213   struct Runnable {
214     std::function<void()> fn;
215     void operator()() { fn(); }
216   };
217   Runnable f;
218   f.fn = [&]{ counter++; };
219   x.add(f);
220   EXPECT_EQ(counter, 1);
221 }
222
223 TEST(Executor, ThrowableThen) {
224   InlineExecutor x;
225   auto f = Future<Unit>().then([]() { throw std::runtime_error("Faildog"); });
226
227   /*
228   auto f = Future<Unit>().via(&x).then([](){
229     throw std::runtime_error("Faildog");
230   });*/
231   EXPECT_THROW(f.value(), std::exception);
232 }
233
234 class CrappyExecutor : public Executor {
235  public:
236   void add(Func /* f */) override { throw std::runtime_error("bad"); }
237 };
238
239 TEST(Executor, CrappyExecutor) {
240   CrappyExecutor x;
241   bool flag = false;
242   auto f = folly::via(&x).onError([&](std::runtime_error& e) {
243     EXPECT_STREQ("bad", e.what());
244     flag = true;
245   });
246   EXPECT_TRUE(flag);
247 }
248
249 class DoNothingExecutor : public Executor {
250  public:
251   void add(Func f) override {
252     storedFunc_ = std::move(f);
253   }
254
255  private:
256   Func storedFunc_;
257 };
258
259 TEST(Executor, DoNothingExecutor) {
260   DoNothingExecutor x;
261
262   // Submit future callback to DoNothingExecutor
263   auto f = folly::via(&x).then([] { return 42; });
264
265   // Callback function is stored in DoNothingExecutor, but not executed.
266   EXPECT_FALSE(f.isReady());
267
268   // Destroy the function stored in DoNothingExecutor. The future callback
269   // will never get executed.
270   x.add({});
271
272   EXPECT_TRUE(f.isReady());
273   EXPECT_THROW(f.get(), folly::BrokenPromise);
274 }