proxygen
ExecutorTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present 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 
20 #include <folly/futures/Future.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) {
31  size_t count = 0;
32  auto f1 = [&]() { count++; };
33  auto f2 = [&]() {
34  x.add(f1);
35  x.add(f1);
36  };
37  x.add(f2);
38  x.run();
39  EXPECT_EQ(count, 0);
40 
41  // ManualExecutor's destructor drains, so explicitly clear the two added by
42  // f2.
43  EXPECT_EQ(2, x.clear());
44 }
45 
46 TEST(ManualExecutor, drainIsNotStable) {
48  size_t count = 0;
49  auto f1 = [&]() { count++; };
50  auto f2 = [&]() {
51  x.add(f1);
52  x.add(f1);
53  };
54  x.add(f2);
55  x.drain();
56  EXPECT_EQ(count, 2);
57 }
58 
59 TEST(ManualExecutor, scheduleDur) {
61  size_t count = 0;
62  std::chrono::milliseconds dur{10};
63  x.schedule([&] { count++; }, dur);
64  EXPECT_EQ(count, 0);
65  x.run();
66  EXPECT_EQ(count, 0);
67  x.advance(dur / 2);
68  EXPECT_EQ(count, 0);
69  x.advance(dur / 2);
70  EXPECT_EQ(count, 1);
71 }
72 
73 TEST(ManualExecutor, laterThingsDontBlockEarlierOnes) {
75  auto first = false;
76  std::chrono::milliseconds dur{10};
77  x.schedule([&] { first = true; }, dur);
78  x.schedule([] {}, 2 * dur);
80  x.advance(dur);
82 }
83 
84 TEST(ManualExecutor, orderWillNotBeQuestioned) {
86  auto first = false;
87  auto second = false;
88  std::chrono::milliseconds dur{10};
89  x.schedule([&] { first = true; }, dur);
90  x.schedule([&] { second = true; }, 2 * dur);
92  EXPECT_FALSE(second);
93  x.advance(dur);
95  EXPECT_FALSE(second);
96  x.advance(dur);
98  EXPECT_TRUE(second);
99 }
100 
101 TEST(ManualExecutor, evenWhenYouSkipAheadEventsRunInProperOrder) {
103  auto counter = 0;
104  auto first = 0;
105  auto second = 0;
106  std::chrono::milliseconds dur{10};
107  x.schedule([&] { first = ++counter; }, dur);
108  x.schedule([&] { second = ++counter; }, 2 * dur);
109  EXPECT_EQ(first, 0);
110  EXPECT_EQ(second, 0);
111  x.advance(3 * dur);
112  EXPECT_EQ(first, 1);
113  EXPECT_EQ(second, 2);
114 }
115 
116 TEST(ManualExecutor, clockStartsAt0) {
118  EXPECT_EQ(x.now(), x.now().min());
119 }
120 
121 TEST(ManualExecutor, scheduleAbs) {
123  size_t count = 0;
124  x.scheduleAt([&] { count++; }, x.now() + std::chrono::milliseconds(10));
125  EXPECT_EQ(count, 0);
126  x.advance(std::chrono::milliseconds(10));
127  EXPECT_EQ(count, 1);
128 }
129 
130 TEST(ManualExecutor, advanceTo) {
132  size_t count = 0;
133  x.scheduleAt([&] { count++; }, std::chrono::steady_clock::now());
134  EXPECT_EQ(count, 0);
136  EXPECT_EQ(count, 1);
137 }
138 
139 TEST(ManualExecutor, advanceBack) {
141  size_t count = 0;
142  x.advance(std::chrono::microseconds(5));
143  x.schedule([&] { count++; }, std::chrono::microseconds(6));
144  EXPECT_EQ(count, 0);
145  x.advanceTo(x.now() - std::chrono::microseconds(1));
146  EXPECT_EQ(count, 0);
147 }
148 
149 TEST(ManualExecutor, advanceNeg) {
151  size_t count = 0;
152  x.advance(std::chrono::microseconds(5));
153  x.schedule([&] { count++; }, std::chrono::microseconds(6));
154  EXPECT_EQ(count, 0);
155  x.advance(std::chrono::microseconds(-1));
156  EXPECT_EQ(count, 0);
157 }
158 
159 TEST(ManualExecutor, waitForDoesNotDeadlock) {
160  ManualExecutor east, west;
161  folly::Baton<> baton;
162  auto f = makeFuture()
163  .via(&east)
164  .then([](Try<Unit>) { return makeFuture(); })
165  .via(&west);
166  std::thread t([&] {
167  baton.post();
168  west.waitFor(f);
169  });
170  baton.wait();
171  east.run();
172  t.join();
173 }
174 
175 TEST(ManualExecutor, getViaDoesNotDeadlock) {
176  ManualExecutor east, west;
177  folly::Baton<> baton;
178  auto f = makeFuture()
179  .via(&east)
180  .then([](Try<Unit>) { return makeFuture(); })
181  .via(&west);
182  std::thread t([&] {
183  baton.post();
184  f.getVia(&west);
185  });
186  baton.wait();
187  east.run();
188  t.join();
189 }
190 
193  size_t count = 0;
194  x.add([&] { ++count; });
195  x.scheduleAt([&] { ++count; }, x.now() + std::chrono::milliseconds(10));
196  EXPECT_EQ(0, count);
197 
198  x.clear();
199  x.advance(std::chrono::milliseconds(10));
200  x.run();
201  EXPECT_EQ(0, count);
202 }
203 
204 TEST(ManualExecutor, drainsOnDestruction) {
205  size_t count = 0;
206  {
208  x.add([&] { ++count; });
209  }
210  EXPECT_EQ(1, count);
211 }
212 
215  size_t counter = 0;
216  x.add([&] {
217  x.add([&] {
218  EXPECT_EQ(counter, 0);
219  counter++;
220  });
221  EXPECT_EQ(counter, 1);
222  counter++;
223  });
224  EXPECT_EQ(counter, 2);
225 }
226 
229  size_t counter = 0;
230  x.add([&] {
231  x.add([&] {
232  EXPECT_EQ(1, counter);
233  counter++;
234  });
235  EXPECT_EQ(0, counter);
236  counter++;
237  });
238  EXPECT_EQ(2, counter);
239 }
240 
241 TEST(Executor, Runnable) {
243  size_t counter = 0;
244  struct Runnable {
245  std::function<void()> fn;
246  void operator()() {
247  fn();
248  }
249  };
250  Runnable f;
251  f.fn = [&] { counter++; };
252  x.add(f);
253  EXPECT_EQ(counter, 1);
254 }
255 
256 TEST(Executor, ThrowableThen) {
258  auto f = Future<Unit>().thenValue(
259  [](auto&&) { throw std::runtime_error("Faildog"); });
260 
261  /*
262  auto f = Future<Unit>().via(&x).then([](){
263  throw std::runtime_error("Faildog");
264  });*/
265  EXPECT_THROW(f.value(), std::exception);
266 }
267 
268 class CrappyExecutor : public Executor {
269  public:
270  void add(Func /* f */) override {
271  throw std::runtime_error("bad");
272  }
273 };
274 
277  bool flag = false;
278  auto f = folly::via(&x).onError([&](std::runtime_error& e) {
279  EXPECT_STREQ("bad", e.what());
280  flag = true;
281  });
282  EXPECT_TRUE(flag);
283 }
284 
285 class DoNothingExecutor : public Executor {
286  public:
287  void add(Func f) override {
288  storedFunc_ = std::move(f);
289  }
290 
291  private:
293 };
294 
297 
298  // Submit future callback to DoNothingExecutor
299  auto f = folly::via(&x).thenValue([](auto&&) { return 42; });
300 
301  // Callback function is stored in DoNothingExecutor, but not executed.
302  EXPECT_FALSE(f.isReady());
303 
304  // Destroy the function stored in DoNothingExecutor. The future callback
305  // will never get executed.
306  x.add({});
307 
308  EXPECT_TRUE(f.isReady());
310 }
auto f
void add(Func) override
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
void scheduleAt(Func &&f, TimePoint const &t) override
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::chrono::steady_clock::time_point now()
const int x
void waitFor(F const &f)
makeProgress until this Future is ready.
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
static once_flag flag
Definition: Random.cpp:75
void schedule(Func &&a)
Alias for add() (for Rx consistency)
void advance(Duration const &dur)
#define EXPECT_STREQ(s1, s2)
Definition: gtest.h:1995
FOLLY_ALWAYS_INLINE void wait(const WaitOptions &opt=wait_options()) noexcept
Definition: Baton.h:170
Function< void()> Func
Definition: Executor.h:27
void advanceTo(TimePoint const &t)
void add(Func f) override
Definition: Try.h:51
void post() noexcept
Definition: Baton.h:123
TimePoint now() override
Get this executor&#39;s notion of time. Must be threadsafe.
int * count
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
std::atomic< int > counter
auto via(Executor *x, Func &&func) -> Future< typename isFutureOrSemiFuture< decltype(std::declval< Func >()())>::Inner >
Definition: Future-inl.h:1290
void add(Func f) override
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
TEST(SequencedExecutor, CPUThreadPoolExecutor)
void add(Func) override
Future< typename std::decay< T >::type > makeFuture(T &&t)
Definition: Future-inl.h:1310
constexpr detail::First first
Definition: Base-inl.h:2553