folly: build with -Wunused-parameter
[folly.git] / folly / futures / test / FutureTest.cpp
1 /*
2  * Copyright 2015 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 <gtest/gtest.h>
18
19 #include <folly/futures/Future.h>
20 #include <folly/Memory.h>
21 #include <folly/Executor.h>
22 #include <folly/dynamic.h>
23 #include <folly/Baton.h>
24
25 #include <algorithm>
26 #include <atomic>
27 #include <memory>
28 #include <numeric>
29 #include <string>
30 #include <thread>
31 #include <type_traits>
32 #include <unistd.h>
33
34 using namespace folly;
35
36 #define EXPECT_TYPE(x, T) \
37   EXPECT_TRUE((std::is_same<decltype(x), T>::value))
38
39 typedef FutureException eggs_t;
40 static eggs_t eggs("eggs");
41
42 // Future
43
44 TEST(Future, onError) {
45   bool theFlag = false;
46   auto flag = [&]{ theFlag = true; };
47 #define EXPECT_FLAG() \
48   do { \
49     EXPECT_TRUE(theFlag); \
50     theFlag = false; \
51   } while(0);
52
53 #define EXPECT_NO_FLAG() \
54   do { \
55     EXPECT_FALSE(theFlag); \
56     theFlag = false; \
57   } while(0);
58
59   // By reference
60   {
61     auto f = makeFuture().then([] {
62       throw eggs;
63     }).onError([&](eggs_t& /* e */) { flag(); });
64     EXPECT_FLAG();
65     EXPECT_NO_THROW(f.value());
66   }
67
68   {
69     auto f = makeFuture()
70                  .then([] { throw eggs; })
71                  .onError([&](eggs_t& /* e */) {
72                    flag();
73                    return makeFuture();
74                  });
75     EXPECT_FLAG();
76     EXPECT_NO_THROW(f.value());
77   }
78
79   // By value
80   {
81     auto f = makeFuture().then([] {
82       throw eggs;
83     }).onError([&](eggs_t /* e */) { flag(); });
84     EXPECT_FLAG();
85     EXPECT_NO_THROW(f.value());
86   }
87
88   {
89     auto f = makeFuture()
90                  .then([] { throw eggs; })
91                  .onError([&](eggs_t /* e */) {
92                    flag();
93                    return makeFuture();
94                  });
95     EXPECT_FLAG();
96     EXPECT_NO_THROW(f.value());
97   }
98
99   // Polymorphic
100   {
101     auto f = makeFuture().then([] {
102       throw eggs;
103     }).onError([&](std::exception& /* e */) { flag(); });
104     EXPECT_FLAG();
105     EXPECT_NO_THROW(f.value());
106   }
107
108   {
109     auto f = makeFuture()
110                  .then([] { throw eggs; })
111                  .onError([&](std::exception& /* e */) {
112                    flag();
113                    return makeFuture();
114                  });
115     EXPECT_FLAG();
116     EXPECT_NO_THROW(f.value());
117   }
118
119   // Non-exceptions
120   {
121     auto f = makeFuture().then([] {
122       throw - 1;
123     }).onError([&](int /* e */) { flag(); });
124     EXPECT_FLAG();
125     EXPECT_NO_THROW(f.value());
126   }
127
128   {
129     auto f = makeFuture()
130                  .then([] { throw - 1; })
131                  .onError([&](int /* e */) {
132                    flag();
133                    return makeFuture();
134                  });
135     EXPECT_FLAG();
136     EXPECT_NO_THROW(f.value());
137   }
138
139   // Mutable lambda
140   {
141     auto f = makeFuture().then([] {
142       throw eggs;
143     }).onError([&](eggs_t& /* e */) mutable { flag(); });
144     EXPECT_FLAG();
145     EXPECT_NO_THROW(f.value());
146   }
147
148   {
149     auto f = makeFuture()
150                  .then([] { throw eggs; })
151                  .onError([&](eggs_t& /* e */) mutable {
152                    flag();
153                    return makeFuture();
154                  });
155     EXPECT_FLAG();
156     EXPECT_NO_THROW(f.value());
157   }
158
159   // No throw
160   {
161     auto f = makeFuture()
162                  .then([] { return 42; })
163                  .onError([&](eggs_t& /* e */) {
164                    flag();
165                    return -1;
166                  });
167     EXPECT_NO_FLAG();
168     EXPECT_EQ(42, f.value());
169   }
170
171   {
172     auto f = makeFuture()
173                  .then([] { return 42; })
174                  .onError([&](eggs_t& /* e */) {
175                    flag();
176                    return makeFuture<int>(-1);
177                  });
178     EXPECT_NO_FLAG();
179     EXPECT_EQ(42, f.value());
180   }
181
182   // Catch different exception
183   {
184     auto f = makeFuture().then([] {
185       throw eggs;
186     }).onError([&](std::runtime_error& /* e */) { flag(); });
187     EXPECT_NO_FLAG();
188     EXPECT_THROW(f.value(), eggs_t);
189   }
190
191   {
192     auto f = makeFuture()
193                  .then([] { throw eggs; })
194                  .onError([&](std::runtime_error& /* e */) {
195                    flag();
196                    return makeFuture();
197                  });
198     EXPECT_NO_FLAG();
199     EXPECT_THROW(f.value(), eggs_t);
200   }
201
202   // Returned value propagates
203   {
204     auto f = makeFuture().then([] {
205       throw eggs;
206       return 0;
207     }).onError([&](eggs_t& /* e */) { return 42; });
208     EXPECT_EQ(42, f.value());
209   }
210
211   // Returned future propagates
212   {
213     auto f = makeFuture().then([] {
214       throw eggs;
215       return 0;
216     }).onError([&](eggs_t& /* e */) { return makeFuture<int>(42); });
217     EXPECT_EQ(42, f.value());
218   }
219
220   // Throw in callback
221   {
222     auto f = makeFuture()
223       .then([] { throw eggs; return 0; })
224       .onError([&] (eggs_t& e) { throw e; return -1; });
225     EXPECT_THROW(f.value(), eggs_t);
226   }
227
228   {
229     auto f = makeFuture()
230       .then([] { throw eggs; return 0; })
231       .onError([&] (eggs_t& e) { throw e; return makeFuture<int>(-1); });
232     EXPECT_THROW(f.value(), eggs_t);
233   }
234
235   // exception_wrapper, return Future<T>
236   {
237     auto f = makeFuture()
238                  .then([] { throw eggs; })
239                  .onError([&](exception_wrapper /* e */) {
240                    flag();
241                    return makeFuture();
242                  });
243     EXPECT_FLAG();
244     EXPECT_NO_THROW(f.value());
245   }
246
247   // exception_wrapper, return Future<T> but throw
248   {
249     auto f = makeFuture()
250                  .then([] {
251                    throw eggs;
252                    return 0;
253                  })
254                  .onError([&](exception_wrapper /* e */) {
255                    flag();
256                    throw eggs;
257                    return makeFuture<int>(-1);
258                  });
259     EXPECT_FLAG();
260     EXPECT_THROW(f.value(), eggs_t);
261   }
262
263   // exception_wrapper, return T
264   {
265     auto f = makeFuture()
266                  .then([] {
267                    throw eggs;
268                    return 0;
269                  })
270                  .onError([&](exception_wrapper /* e */) {
271                    flag();
272                    return -1;
273                  });
274     EXPECT_FLAG();
275     EXPECT_EQ(-1, f.value());
276   }
277
278   // exception_wrapper, return T but throw
279   {
280     auto f = makeFuture()
281                  .then([] {
282                    throw eggs;
283                    return 0;
284                  })
285                  .onError([&](exception_wrapper /* e */) {
286                    flag();
287                    throw eggs;
288                    return -1;
289                  });
290     EXPECT_FLAG();
291     EXPECT_THROW(f.value(), eggs_t);
292   }
293
294   // const exception_wrapper&
295   {
296     auto f = makeFuture()
297                  .then([] { throw eggs; })
298                  .onError([&](const exception_wrapper& /* e */) {
299                    flag();
300                    return makeFuture();
301                  });
302     EXPECT_FLAG();
303     EXPECT_NO_THROW(f.value());
304   }
305
306 }
307
308 TEST(Future, special) {
309   EXPECT_FALSE(std::is_copy_constructible<Future<int>>::value);
310   EXPECT_FALSE(std::is_copy_assignable<Future<int>>::value);
311   EXPECT_TRUE(std::is_move_constructible<Future<int>>::value);
312   EXPECT_TRUE(std::is_move_assignable<Future<int>>::value);
313 }
314
315 TEST(Future, then) {
316   auto f = makeFuture<std::string>("0")
317     .then([](){
318       return makeFuture<std::string>("1"); })
319     .then([](Try<std::string>&& t) {
320       return makeFuture(t.value() + ";2"); })
321     .then([](const Try<std::string>&& t) {
322       return makeFuture(t.value() + ";3"); })
323     .then([](Try<std::string>& t) {
324       return makeFuture(t.value() + ";4"); })
325     .then([](const Try<std::string>& t) {
326       return makeFuture(t.value() + ";5"); })
327     .then([](Try<std::string> t) {
328       return makeFuture(t.value() + ";6"); })
329     .then([](const Try<std::string> t) {
330       return makeFuture(t.value() + ";7"); })
331     .then([](std::string&& s) {
332       return makeFuture(s + ";8"); })
333     .then([](const std::string&& s) {
334       return makeFuture(s + ";9"); })
335     .then([](std::string& s) {
336       return makeFuture(s + ";10"); })
337     .then([](const std::string& s) {
338       return makeFuture(s + ";11"); })
339     .then([](std::string s) {
340       return makeFuture(s + ";12"); })
341     .then([](const std::string s) {
342       return makeFuture(s + ";13"); })
343   ;
344   EXPECT_EQ(f.value(), "1;2;3;4;5;6;7;8;9;10;11;12;13");
345 }
346
347 TEST(Future, thenTry) {
348   bool flag = false;
349
350   makeFuture<int>(42).then([&](Try<int>&& t) {
351                               flag = true;
352                               EXPECT_EQ(42, t.value());
353                             });
354   EXPECT_TRUE(flag); flag = false;
355
356   makeFuture<int>(42)
357     .then([](Try<int>&& t) { return t.value(); })
358     .then([&](Try<int>&& t) { flag = true; EXPECT_EQ(42, t.value()); });
359   EXPECT_TRUE(flag); flag = false;
360
361   makeFuture().then([&](Try<Unit>&& t) { flag = true; t.value(); });
362   EXPECT_TRUE(flag); flag = false;
363
364   Promise<Unit> p;
365   auto f = p.getFuture().then([&](Try<Unit>&& /* t */) { flag = true; });
366   EXPECT_FALSE(flag);
367   EXPECT_FALSE(f.isReady());
368   p.setValue();
369   EXPECT_TRUE(flag);
370   EXPECT_TRUE(f.isReady());
371 }
372
373 TEST(Future, thenValue) {
374   bool flag = false;
375   makeFuture<int>(42).then([&](int i){
376     EXPECT_EQ(42, i);
377     flag = true;
378   });
379   EXPECT_TRUE(flag); flag = false;
380
381   makeFuture<int>(42)
382     .then([](int i){ return i; })
383     .then([&](int i) { flag = true; EXPECT_EQ(42, i); });
384   EXPECT_TRUE(flag); flag = false;
385
386   makeFuture().then([&]{
387     flag = true;
388   });
389   EXPECT_TRUE(flag); flag = false;
390
391   auto f = makeFuture<int>(eggs).then([&](int /* i */) {});
392   EXPECT_THROW(f.value(), eggs_t);
393
394   f = makeFuture<Unit>(eggs).then([&]{});
395   EXPECT_THROW(f.value(), eggs_t);
396 }
397
398 TEST(Future, thenValueFuture) {
399   bool flag = false;
400   makeFuture<int>(42)
401     .then([](int i){ return makeFuture<int>(std::move(i)); })
402     .then([&](Try<int>&& t) { flag = true; EXPECT_EQ(42, t.value()); });
403   EXPECT_TRUE(flag); flag = false;
404
405   makeFuture().then([] {
406     return makeFuture();
407   }).then([&](Try<Unit>&& /* t */) { flag = true; });
408   EXPECT_TRUE(flag); flag = false;
409 }
410
411 static std::string doWorkStatic(Try<std::string>&& t) {
412   return t.value() + ";static";
413 }
414
415 TEST(Future, thenFunction) {
416   struct Worker {
417     std::string doWork(Try<std::string>&& t) {
418       return t.value() + ";class";
419     }
420     static std::string doWorkStatic(Try<std::string>&& t) {
421       return t.value() + ";class-static";
422     }
423   } w;
424
425   auto f = makeFuture<std::string>("start")
426     .then(doWorkStatic)
427     .then(Worker::doWorkStatic)
428     .then(&Worker::doWork, &w);
429
430   EXPECT_EQ(f.value(), "start;static;class-static;class");
431 }
432
433 static Future<std::string> doWorkStaticFuture(Try<std::string>&& t) {
434   return makeFuture(t.value() + ";static");
435 }
436
437 TEST(Future, thenFunctionFuture) {
438   struct Worker {
439     Future<std::string> doWorkFuture(Try<std::string>&& t) {
440       return makeFuture(t.value() + ";class");
441     }
442     static Future<std::string> doWorkStaticFuture(Try<std::string>&& t) {
443       return makeFuture(t.value() + ";class-static");
444     }
445   } w;
446
447   auto f = makeFuture<std::string>("start")
448     .then(doWorkStaticFuture)
449     .then(Worker::doWorkStaticFuture)
450     .then(&Worker::doWorkFuture, &w);
451
452   EXPECT_EQ(f.value(), "start;static;class-static;class");
453 }
454
455 TEST(Future, thenStdFunction) {
456   {
457     std::function<int()> fn = [](){ return 42; };
458     auto f = makeFuture().then(std::move(fn));
459     EXPECT_EQ(f.value(), 42);
460   }
461   {
462     std::function<int(int)> fn = [](int i){ return i + 23; };
463     auto f = makeFuture(19).then(std::move(fn));
464     EXPECT_EQ(f.value(), 42);
465   }
466   {
467     std::function<int(Try<int>&)> fn = [](Try<int>& t){ return t.value() + 2; };
468     auto f = makeFuture(1).then(std::move(fn));
469     EXPECT_EQ(f.value(), 3);
470   }
471   {
472     bool flag = false;
473     std::function<void()> fn = [&flag](){ flag = true; };
474     auto f = makeFuture().then(std::move(fn));
475     EXPECT_TRUE(f.isReady());
476     EXPECT_TRUE(flag);
477   }
478 }
479
480 TEST(Future, thenBind) {
481   auto l = []() {
482     return makeFuture("bind");
483   };
484   auto b = std::bind(l);
485   auto f = makeFuture().then(std::move(b));
486   EXPECT_EQ(f.value(), "bind");
487 }
488
489 TEST(Future, thenBindTry) {
490   auto l = [](Try<std::string>&& t) {
491     return makeFuture(t.value() + ";bind");
492   };
493   auto b = std::bind(l, std::placeholders::_1);
494   auto f = makeFuture<std::string>("start").then(std::move(b));
495
496   EXPECT_EQ(f.value(), "start;bind");
497 }
498
499 TEST(Future, value) {
500   auto f = makeFuture(std::unique_ptr<int>(new int(42)));
501   auto up = std::move(f.value());
502   EXPECT_EQ(42, *up);
503
504   EXPECT_THROW(makeFuture<int>(eggs).value(), eggs_t);
505 }
506
507 TEST(Future, isReady) {
508   Promise<int> p;
509   auto f = p.getFuture();
510   EXPECT_FALSE(f.isReady());
511   p.setValue(42);
512   EXPECT_TRUE(f.isReady());
513   }
514
515 TEST(Future, futureNotReady) {
516   Promise<int> p;
517   Future<int> f = p.getFuture();
518   EXPECT_THROW(f.value(), eggs_t);
519 }
520
521 TEST(Future, hasException) {
522   EXPECT_TRUE(makeFuture<int>(eggs).getTry().hasException());
523   EXPECT_FALSE(makeFuture(42).getTry().hasException());
524 }
525
526 TEST(Future, hasValue) {
527   EXPECT_TRUE(makeFuture(42).getTry().hasValue());
528   EXPECT_FALSE(makeFuture<int>(eggs).getTry().hasValue());
529 }
530
531 TEST(Future, makeFuture) {
532   EXPECT_TYPE(makeFuture(42), Future<int>);
533   EXPECT_EQ(42, makeFuture(42).value());
534
535   EXPECT_TYPE(makeFuture<float>(42), Future<float>);
536   EXPECT_EQ(42, makeFuture<float>(42).value());
537
538   auto fun = [] { return 42; };
539   EXPECT_TYPE(makeFutureWith(fun), Future<int>);
540   EXPECT_EQ(42, makeFutureWith(fun).value());
541
542   auto funf = [] { return makeFuture<int>(43); };
543   EXPECT_TYPE(makeFutureWith(funf), Future<int>);
544   EXPECT_EQ(43, makeFutureWith(funf).value());
545
546   auto failfun = []() -> int { throw eggs; };
547   EXPECT_TYPE(makeFutureWith(failfun), Future<int>);
548   EXPECT_NO_THROW(makeFutureWith(failfun));
549   EXPECT_THROW(makeFutureWith(failfun).value(), eggs_t);
550
551   auto failfunf = []() -> Future<int> { throw eggs; };
552   EXPECT_TYPE(makeFutureWith(failfunf), Future<int>);
553   EXPECT_NO_THROW(makeFutureWith(failfunf));
554   EXPECT_THROW(makeFutureWith(failfunf).value(), eggs_t);
555
556   EXPECT_TYPE(makeFuture(), Future<Unit>);
557 }
558
559 TEST(Future, finish) {
560   auto x = std::make_shared<int>(0);
561   {
562     Promise<int> p;
563     auto f = p.getFuture().then([x](Try<int>&& t) { *x = t.value(); });
564
565     // The callback hasn't executed
566     EXPECT_EQ(0, *x);
567
568     // The callback has a reference to x
569     EXPECT_EQ(2, x.use_count());
570
571     p.setValue(42);
572
573     // the callback has executed
574     EXPECT_EQ(42, *x);
575   }
576   // the callback has been destructed
577   // and has released its reference to x
578   EXPECT_EQ(1, x.use_count());
579 }
580
581 TEST(Future, unwrap) {
582   Promise<int> a;
583   Promise<int> b;
584
585   auto fa = a.getFuture();
586   auto fb = b.getFuture();
587
588   bool flag1 = false;
589   bool flag2 = false;
590
591   // do a, then do b, and get the result of a + b.
592   Future<int> f = fa.then([&](Try<int>&& ta) {
593     auto va = ta.value();
594     flag1 = true;
595     return fb.then([va, &flag2](Try<int>&& tb) {
596       flag2 = true;
597       return va + tb.value();
598     });
599   });
600
601   EXPECT_FALSE(flag1);
602   EXPECT_FALSE(flag2);
603   EXPECT_FALSE(f.isReady());
604
605   a.setValue(3);
606   EXPECT_TRUE(flag1);
607   EXPECT_FALSE(flag2);
608   EXPECT_FALSE(f.isReady());
609
610   b.setValue(4);
611   EXPECT_TRUE(flag1);
612   EXPECT_TRUE(flag2);
613   EXPECT_EQ(7, f.value());
614 }
615
616 TEST(Future, throwCaughtInImmediateThen) {
617   // Neither of these should throw "Promise already satisfied"
618   makeFuture().then(
619     [=](Try<Unit>&&) -> int { throw std::exception(); });
620   makeFuture().then(
621     [=](Try<Unit>&&) -> Future<int> { throw std::exception(); });
622 }
623
624 TEST(Future, throwIfFailed) {
625   makeFuture<Unit>(eggs)
626     .then([=](Try<Unit>&& t) {
627       EXPECT_THROW(t.throwIfFailed(), eggs_t);
628     });
629   makeFuture()
630     .then([=](Try<Unit>&& t) {
631       EXPECT_NO_THROW(t.throwIfFailed());
632     });
633
634   makeFuture<int>(eggs)
635     .then([=](Try<int>&& t) {
636       EXPECT_THROW(t.throwIfFailed(), eggs_t);
637     });
638   makeFuture<int>(42)
639     .then([=](Try<int>&& t) {
640       EXPECT_NO_THROW(t.throwIfFailed());
641     });
642 }
643
644 TEST(Future, getFutureAfterSetValue) {
645   Promise<int> p;
646   p.setValue(42);
647   EXPECT_EQ(42, p.getFuture().value());
648 }
649
650 TEST(Future, getFutureAfterSetException) {
651   Promise<Unit> p;
652   p.setWith([]() -> void { throw std::logic_error("foo"); });
653   EXPECT_THROW(p.getFuture().value(), std::logic_error);
654 }
655
656 TEST(Future, detachRace) {
657   // Task #5438209
658   // This test is designed to detect a race that was in Core::detachOne()
659   // where detached_ was incremented and then tested, and that
660   // allowed a race where both Promise and Future would think they were the
661   // second and both try to delete. This showed up at scale but was very
662   // difficult to reliably repro in a test. As it is, this only fails about
663   // once in every 1,000 executions. Doing this 1,000 times is going to make a
664   // slow test so I won't do that but if it ever fails, take it seriously, and
665   // run the test binary with "--gtest_repeat=10000 --gtest_filter=*detachRace"
666   // (Don't forget to enable ASAN)
667   auto p = folly::make_unique<Promise<bool>>();
668   auto f = folly::make_unique<Future<bool>>(p->getFuture());
669   folly::Baton<> baton;
670   std::thread t1([&]{
671     baton.post();
672     p.reset();
673   });
674   baton.wait();
675   f.reset();
676   t1.join();
677 }
678
679 // Test of handling of a circular dependency. It's never recommended
680 // to have one because of possible memory leaks. Here we test that
681 // we can handle freeing of the Future while it is running.
682 TEST(Future, CircularDependencySharedPtrSelfReset) {
683   Promise<int64_t> promise;
684   auto ptr = std::make_shared<Future<int64_t>>(promise.getFuture());
685
686   ptr->then([ptr](folly::Try<int64_t>&& /* uid */) mutable {
687     EXPECT_EQ(1, ptr.use_count());
688
689     // Leaving no references to ourselves.
690     ptr.reset();
691     EXPECT_EQ(0, ptr.use_count());
692   });
693
694   EXPECT_EQ(2, ptr.use_count());
695
696   ptr.reset();
697
698   promise.setValue(1);
699 }
700
701 TEST(Future, Constructor) {
702   auto f1 = []() -> Future<int> { return Future<int>(3); }();
703   EXPECT_EQ(f1.value(), 3);
704   auto f2 = []() -> Future<Unit> { return Future<Unit>(); }();
705   EXPECT_NO_THROW(f2.value());
706 }
707
708 TEST(Future, ImplicitConstructor) {
709   auto f1 = []() -> Future<int> { return 3; }();
710   EXPECT_EQ(f1.value(), 3);
711   // Unfortunately, the C++ standard does not allow the
712   // following implicit conversion to work:
713   //auto f2 = []() -> Future<Unit> { }();
714 }
715
716 TEST(Future, thenDynamic) {
717   // folly::dynamic has a constructor that takes any T, this test makes
718   // sure that we call the then lambda with folly::dynamic and not
719   // Try<folly::dynamic> because that then fails to compile
720   Promise<folly::dynamic> p;
721   Future<folly::dynamic> f = p.getFuture().then(
722       [](const folly::dynamic& d) {
723         return folly::dynamic(d.asInt() + 3);
724       }
725   );
726   p.setValue(2);
727   EXPECT_EQ(f.get(), 5);
728 }
729
730 TEST(Future, RequestContext) {
731   class NewThreadExecutor : public Executor {
732    public:
733     ~NewThreadExecutor() override {
734       std::for_each(v_.begin(), v_.end(), [](std::thread& t){ t.join(); });
735     }
736     void add(Func f) override {
737       if (throwsOnAdd_) { throw std::exception(); }
738       v_.emplace_back(std::move(f));
739     }
740     void addWithPriority(Func f, int8_t /* prio */) override {
741       add(std::move(f));
742     }
743     uint8_t getNumPriorities() const override { return numPriorities_; }
744
745     void setHandlesPriorities() { numPriorities_ = 2; }
746     void setThrowsOnAdd() { throwsOnAdd_ = true; }
747    private:
748     std::vector<std::thread> v_;
749     uint8_t numPriorities_ = 1;
750     bool throwsOnAdd_ = false;
751   };
752
753   struct MyRequestData : RequestData {
754     MyRequestData(bool value = false) : value(value) {}
755     bool value;
756   };
757
758   NewThreadExecutor e;
759   RequestContext::create();
760   RequestContext::get()->setContextData("key",
761       folly::make_unique<MyRequestData>(true));
762   auto checker = [](int lineno) {
763     return [lineno](Try<int>&& /* t */) {
764       auto d = static_cast<MyRequestData*>(
765         RequestContext::get()->getContextData("key"));
766       EXPECT_TRUE(d && d->value) << "on line " << lineno;
767     };
768   };
769
770   makeFuture(1).via(&e).then(checker(__LINE__));
771
772   e.setHandlesPriorities();
773   makeFuture(2).via(&e).then(checker(__LINE__));
774
775   Promise<int> p1, p2;
776   p1.getFuture().then(checker(__LINE__));
777
778   e.setThrowsOnAdd();
779   p2.getFuture().via(&e).then(checker(__LINE__));
780
781   RequestContext::create();
782   p1.setValue(3);
783   p2.setValue(4);
784 }
785
786 TEST(Future, makeFutureNoThrow) {
787   makeFuture().value();
788 }