1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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/executors/ThreadedExecutor.h>
18 
19 #include <stdexcept>
20 
21 #include <folly/Conv.h>
22 #include <folly/futures/Future.h>
23 #include <folly/gen/Base.h>
24 #include <folly/portability/GTest.h>
25 
26 namespace {
27 
28 class ThreadedExecutorTest : public testing::Test {};
29 } // namespace
30 
TEST_F(ThreadedExecutorTest,example)31 TEST_F(ThreadedExecutorTest, example) {
32   folly::ThreadedExecutor x;
33   auto ret = folly::via(&x)
34                  .thenValue([&](auto&&) { return 42; })
35                  .thenValue([&](int n) { return folly::to<std::string>(n); })
36                  .get();
37 
38   EXPECT_EQ("42", ret);
39 }
40 
TEST_F(ThreadedExecutorTest,exception)41 TEST_F(ThreadedExecutorTest, exception) {
42   folly::ThreadedExecutor x;
43   x.add([] { throw std::runtime_error("This should not crash the program"); });
44 }
45 
TEST_F(ThreadedExecutorTest,dtor_waits)46 TEST_F(ThreadedExecutorTest, dtor_waits) {
47   constexpr auto kDelay = std::chrono::milliseconds(100);
48   auto x = std::make_unique<folly::ThreadedExecutor>();
49   auto fut = folly::via(&*x, [&] { /* sleep override */
50                                    std::this_thread::sleep_for(kDelay);
51   });
52   x = nullptr;
53 
54   EXPECT_TRUE(fut.isReady());
55 }
56 
TEST_F(ThreadedExecutorTest,many)57 TEST_F(ThreadedExecutorTest, many) {
58   constexpr auto kNumTasks = 1024;
59   folly::ThreadedExecutor x;
60   auto rets =
61       folly::collect(
62           folly::gen::range<size_t>(0, kNumTasks) |
63           folly::gen::map([&](size_t i) {
64             return folly::via(&x)
65                 .thenValue([=](auto&&) { return i; })
66                 .thenValue([](size_t k) { return folly::to<std::string>(k); });
67           }) |
68           folly::gen::as<std::vector>())
69           .get();
70 
71   EXPECT_EQ("42", rets[42]);
72 }
73 
TEST_F(ThreadedExecutorTest,many_sleeping_constant_time)74 TEST_F(ThreadedExecutorTest, many_sleeping_constant_time) {
75   constexpr auto kNumTasks = 256;
76   constexpr auto kDelay = std::chrono::milliseconds(100);
77   folly::ThreadedExecutor x;
78   auto rets =
79       folly::collect(
80           folly::gen::range<size_t>(0, kNumTasks) |
81           folly::gen::map([&](size_t i) {
82             return folly::via(&x)
83                 .thenValue([=](auto&&) {
84                   /* sleep override */ std::this_thread::sleep_for(kDelay);
85                 })
86                 .thenValue([=](auto&&) { return i; })
87                 .thenValue([](size_t k) { return folly::to<std::string>(k); });
88           }) |
89           folly::gen::as<std::vector>())
90           .get();
91 
92   EXPECT_EQ("42", rets[42]);
93 }
94 
TEST_F(ThreadedExecutorTest,many_sleeping_decreasing_time)95 TEST_F(ThreadedExecutorTest, many_sleeping_decreasing_time) {
96   constexpr auto kNumTasks = 256;
97   constexpr auto kDelay = std::chrono::milliseconds(100);
98   folly::ThreadedExecutor x;
99   auto rets =
100       folly::collect(
101           folly::gen::range<size_t>(0, kNumTasks) |
102           folly::gen::map([&](size_t i) {
103             return folly::via(&x)
104                 .thenValue([=](auto&&) {
105                   auto delay = kDelay * (kNumTasks - i) / kNumTasks;
106                   /* sleep override */ std::this_thread::sleep_for(delay);
107                 })
108                 .thenValue([=](auto&&) { return i; })
109                 .thenValue([](size_t k) { return folly::to<std::string>(k); });
110           }) |
111           folly::gen::as<std::vector>())
112           .get();
113 
114   EXPECT_EQ("42", rets[42]);
115 }
116