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