Split up FibersTest into test and Benchmark.
[folly.git] / folly / fibers / test / FibersTest.cpp
1 /*
2  * Copyright 2016 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 #include <atomic>
17 #include <thread>
18 #include <vector>
19
20 #include <gtest/gtest.h>
21
22 #include <folly/Memory.h>
23 #include <folly/futures/Future.h>
24
25 #include <folly/fibers/AddTasks.h>
26 #include <folly/fibers/EventBaseLoopController.h>
27 #include <folly/fibers/FiberManager.h>
28 #include <folly/fibers/FiberManagerMap.h>
29 #include <folly/fibers/GenericBaton.h>
30 #include <folly/fibers/SimpleLoopController.h>
31 #include <folly/fibers/WhenN.h>
32
33 using namespace folly::fibers;
34
35 using folly::Try;
36
37 TEST(FiberManager, batonTimedWaitTimeout) {
38   bool taskAdded = false;
39   size_t iterations = 0;
40
41   FiberManager manager(folly::make_unique<SimpleLoopController>());
42   auto& loopController =
43       dynamic_cast<SimpleLoopController&>(manager.loopController());
44
45   auto loopFunc = [&]() {
46     if (!taskAdded) {
47       manager.addTask([&]() {
48         Baton baton;
49
50         auto res = baton.timed_wait(std::chrono::milliseconds(230));
51
52         EXPECT_FALSE(res);
53         EXPECT_EQ(5, iterations);
54
55         loopController.stop();
56       });
57       manager.addTask([&]() {
58         Baton baton;
59
60         auto res = baton.timed_wait(std::chrono::milliseconds(130));
61
62         EXPECT_FALSE(res);
63         EXPECT_EQ(3, iterations);
64
65         loopController.stop();
66       });
67       taskAdded = true;
68     } else {
69       std::this_thread::sleep_for(std::chrono::milliseconds(50));
70       iterations++;
71     }
72   };
73
74   loopController.loop(std::move(loopFunc));
75 }
76
77 TEST(FiberManager, batonTimedWaitPost) {
78   bool taskAdded = false;
79   size_t iterations = 0;
80   Baton* baton_ptr;
81
82   FiberManager manager(folly::make_unique<SimpleLoopController>());
83   auto& loopController =
84       dynamic_cast<SimpleLoopController&>(manager.loopController());
85
86   auto loopFunc = [&]() {
87     if (!taskAdded) {
88       manager.addTask([&]() {
89         Baton baton;
90         baton_ptr = &baton;
91
92         auto res = baton.timed_wait(std::chrono::milliseconds(130));
93
94         EXPECT_TRUE(res);
95         EXPECT_EQ(2, iterations);
96
97         loopController.stop();
98       });
99       taskAdded = true;
100     } else {
101       std::this_thread::sleep_for(std::chrono::milliseconds(50));
102       iterations++;
103       if (iterations == 2) {
104         baton_ptr->post();
105       }
106     }
107   };
108
109   loopController.loop(std::move(loopFunc));
110 }
111
112 TEST(FiberManager, batonTimedWaitTimeoutEvb) {
113   size_t tasksComplete = 0;
114
115   folly::EventBase evb;
116
117   FiberManager manager(folly::make_unique<EventBaseLoopController>());
118   dynamic_cast<EventBaseLoopController&>(manager.loopController())
119       .attachEventBase(evb);
120
121   auto task = [&](size_t timeout_ms) {
122     Baton baton;
123
124     auto start = EventBaseLoopController::Clock::now();
125     auto res = baton.timed_wait(std::chrono::milliseconds(timeout_ms));
126     auto finish = EventBaseLoopController::Clock::now();
127
128     EXPECT_FALSE(res);
129
130     auto duration_ms =
131         std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
132
133     EXPECT_GT(duration_ms.count(), timeout_ms - 50);
134     EXPECT_LT(duration_ms.count(), timeout_ms + 50);
135
136     if (++tasksComplete == 2) {
137       evb.terminateLoopSoon();
138     }
139   };
140
141   evb.runInEventBaseThread([&]() {
142     manager.addTask([&]() { task(500); });
143     manager.addTask([&]() { task(250); });
144   });
145
146   evb.loopForever();
147
148   EXPECT_EQ(2, tasksComplete);
149 }
150
151 TEST(FiberManager, batonTimedWaitPostEvb) {
152   size_t tasksComplete = 0;
153
154   folly::EventBase evb;
155
156   FiberManager manager(folly::make_unique<EventBaseLoopController>());
157   dynamic_cast<EventBaseLoopController&>(manager.loopController())
158       .attachEventBase(evb);
159
160   evb.runInEventBaseThread([&]() {
161     manager.addTask([&]() {
162       Baton baton;
163
164       evb.tryRunAfterDelay([&]() { baton.post(); }, 100);
165
166       auto start = EventBaseLoopController::Clock::now();
167       auto res = baton.timed_wait(std::chrono::milliseconds(130));
168       auto finish = EventBaseLoopController::Clock::now();
169
170       EXPECT_TRUE(res);
171
172       auto duration_ms =
173           std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
174
175       EXPECT_TRUE(duration_ms.count() > 95 && duration_ms.count() < 110);
176
177       if (++tasksComplete == 1) {
178         evb.terminateLoopSoon();
179       }
180     });
181   });
182
183   evb.loopForever();
184
185   EXPECT_EQ(1, tasksComplete);
186 }
187
188 TEST(FiberManager, batonTryWait) {
189   FiberManager manager(folly::make_unique<SimpleLoopController>());
190
191   // Check if try_wait and post work as expected
192   Baton b;
193
194   manager.addTask([&]() {
195     while (!b.try_wait()) {
196     }
197   });
198   auto thr = std::thread([&]() {
199     std::this_thread::sleep_for(std::chrono::milliseconds(300));
200     b.post();
201   });
202
203   manager.loopUntilNoReady();
204   thr.join();
205
206   Baton c;
207
208   // Check try_wait without post
209   manager.addTask([&]() {
210     int cnt = 100;
211     while (cnt && !c.try_wait()) {
212       cnt--;
213     }
214     EXPECT_TRUE(!c.try_wait()); // must still hold
215     EXPECT_EQ(cnt, 0);
216   });
217
218   manager.loopUntilNoReady();
219 }
220
221 TEST(FiberManager, genericBatonFiberWait) {
222   FiberManager manager(folly::make_unique<SimpleLoopController>());
223
224   GenericBaton b;
225   bool fiberRunning = false;
226
227   manager.addTask([&]() {
228     EXPECT_EQ(manager.hasActiveFiber(), true);
229     fiberRunning = true;
230     b.wait();
231     fiberRunning = false;
232   });
233
234   EXPECT_FALSE(fiberRunning);
235   manager.loopUntilNoReady();
236   EXPECT_TRUE(fiberRunning); // ensure fiber still active
237
238   auto thr = std::thread([&]() {
239     std::this_thread::sleep_for(std::chrono::milliseconds(300));
240     b.post();
241   });
242
243   while (fiberRunning) {
244     manager.loopUntilNoReady();
245   }
246
247   thr.join();
248 }
249
250 TEST(FiberManager, genericBatonThreadWait) {
251   FiberManager manager(folly::make_unique<SimpleLoopController>());
252   GenericBaton b;
253   std::atomic<bool> threadWaiting(false);
254
255   auto thr = std::thread([&]() {
256     threadWaiting = true;
257     b.wait();
258     threadWaiting = false;
259   });
260
261   while (!threadWaiting) {
262   }
263   std::this_thread::sleep_for(std::chrono::milliseconds(300));
264
265   manager.addTask([&]() {
266     EXPECT_EQ(manager.hasActiveFiber(), true);
267     EXPECT_TRUE(threadWaiting);
268     b.post();
269     while (threadWaiting) {
270     }
271   });
272
273   manager.loopUntilNoReady();
274   thr.join();
275 }
276
277 TEST(FiberManager, addTasksNoncopyable) {
278   std::vector<Promise<int>> pendingFibers;
279   bool taskAdded = false;
280
281   FiberManager manager(folly::make_unique<SimpleLoopController>());
282   auto& loopController =
283       dynamic_cast<SimpleLoopController&>(manager.loopController());
284
285   auto loopFunc = [&]() {
286     if (!taskAdded) {
287       manager.addTask([&]() {
288         std::vector<std::function<std::unique_ptr<int>()>> funcs;
289         for (size_t i = 0; i < 3; ++i) {
290           funcs.push_back([i, &pendingFibers]() {
291             await([&pendingFibers](Promise<int> promise) {
292               pendingFibers.push_back(std::move(promise));
293             });
294             return folly::make_unique<int>(i * 2 + 1);
295           });
296         }
297
298         auto iter = addTasks(funcs.begin(), funcs.end());
299
300         size_t n = 0;
301         while (iter.hasNext()) {
302           auto result = iter.awaitNext();
303           EXPECT_EQ(2 * iter.getTaskID() + 1, *result);
304           EXPECT_GE(2 - n, pendingFibers.size());
305           ++n;
306         }
307         EXPECT_EQ(3, n);
308       });
309       taskAdded = true;
310     } else if (pendingFibers.size()) {
311       pendingFibers.back().setValue(0);
312       pendingFibers.pop_back();
313     } else {
314       loopController.stop();
315     }
316   };
317
318   loopController.loop(std::move(loopFunc));
319 }
320
321 TEST(FiberManager, awaitThrow) {
322   folly::EventBase evb;
323   struct ExpectedException {};
324   getFiberManager(evb)
325       .addTaskFuture([&] {
326         EXPECT_THROW(
327           await([](Promise<int> p) {
328               p.setValue(42);
329               throw ExpectedException();
330             }),
331           ExpectedException
332         );
333
334         EXPECT_THROW(
335           await([&](Promise<int> p) {
336               evb.runInEventBaseThread([p = std::move(p)]() mutable {
337                   p.setValue(42);
338                 });
339               throw ExpectedException();
340             }),
341           ExpectedException);
342       })
343       .waitVia(&evb);
344 }
345
346 TEST(FiberManager, addTasksThrow) {
347   std::vector<Promise<int>> pendingFibers;
348   bool taskAdded = false;
349
350   FiberManager manager(folly::make_unique<SimpleLoopController>());
351   auto& loopController =
352       dynamic_cast<SimpleLoopController&>(manager.loopController());
353
354   auto loopFunc = [&]() {
355     if (!taskAdded) {
356       manager.addTask([&]() {
357         std::vector<std::function<int()>> funcs;
358         for (size_t i = 0; i < 3; ++i) {
359           funcs.push_back([i, &pendingFibers]() {
360             await([&pendingFibers](Promise<int> promise) {
361               pendingFibers.push_back(std::move(promise));
362             });
363             if (i % 2 == 0) {
364               throw std::runtime_error("Runtime");
365             }
366             return i * 2 + 1;
367           });
368         }
369
370         auto iter = addTasks(funcs.begin(), funcs.end());
371
372         size_t n = 0;
373         while (iter.hasNext()) {
374           try {
375             int result = iter.awaitNext();
376             EXPECT_EQ(1, iter.getTaskID() % 2);
377             EXPECT_EQ(2 * iter.getTaskID() + 1, result);
378           } catch (...) {
379             EXPECT_EQ(0, iter.getTaskID() % 2);
380           }
381           EXPECT_GE(2 - n, pendingFibers.size());
382           ++n;
383         }
384         EXPECT_EQ(3, n);
385       });
386       taskAdded = true;
387     } else if (pendingFibers.size()) {
388       pendingFibers.back().setValue(0);
389       pendingFibers.pop_back();
390     } else {
391       loopController.stop();
392     }
393   };
394
395   loopController.loop(std::move(loopFunc));
396 }
397
398 TEST(FiberManager, addTasksVoid) {
399   std::vector<Promise<int>> pendingFibers;
400   bool taskAdded = false;
401
402   FiberManager manager(folly::make_unique<SimpleLoopController>());
403   auto& loopController =
404       dynamic_cast<SimpleLoopController&>(manager.loopController());
405
406   auto loopFunc = [&]() {
407     if (!taskAdded) {
408       manager.addTask([&]() {
409         std::vector<std::function<void()>> funcs;
410         for (size_t i = 0; i < 3; ++i) {
411           funcs.push_back([i, &pendingFibers]() {
412             await([&pendingFibers](Promise<int> promise) {
413               pendingFibers.push_back(std::move(promise));
414             });
415           });
416         }
417
418         auto iter = addTasks(funcs.begin(), funcs.end());
419
420         size_t n = 0;
421         while (iter.hasNext()) {
422           iter.awaitNext();
423           EXPECT_GE(2 - n, pendingFibers.size());
424           ++n;
425         }
426         EXPECT_EQ(3, n);
427       });
428       taskAdded = true;
429     } else if (pendingFibers.size()) {
430       pendingFibers.back().setValue(0);
431       pendingFibers.pop_back();
432     } else {
433       loopController.stop();
434     }
435   };
436
437   loopController.loop(std::move(loopFunc));
438 }
439
440 TEST(FiberManager, addTasksVoidThrow) {
441   std::vector<Promise<int>> pendingFibers;
442   bool taskAdded = false;
443
444   FiberManager manager(folly::make_unique<SimpleLoopController>());
445   auto& loopController =
446       dynamic_cast<SimpleLoopController&>(manager.loopController());
447
448   auto loopFunc = [&]() {
449     if (!taskAdded) {
450       manager.addTask([&]() {
451         std::vector<std::function<void()>> funcs;
452         for (size_t i = 0; i < 3; ++i) {
453           funcs.push_back([i, &pendingFibers]() {
454             await([&pendingFibers](Promise<int> promise) {
455               pendingFibers.push_back(std::move(promise));
456             });
457             if (i % 2 == 0) {
458               throw std::runtime_error("");
459             }
460           });
461         }
462
463         auto iter = addTasks(funcs.begin(), funcs.end());
464
465         size_t n = 0;
466         while (iter.hasNext()) {
467           try {
468             iter.awaitNext();
469             EXPECT_EQ(1, iter.getTaskID() % 2);
470           } catch (...) {
471             EXPECT_EQ(0, iter.getTaskID() % 2);
472           }
473           EXPECT_GE(2 - n, pendingFibers.size());
474           ++n;
475         }
476         EXPECT_EQ(3, n);
477       });
478       taskAdded = true;
479     } else if (pendingFibers.size()) {
480       pendingFibers.back().setValue(0);
481       pendingFibers.pop_back();
482     } else {
483       loopController.stop();
484     }
485   };
486
487   loopController.loop(std::move(loopFunc));
488 }
489
490 TEST(FiberManager, addTasksReserve) {
491   std::vector<Promise<int>> pendingFibers;
492   bool taskAdded = false;
493
494   FiberManager manager(folly::make_unique<SimpleLoopController>());
495   auto& loopController =
496       dynamic_cast<SimpleLoopController&>(manager.loopController());
497
498   auto loopFunc = [&]() {
499     if (!taskAdded) {
500       manager.addTask([&]() {
501         std::vector<std::function<void()>> funcs;
502         for (size_t i = 0; i < 3; ++i) {
503           funcs.push_back([&pendingFibers]() {
504             await([&pendingFibers](Promise<int> promise) {
505               pendingFibers.push_back(std::move(promise));
506             });
507           });
508         }
509
510         auto iter = addTasks(funcs.begin(), funcs.end());
511
512         iter.reserve(2);
513         EXPECT_TRUE(iter.hasCompleted());
514         EXPECT_TRUE(iter.hasPending());
515         EXPECT_TRUE(iter.hasNext());
516
517         iter.awaitNext();
518         EXPECT_TRUE(iter.hasCompleted());
519         EXPECT_TRUE(iter.hasPending());
520         EXPECT_TRUE(iter.hasNext());
521
522         iter.awaitNext();
523         EXPECT_FALSE(iter.hasCompleted());
524         EXPECT_TRUE(iter.hasPending());
525         EXPECT_TRUE(iter.hasNext());
526
527         iter.awaitNext();
528         EXPECT_FALSE(iter.hasCompleted());
529         EXPECT_FALSE(iter.hasPending());
530         EXPECT_FALSE(iter.hasNext());
531       });
532       taskAdded = true;
533     } else if (pendingFibers.size()) {
534       pendingFibers.back().setValue(0);
535       pendingFibers.pop_back();
536     } else {
537       loopController.stop();
538     }
539   };
540
541   loopController.loop(std::move(loopFunc));
542 }
543
544 TEST(FiberManager, addTaskDynamic) {
545   folly::EventBase evb;
546
547   Baton batons[3];
548
549   auto makeTask = [&](size_t taskId) {
550     return [&, taskId]() -> size_t {
551       batons[taskId].wait();
552       return taskId;
553     };
554   };
555
556   getFiberManager(evb)
557       .addTaskFuture([&]() {
558         TaskIterator<size_t> iterator;
559
560         iterator.addTask(makeTask(0));
561         iterator.addTask(makeTask(1));
562
563         batons[1].post();
564
565         EXPECT_EQ(1, iterator.awaitNext());
566
567         iterator.addTask(makeTask(2));
568
569         batons[2].post();
570
571         EXPECT_EQ(2, iterator.awaitNext());
572
573         batons[0].post();
574
575         EXPECT_EQ(0, iterator.awaitNext());
576       })
577       .waitVia(&evb);
578 }
579
580 TEST(FiberManager, forEach) {
581   std::vector<Promise<int>> pendingFibers;
582   bool taskAdded = false;
583
584   FiberManager manager(folly::make_unique<SimpleLoopController>());
585   auto& loopController =
586       dynamic_cast<SimpleLoopController&>(manager.loopController());
587
588   auto loopFunc = [&]() {
589     if (!taskAdded) {
590       manager.addTask([&]() {
591         std::vector<std::function<int()>> funcs;
592         for (size_t i = 0; i < 3; ++i) {
593           funcs.push_back([i, &pendingFibers]() {
594             await([&pendingFibers](Promise<int> promise) {
595               pendingFibers.push_back(std::move(promise));
596             });
597             return i * 2 + 1;
598           });
599         }
600
601         std::vector<std::pair<size_t, int>> results;
602         forEach(funcs.begin(), funcs.end(), [&results](size_t id, int result) {
603           results.emplace_back(id, result);
604         });
605         EXPECT_EQ(3, results.size());
606         EXPECT_TRUE(pendingFibers.empty());
607         for (size_t i = 0; i < 3; ++i) {
608           EXPECT_EQ(results[i].first * 2 + 1, results[i].second);
609         }
610       });
611       taskAdded = true;
612     } else if (pendingFibers.size()) {
613       pendingFibers.back().setValue(0);
614       pendingFibers.pop_back();
615     } else {
616       loopController.stop();
617     }
618   };
619
620   loopController.loop(std::move(loopFunc));
621 }
622
623 TEST(FiberManager, collectN) {
624   std::vector<Promise<int>> pendingFibers;
625   bool taskAdded = false;
626
627   FiberManager manager(folly::make_unique<SimpleLoopController>());
628   auto& loopController =
629       dynamic_cast<SimpleLoopController&>(manager.loopController());
630
631   auto loopFunc = [&]() {
632     if (!taskAdded) {
633       manager.addTask([&]() {
634         std::vector<std::function<int()>> funcs;
635         for (size_t i = 0; i < 3; ++i) {
636           funcs.push_back([i, &pendingFibers]() {
637             await([&pendingFibers](Promise<int> promise) {
638               pendingFibers.push_back(std::move(promise));
639             });
640             return i * 2 + 1;
641           });
642         }
643
644         auto results = collectN(funcs.begin(), funcs.end(), 2);
645         EXPECT_EQ(2, results.size());
646         EXPECT_EQ(1, pendingFibers.size());
647         for (size_t i = 0; i < 2; ++i) {
648           EXPECT_EQ(results[i].first * 2 + 1, results[i].second);
649         }
650       });
651       taskAdded = true;
652     } else if (pendingFibers.size()) {
653       pendingFibers.back().setValue(0);
654       pendingFibers.pop_back();
655     } else {
656       loopController.stop();
657     }
658   };
659
660   loopController.loop(std::move(loopFunc));
661 }
662
663 TEST(FiberManager, collectNThrow) {
664   std::vector<Promise<int>> pendingFibers;
665   bool taskAdded = false;
666
667   FiberManager manager(folly::make_unique<SimpleLoopController>());
668   auto& loopController =
669       dynamic_cast<SimpleLoopController&>(manager.loopController());
670
671   auto loopFunc = [&]() {
672     if (!taskAdded) {
673       manager.addTask([&]() {
674         std::vector<std::function<int()>> funcs;
675         for (size_t i = 0; i < 3; ++i) {
676           funcs.push_back([i, &pendingFibers]() {
677             await([&pendingFibers](Promise<int> promise) {
678               pendingFibers.push_back(std::move(promise));
679             });
680             throw std::runtime_error("Runtime");
681             return i * 2 + 1;
682           });
683         }
684
685         try {
686           collectN(funcs.begin(), funcs.end(), 2);
687         } catch (...) {
688           EXPECT_EQ(1, pendingFibers.size());
689         }
690       });
691       taskAdded = true;
692     } else if (pendingFibers.size()) {
693       pendingFibers.back().setValue(0);
694       pendingFibers.pop_back();
695     } else {
696       loopController.stop();
697     }
698   };
699
700   loopController.loop(std::move(loopFunc));
701 }
702
703 TEST(FiberManager, collectNVoid) {
704   std::vector<Promise<int>> pendingFibers;
705   bool taskAdded = false;
706
707   FiberManager manager(folly::make_unique<SimpleLoopController>());
708   auto& loopController =
709       dynamic_cast<SimpleLoopController&>(manager.loopController());
710
711   auto loopFunc = [&]() {
712     if (!taskAdded) {
713       manager.addTask([&]() {
714         std::vector<std::function<void()>> funcs;
715         for (size_t i = 0; i < 3; ++i) {
716           funcs.push_back([i, &pendingFibers]() {
717             await([&pendingFibers](Promise<int> promise) {
718               pendingFibers.push_back(std::move(promise));
719             });
720           });
721         }
722
723         auto results = collectN(funcs.begin(), funcs.end(), 2);
724         EXPECT_EQ(2, results.size());
725         EXPECT_EQ(1, pendingFibers.size());
726       });
727       taskAdded = true;
728     } else if (pendingFibers.size()) {
729       pendingFibers.back().setValue(0);
730       pendingFibers.pop_back();
731     } else {
732       loopController.stop();
733     }
734   };
735
736   loopController.loop(std::move(loopFunc));
737 }
738
739 TEST(FiberManager, collectNVoidThrow) {
740   std::vector<Promise<int>> pendingFibers;
741   bool taskAdded = false;
742
743   FiberManager manager(folly::make_unique<SimpleLoopController>());
744   auto& loopController =
745       dynamic_cast<SimpleLoopController&>(manager.loopController());
746
747   auto loopFunc = [&]() {
748     if (!taskAdded) {
749       manager.addTask([&]() {
750         std::vector<std::function<void()>> funcs;
751         for (size_t i = 0; i < 3; ++i) {
752           funcs.push_back([i, &pendingFibers]() {
753             await([&pendingFibers](Promise<int> promise) {
754               pendingFibers.push_back(std::move(promise));
755             });
756             throw std::runtime_error("Runtime");
757           });
758         }
759
760         try {
761           collectN(funcs.begin(), funcs.end(), 2);
762         } catch (...) {
763           EXPECT_EQ(1, pendingFibers.size());
764         }
765       });
766       taskAdded = true;
767     } else if (pendingFibers.size()) {
768       pendingFibers.back().setValue(0);
769       pendingFibers.pop_back();
770     } else {
771       loopController.stop();
772     }
773   };
774
775   loopController.loop(std::move(loopFunc));
776 }
777
778 TEST(FiberManager, collectAll) {
779   std::vector<Promise<int>> pendingFibers;
780   bool taskAdded = false;
781
782   FiberManager manager(folly::make_unique<SimpleLoopController>());
783   auto& loopController =
784       dynamic_cast<SimpleLoopController&>(manager.loopController());
785
786   auto loopFunc = [&]() {
787     if (!taskAdded) {
788       manager.addTask([&]() {
789         std::vector<std::function<int()>> funcs;
790         for (size_t i = 0; i < 3; ++i) {
791           funcs.push_back([i, &pendingFibers]() {
792             await([&pendingFibers](Promise<int> promise) {
793               pendingFibers.push_back(std::move(promise));
794             });
795             return i * 2 + 1;
796           });
797         }
798
799         auto results = collectAll(funcs.begin(), funcs.end());
800         EXPECT_TRUE(pendingFibers.empty());
801         for (size_t i = 0; i < 3; ++i) {
802           EXPECT_EQ(i * 2 + 1, results[i]);
803         }
804       });
805       taskAdded = true;
806     } else if (pendingFibers.size()) {
807       pendingFibers.back().setValue(0);
808       pendingFibers.pop_back();
809     } else {
810       loopController.stop();
811     }
812   };
813
814   loopController.loop(std::move(loopFunc));
815 }
816
817 TEST(FiberManager, collectAllVoid) {
818   std::vector<Promise<int>> pendingFibers;
819   bool taskAdded = false;
820
821   FiberManager manager(folly::make_unique<SimpleLoopController>());
822   auto& loopController =
823       dynamic_cast<SimpleLoopController&>(manager.loopController());
824
825   auto loopFunc = [&]() {
826     if (!taskAdded) {
827       manager.addTask([&]() {
828         std::vector<std::function<void()>> funcs;
829         for (size_t i = 0; i < 3; ++i) {
830           funcs.push_back([i, &pendingFibers]() {
831             await([&pendingFibers](Promise<int> promise) {
832               pendingFibers.push_back(std::move(promise));
833             });
834           });
835         }
836
837         collectAll(funcs.begin(), funcs.end());
838         EXPECT_TRUE(pendingFibers.empty());
839       });
840       taskAdded = true;
841     } else if (pendingFibers.size()) {
842       pendingFibers.back().setValue(0);
843       pendingFibers.pop_back();
844     } else {
845       loopController.stop();
846     }
847   };
848
849   loopController.loop(std::move(loopFunc));
850 }
851
852 TEST(FiberManager, collectAny) {
853   std::vector<Promise<int>> pendingFibers;
854   bool taskAdded = false;
855
856   FiberManager manager(folly::make_unique<SimpleLoopController>());
857   auto& loopController =
858       dynamic_cast<SimpleLoopController&>(manager.loopController());
859
860   auto loopFunc = [&]() {
861     if (!taskAdded) {
862       manager.addTask([&]() {
863         std::vector<std::function<int()>> funcs;
864         for (size_t i = 0; i < 3; ++i) {
865           funcs.push_back([i, &pendingFibers]() {
866             await([&pendingFibers](Promise<int> promise) {
867               pendingFibers.push_back(std::move(promise));
868             });
869             if (i == 1) {
870               throw std::runtime_error("This exception will be ignored");
871             }
872             return i * 2 + 1;
873           });
874         }
875
876         auto result = collectAny(funcs.begin(), funcs.end());
877         EXPECT_EQ(2, pendingFibers.size());
878         EXPECT_EQ(2, result.first);
879         EXPECT_EQ(2 * 2 + 1, result.second);
880       });
881       taskAdded = true;
882     } else if (pendingFibers.size()) {
883       pendingFibers.back().setValue(0);
884       pendingFibers.pop_back();
885     } else {
886       loopController.stop();
887     }
888   };
889
890   loopController.loop(std::move(loopFunc));
891 }
892
893 namespace {
894 /* Checks that this function was run from a main context,
895    by comparing an address on a stack to a known main stack address
896    and a known related fiber stack address.  The assumption
897    is that fiber stack and main stack will be far enough apart,
898    while any two values on the same stack will be close. */
899 void expectMainContext(bool& ran, int* mainLocation, int* fiberLocation) {
900   int here;
901   /* 2 pages is a good guess */
902   constexpr ssize_t DISTANCE = 0x2000 / sizeof(int);
903   if (fiberLocation) {
904     EXPECT_TRUE(std::abs(&here - fiberLocation) > DISTANCE);
905   }
906   if (mainLocation) {
907     EXPECT_TRUE(std::abs(&here - mainLocation) < DISTANCE);
908   }
909
910   EXPECT_FALSE(ran);
911   ran = true;
912 }
913 }
914
915 TEST(FiberManager, runInMainContext) {
916   FiberManager manager(folly::make_unique<SimpleLoopController>());
917   auto& loopController =
918       dynamic_cast<SimpleLoopController&>(manager.loopController());
919
920   bool checkRan = false;
921
922   int mainLocation;
923   manager.runInMainContext(
924       [&]() { expectMainContext(checkRan, &mainLocation, nullptr); });
925   EXPECT_TRUE(checkRan);
926
927   checkRan = false;
928
929   manager.addTask([&]() {
930     struct A {
931       explicit A(int value_) : value(value_) {}
932       A(const A&) = delete;
933       A(A&&) = default;
934
935       int value;
936     };
937     int stackLocation;
938     auto ret = runInMainContext([&]() {
939       expectMainContext(checkRan, &mainLocation, &stackLocation);
940       return A(42);
941     });
942     EXPECT_TRUE(checkRan);
943     EXPECT_EQ(42, ret.value);
944   });
945
946   loopController.loop([&]() { loopController.stop(); });
947
948   EXPECT_TRUE(checkRan);
949 }
950
951 TEST(FiberManager, addTaskFinally) {
952   FiberManager manager(folly::make_unique<SimpleLoopController>());
953   auto& loopController =
954       dynamic_cast<SimpleLoopController&>(manager.loopController());
955
956   bool checkRan = false;
957
958   int mainLocation;
959
960   manager.addTaskFinally(
961       [&]() { return 1234; },
962       [&](Try<int>&& result) {
963         EXPECT_EQ(result.value(), 1234);
964
965         expectMainContext(checkRan, &mainLocation, nullptr);
966       });
967
968   EXPECT_FALSE(checkRan);
969
970   loopController.loop([&]() { loopController.stop(); });
971
972   EXPECT_TRUE(checkRan);
973 }
974
975 TEST(FiberManager, fibersPoolWithinLimit) {
976   FiberManager::Options opts;
977   opts.maxFibersPoolSize = 5;
978
979   FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
980   auto& loopController =
981       dynamic_cast<SimpleLoopController&>(manager.loopController());
982
983   size_t fibersRun = 0;
984
985   for (size_t i = 0; i < 5; ++i) {
986     manager.addTask([&]() { ++fibersRun; });
987   }
988   loopController.loop([&]() { loopController.stop(); });
989
990   EXPECT_EQ(5, fibersRun);
991   EXPECT_EQ(5, manager.fibersAllocated());
992   EXPECT_EQ(5, manager.fibersPoolSize());
993
994   for (size_t i = 0; i < 5; ++i) {
995     manager.addTask([&]() { ++fibersRun; });
996   }
997   loopController.loop([&]() { loopController.stop(); });
998
999   EXPECT_EQ(10, fibersRun);
1000   EXPECT_EQ(5, manager.fibersAllocated());
1001   EXPECT_EQ(5, manager.fibersPoolSize());
1002 }
1003
1004 TEST(FiberManager, fibersPoolOverLimit) {
1005   FiberManager::Options opts;
1006   opts.maxFibersPoolSize = 5;
1007
1008   FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
1009   auto& loopController =
1010       dynamic_cast<SimpleLoopController&>(manager.loopController());
1011
1012   size_t fibersRun = 0;
1013
1014   for (size_t i = 0; i < 10; ++i) {
1015     manager.addTask([&]() { ++fibersRun; });
1016   }
1017
1018   EXPECT_EQ(0, fibersRun);
1019   EXPECT_EQ(10, manager.fibersAllocated());
1020   EXPECT_EQ(0, manager.fibersPoolSize());
1021
1022   loopController.loop([&]() { loopController.stop(); });
1023
1024   EXPECT_EQ(10, fibersRun);
1025   EXPECT_EQ(5, manager.fibersAllocated());
1026   EXPECT_EQ(5, manager.fibersPoolSize());
1027 }
1028
1029 TEST(FiberManager, remoteFiberBasic) {
1030   FiberManager manager(folly::make_unique<SimpleLoopController>());
1031   auto& loopController =
1032       dynamic_cast<SimpleLoopController&>(manager.loopController());
1033
1034   int result[2];
1035   result[0] = result[1] = 0;
1036   folly::Optional<Promise<int>> savedPromise[2];
1037   manager.addTask([&]() {
1038     result[0] = await(
1039         [&](Promise<int> promise) { savedPromise[0] = std::move(promise); });
1040   });
1041   manager.addTask([&]() {
1042     result[1] = await(
1043         [&](Promise<int> promise) { savedPromise[1] = std::move(promise); });
1044   });
1045
1046   manager.loopUntilNoReady();
1047
1048   EXPECT_TRUE(savedPromise[0].hasValue());
1049   EXPECT_TRUE(savedPromise[1].hasValue());
1050   EXPECT_EQ(0, result[0]);
1051   EXPECT_EQ(0, result[1]);
1052
1053   std::thread remoteThread0{[&]() { savedPromise[0]->setValue(42); }};
1054   std::thread remoteThread1{[&]() { savedPromise[1]->setValue(43); }};
1055   remoteThread0.join();
1056   remoteThread1.join();
1057   EXPECT_EQ(0, result[0]);
1058   EXPECT_EQ(0, result[1]);
1059   /* Should only have scheduled once */
1060   EXPECT_EQ(1, loopController.remoteScheduleCalled());
1061
1062   manager.loopUntilNoReady();
1063   EXPECT_EQ(42, result[0]);
1064   EXPECT_EQ(43, result[1]);
1065 }
1066
1067 TEST(FiberManager, addTaskRemoteBasic) {
1068   FiberManager manager(folly::make_unique<SimpleLoopController>());
1069
1070   int result[2];
1071   result[0] = result[1] = 0;
1072   folly::Optional<Promise<int>> savedPromise[2];
1073
1074   std::thread remoteThread0{[&]() {
1075     manager.addTaskRemote([&]() {
1076       result[0] = await(
1077           [&](Promise<int> promise) { savedPromise[0] = std::move(promise); });
1078     });
1079   }};
1080   std::thread remoteThread1{[&]() {
1081     manager.addTaskRemote([&]() {
1082       result[1] = await(
1083           [&](Promise<int> promise) { savedPromise[1] = std::move(promise); });
1084     });
1085   }};
1086   remoteThread0.join();
1087   remoteThread1.join();
1088
1089   manager.loopUntilNoReady();
1090
1091   EXPECT_TRUE(savedPromise[0].hasValue());
1092   EXPECT_TRUE(savedPromise[1].hasValue());
1093   EXPECT_EQ(0, result[0]);
1094   EXPECT_EQ(0, result[1]);
1095
1096   savedPromise[0]->setValue(42);
1097   savedPromise[1]->setValue(43);
1098
1099   EXPECT_EQ(0, result[0]);
1100   EXPECT_EQ(0, result[1]);
1101
1102   manager.loopUntilNoReady();
1103   EXPECT_EQ(42, result[0]);
1104   EXPECT_EQ(43, result[1]);
1105 }
1106
1107 TEST(FiberManager, remoteHasTasks) {
1108   size_t counter = 0;
1109   FiberManager fm(folly::make_unique<SimpleLoopController>());
1110   std::thread remote([&]() { fm.addTaskRemote([&]() { ++counter; }); });
1111
1112   remote.join();
1113
1114   while (fm.hasTasks()) {
1115     fm.loopUntilNoReady();
1116   }
1117
1118   EXPECT_FALSE(fm.hasTasks());
1119   EXPECT_EQ(counter, 1);
1120 }
1121
1122 TEST(FiberManager, remoteHasReadyTasks) {
1123   int result = 0;
1124   folly::Optional<Promise<int>> savedPromise;
1125   FiberManager fm(folly::make_unique<SimpleLoopController>());
1126   std::thread remote([&]() {
1127     fm.addTaskRemote([&]() {
1128       result = await(
1129           [&](Promise<int> promise) { savedPromise = std::move(promise); });
1130       EXPECT_TRUE(fm.hasTasks());
1131     });
1132   });
1133
1134   remote.join();
1135   EXPECT_TRUE(fm.hasTasks());
1136
1137   fm.loopUntilNoReady();
1138   EXPECT_TRUE(fm.hasTasks());
1139
1140   std::thread remote2([&]() { savedPromise->setValue(47); });
1141   remote2.join();
1142   EXPECT_TRUE(fm.hasTasks());
1143
1144   fm.loopUntilNoReady();
1145   EXPECT_FALSE(fm.hasTasks());
1146
1147   EXPECT_EQ(result, 47);
1148 }
1149
1150 template <typename Data>
1151 void testFiberLocal() {
1152   FiberManager fm(
1153       LocalType<Data>(), folly::make_unique<SimpleLoopController>());
1154
1155   fm.addTask([]() {
1156     EXPECT_EQ(42, local<Data>().value);
1157
1158     local<Data>().value = 43;
1159
1160     addTask([]() {
1161       EXPECT_EQ(43, local<Data>().value);
1162
1163       local<Data>().value = 44;
1164
1165       addTask([]() { EXPECT_EQ(44, local<Data>().value); });
1166     });
1167   });
1168
1169   fm.addTask([&]() {
1170     EXPECT_EQ(42, local<Data>().value);
1171
1172     local<Data>().value = 43;
1173
1174     fm.addTaskRemote([]() { EXPECT_EQ(43, local<Data>().value); });
1175   });
1176
1177   fm.addTask([]() {
1178     EXPECT_EQ(42, local<Data>().value);
1179     local<Data>().value = 43;
1180
1181     auto task = []() {
1182       EXPECT_EQ(43, local<Data>().value);
1183       local<Data>().value = 44;
1184     };
1185     std::vector<std::function<void()>> tasks{task};
1186     collectAny(tasks.begin(), tasks.end());
1187
1188     EXPECT_EQ(43, local<Data>().value);
1189   });
1190
1191   fm.loopUntilNoReady();
1192   EXPECT_FALSE(fm.hasTasks());
1193 }
1194
1195 TEST(FiberManager, fiberLocal) {
1196   struct SimpleData {
1197     int value{42};
1198   };
1199
1200   testFiberLocal<SimpleData>();
1201 }
1202
1203 TEST(FiberManager, fiberLocalHeap) {
1204   struct LargeData {
1205     char _[1024 * 1024];
1206     int value{42};
1207   };
1208
1209   testFiberLocal<LargeData>();
1210 }
1211
1212 TEST(FiberManager, fiberLocalDestructor) {
1213   struct CrazyData {
1214     size_t data{42};
1215
1216     ~CrazyData() {
1217       if (data == 41) {
1218         addTask([]() {
1219           EXPECT_EQ(42, local<CrazyData>().data);
1220           // Make sure we don't have infinite loop
1221           local<CrazyData>().data = 0;
1222         });
1223       }
1224     }
1225   };
1226
1227   FiberManager fm(
1228       LocalType<CrazyData>(), folly::make_unique<SimpleLoopController>());
1229
1230   fm.addTask([]() { local<CrazyData>().data = 41; });
1231
1232   fm.loopUntilNoReady();
1233   EXPECT_FALSE(fm.hasTasks());
1234 }
1235
1236 TEST(FiberManager, yieldTest) {
1237   FiberManager manager(folly::make_unique<SimpleLoopController>());
1238   auto& loopController =
1239       dynamic_cast<SimpleLoopController&>(manager.loopController());
1240
1241   bool checkRan = false;
1242
1243   manager.addTask([&]() {
1244     manager.yield();
1245     checkRan = true;
1246   });
1247
1248   loopController.loop([&]() {
1249     if (checkRan) {
1250       loopController.stop();
1251     }
1252   });
1253
1254   EXPECT_TRUE(checkRan);
1255 }
1256
1257 TEST(FiberManager, RequestContext) {
1258   FiberManager fm(folly::make_unique<SimpleLoopController>());
1259
1260   bool checkRun1 = false;
1261   bool checkRun2 = false;
1262   bool checkRun3 = false;
1263   bool checkRun4 = false;
1264   folly::fibers::Baton baton1;
1265   folly::fibers::Baton baton2;
1266   folly::fibers::Baton baton3;
1267   folly::fibers::Baton baton4;
1268
1269   {
1270     folly::RequestContextScopeGuard rctx;
1271     auto rcontext1 = folly::RequestContext::get();
1272     fm.addTask([&, rcontext1]() {
1273       EXPECT_EQ(rcontext1, folly::RequestContext::get());
1274       baton1.wait(
1275           [&]() { EXPECT_EQ(rcontext1, folly::RequestContext::get()); });
1276       EXPECT_EQ(rcontext1, folly::RequestContext::get());
1277       runInMainContext(
1278           [&]() { EXPECT_EQ(rcontext1, folly::RequestContext::get()); });
1279       checkRun1 = true;
1280     });
1281   }
1282   {
1283     folly::RequestContextScopeGuard rctx;
1284     auto rcontext2 = folly::RequestContext::get();
1285     fm.addTaskRemote([&, rcontext2]() {
1286       EXPECT_EQ(rcontext2, folly::RequestContext::get());
1287       baton2.wait();
1288       EXPECT_EQ(rcontext2, folly::RequestContext::get());
1289       checkRun2 = true;
1290     });
1291   }
1292   {
1293     folly::RequestContextScopeGuard rctx;
1294     auto rcontext3 = folly::RequestContext::get();
1295     fm.addTaskFinally(
1296         [&, rcontext3]() {
1297           EXPECT_EQ(rcontext3, folly::RequestContext::get());
1298           baton3.wait();
1299           EXPECT_EQ(rcontext3, folly::RequestContext::get());
1300
1301           return folly::Unit();
1302         },
1303         [&, rcontext3](Try<folly::Unit>&& /* t */) {
1304           EXPECT_EQ(rcontext3, folly::RequestContext::get());
1305           checkRun3 = true;
1306         });
1307   }
1308   {
1309     folly::RequestContext::setContext(nullptr);
1310     fm.addTask([&]() {
1311       folly::RequestContextScopeGuard rctx;
1312       auto rcontext4 = folly::RequestContext::get();
1313       baton4.wait();
1314       EXPECT_EQ(rcontext4, folly::RequestContext::get());
1315       checkRun4 = true;
1316     });
1317   }
1318   {
1319     folly::RequestContextScopeGuard rctx;
1320     auto rcontext = folly::RequestContext::get();
1321
1322     fm.loopUntilNoReady();
1323     EXPECT_EQ(rcontext, folly::RequestContext::get());
1324
1325     baton1.post();
1326     EXPECT_EQ(rcontext, folly::RequestContext::get());
1327     fm.loopUntilNoReady();
1328     EXPECT_TRUE(checkRun1);
1329     EXPECT_EQ(rcontext, folly::RequestContext::get());
1330
1331     baton2.post();
1332     EXPECT_EQ(rcontext, folly::RequestContext::get());
1333     fm.loopUntilNoReady();
1334     EXPECT_TRUE(checkRun2);
1335     EXPECT_EQ(rcontext, folly::RequestContext::get());
1336
1337     baton3.post();
1338     EXPECT_EQ(rcontext, folly::RequestContext::get());
1339     fm.loopUntilNoReady();
1340     EXPECT_TRUE(checkRun3);
1341     EXPECT_EQ(rcontext, folly::RequestContext::get());
1342
1343     baton4.post();
1344     EXPECT_EQ(rcontext, folly::RequestContext::get());
1345     fm.loopUntilNoReady();
1346     EXPECT_TRUE(checkRun4);
1347     EXPECT_EQ(rcontext, folly::RequestContext::get());
1348   }
1349 }
1350
1351 TEST(FiberManager, resizePeriodically) {
1352   FiberManager::Options opts;
1353   opts.fibersPoolResizePeriodMs = 300;
1354   opts.maxFibersPoolSize = 5;
1355
1356   FiberManager manager(folly::make_unique<EventBaseLoopController>(), opts);
1357
1358   folly::EventBase evb;
1359   dynamic_cast<EventBaseLoopController&>(manager.loopController())
1360       .attachEventBase(evb);
1361
1362   std::vector<Baton> batons(10);
1363
1364   size_t tasksRun = 0;
1365   for (size_t i = 0; i < 30; ++i) {
1366     manager.addTask([i, &batons, &tasksRun]() {
1367       ++tasksRun;
1368       // Keep some fibers active indefinitely
1369       if (i < batons.size()) {
1370         batons[i].wait();
1371       }
1372     });
1373   }
1374
1375   EXPECT_EQ(0, tasksRun);
1376   EXPECT_EQ(30, manager.fibersAllocated());
1377   EXPECT_EQ(0, manager.fibersPoolSize());
1378
1379   evb.loopOnce();
1380   EXPECT_EQ(30, tasksRun);
1381   EXPECT_EQ(30, manager.fibersAllocated());
1382   // Can go over maxFibersPoolSize, 10 of 30 fibers still active
1383   EXPECT_EQ(20, manager.fibersPoolSize());
1384
1385   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1386   evb.loopOnce(); // no fibers active in this period
1387   EXPECT_EQ(30, manager.fibersAllocated());
1388   EXPECT_EQ(20, manager.fibersPoolSize());
1389
1390   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1391   evb.loopOnce(); // should shrink fibers pool to maxFibersPoolSize
1392   EXPECT_EQ(15, manager.fibersAllocated());
1393   EXPECT_EQ(5, manager.fibersPoolSize());
1394
1395   for (size_t i = 0; i < batons.size(); ++i) {
1396     batons[i].post();
1397   }
1398   evb.loopOnce();
1399   EXPECT_EQ(15, manager.fibersAllocated());
1400   EXPECT_EQ(15, manager.fibersPoolSize());
1401
1402   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1403   evb.loopOnce(); // 10 fibers active in last period
1404   EXPECT_EQ(10, manager.fibersAllocated());
1405   EXPECT_EQ(10, manager.fibersPoolSize());
1406
1407   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1408   evb.loopOnce();
1409   EXPECT_EQ(5, manager.fibersAllocated());
1410   EXPECT_EQ(5, manager.fibersPoolSize());
1411 }
1412
1413 TEST(FiberManager, batonWaitTimeoutHandler) {
1414   FiberManager manager(folly::make_unique<EventBaseLoopController>());
1415
1416   folly::EventBase evb;
1417   dynamic_cast<EventBaseLoopController&>(manager.loopController())
1418       .attachEventBase(evb);
1419
1420   size_t fibersRun = 0;
1421   Baton baton;
1422   Baton::TimeoutHandler timeoutHandler;
1423
1424   manager.addTask([&]() {
1425     baton.wait(timeoutHandler);
1426     ++fibersRun;
1427   });
1428   manager.loopUntilNoReady();
1429
1430   EXPECT_FALSE(baton.try_wait());
1431   EXPECT_EQ(0, fibersRun);
1432
1433   timeoutHandler.scheduleTimeout(std::chrono::milliseconds(250));
1434   std::this_thread::sleep_for(std::chrono::milliseconds(500));
1435
1436   EXPECT_FALSE(baton.try_wait());
1437   EXPECT_EQ(0, fibersRun);
1438
1439   evb.loopOnce();
1440   manager.loopUntilNoReady();
1441
1442   EXPECT_EQ(1, fibersRun);
1443 }
1444
1445 TEST(FiberManager, batonWaitTimeoutMany) {
1446   FiberManager manager(folly::make_unique<EventBaseLoopController>());
1447
1448   folly::EventBase evb;
1449   dynamic_cast<EventBaseLoopController&>(manager.loopController())
1450       .attachEventBase(evb);
1451
1452   constexpr size_t kNumTimeoutTasks = 10000;
1453   size_t tasksCount = kNumTimeoutTasks;
1454
1455   // We add many tasks to hit timeout queue deallocation logic.
1456   for (size_t i = 0; i < kNumTimeoutTasks; ++i) {
1457     manager.addTask([&]() {
1458       Baton baton;
1459       Baton::TimeoutHandler timeoutHandler;
1460
1461       folly::fibers::addTask([&] {
1462         timeoutHandler.scheduleTimeout(std::chrono::milliseconds(1000));
1463       });
1464
1465       baton.wait(timeoutHandler);
1466       if (--tasksCount == 0) {
1467         evb.terminateLoopSoon();
1468       }
1469     });
1470   }
1471
1472   evb.loopForever();
1473 }
1474
1475 TEST(FiberManager, remoteFutureTest) {
1476   FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1477   auto& loopController =
1478       dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1479
1480   int testValue1 = 5;
1481   int testValue2 = 7;
1482   auto f1 = fiberManager.addTaskFuture([&]() { return testValue1; });
1483   auto f2 = fiberManager.addTaskRemoteFuture([&]() { return testValue2; });
1484   loopController.loop([&]() { loopController.stop(); });
1485   auto v1 = f1.get();
1486   auto v2 = f2.get();
1487
1488   EXPECT_EQ(v1, testValue1);
1489   EXPECT_EQ(v2, testValue2);
1490 }
1491
1492 // Test that a void function produes a Future<Unit>.
1493 TEST(FiberManager, remoteFutureVoidUnitTest) {
1494   FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1495   auto& loopController =
1496       dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1497
1498   bool ranLocal = false;
1499   folly::Future<folly::Unit> futureLocal =
1500       fiberManager.addTaskFuture([&]() { ranLocal = true; });
1501
1502   bool ranRemote = false;
1503   folly::Future<folly::Unit> futureRemote =
1504       fiberManager.addTaskRemoteFuture([&]() { ranRemote = true; });
1505
1506   loopController.loop([&]() { loopController.stop(); });
1507
1508   futureLocal.wait();
1509   ASSERT_TRUE(ranLocal);
1510
1511   futureRemote.wait();
1512   ASSERT_TRUE(ranRemote);
1513 }
1514
1515 TEST(FiberManager, nestedFiberManagers) {
1516   folly::EventBase outerEvb;
1517   folly::EventBase innerEvb;
1518
1519   getFiberManager(outerEvb).addTask([&]() {
1520     EXPECT_EQ(
1521         &getFiberManager(outerEvb), FiberManager::getFiberManagerUnsafe());
1522
1523     runInMainContext([&]() {
1524       getFiberManager(innerEvb).addTask([&]() {
1525         EXPECT_EQ(
1526             &getFiberManager(innerEvb), FiberManager::getFiberManagerUnsafe());
1527
1528         innerEvb.terminateLoopSoon();
1529       });
1530
1531       innerEvb.loopForever();
1532     });
1533
1534     EXPECT_EQ(
1535         &getFiberManager(outerEvb), FiberManager::getFiberManagerUnsafe());
1536
1537     outerEvb.terminateLoopSoon();
1538   });
1539
1540   outerEvb.loopForever();
1541 }