proxygen
TimekeeperTest.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 
17 #include <folly/Singleton.h>
19 #include <folly/futures/Future.h>
22 
23 using namespace folly;
24 using std::chrono::milliseconds;
25 
26 std::chrono::milliseconds const zero_ms(0);
27 std::chrono::milliseconds const one_ms(1);
28 std::chrono::milliseconds const awhile(10);
29 std::chrono::seconds const too_long(10);
30 
31 std::chrono::steady_clock::time_point now() {
33 }
34 
37 
38  std::shared_ptr<Timekeeper> timeLord_;
39 };
40 
42  auto t1 = now();
43  auto f = timeLord_->after(awhile);
44  EXPECT_FALSE(f.isReady());
45  std::move(f).get();
46  auto t2 = now();
47 
48  EXPECT_GE(t2 - t1, awhile);
49 }
50 
51 TEST(Timekeeper, futureGet) {
52  Promise<int> p;
53  auto t = std::thread([&] { p.setValue(42); });
54  EXPECT_EQ(42, p.getFuture().get());
55  t.join();
56 }
57 
58 TEST(Timekeeper, futureGetBeforeTimeout) {
59  Promise<int> p;
60  auto t = std::thread([&] { p.setValue(42); });
61  // Technically this is a race and if the test server is REALLY overloaded
62  // and it takes more than a second to do that thread it could be flaky. But
63  // I want a low timeout (in human terms) so if this regresses and someone
64  // runs it by hand they're not sitting there forever wondering why it's
65  // blocked, and get a useful error message instead. If it does get flaky,
66  // empirically increase the timeout to the point where it's very improbable.
67  EXPECT_EQ(42, p.getFuture().get(std::chrono::seconds(2)));
68  t.join();
69 }
70 
71 TEST(Timekeeper, futureGetTimeout) {
72  Promise<int> p;
74 }
75 
76 TEST(Timekeeper, futureSleep) {
77  auto t1 = now();
78  futures::sleep(one_ms).get();
79  EXPECT_GE(now() - t1, one_ms);
80 }
81 
82 TEST(Timekeeper, futureSleepHandlesNullTimekeeperSingleton) {
83  Singleton<ThreadWheelTimekeeper>::make_mock([] { return nullptr; });
84  SCOPE_EXIT {
86  };
88 }
89 
90 TEST(Timekeeper, futureWithinHandlesNullTimekeeperSingleton) {
91  Singleton<ThreadWheelTimekeeper>::make_mock([] { return nullptr; });
92  SCOPE_EXIT {
94  };
95  Promise<int> p;
96  auto f = p.getFuture().within(one_ms);
98 }
99 
100 TEST(Timekeeper, semiFutureWithinHandlesNullTimekeeperSingleton) {
101  Singleton<ThreadWheelTimekeeper>::make_mock([] { return nullptr; });
102  SCOPE_EXIT {
104  };
105  Promise<int> p;
106  auto f = p.getSemiFuture().within(one_ms);
108 }
109 
110 TEST(Timekeeper, futureDelayed) {
111  auto t1 = now();
112  auto dur = makeFuture()
113  .delayed(one_ms)
114  .thenValue([=](auto&&) { return now() - t1; })
115  .get();
116 
117  EXPECT_GE(dur, one_ms);
118 }
119 
120 TEST(Timekeeper, semiFutureDelayed) {
121  auto t1 = now();
122  auto dur = makeSemiFuture()
123  .delayed(one_ms)
124  .toUnsafeFuture()
125  .thenValue([=](auto&&) { return now() - t1; })
126  .get();
127 
128  EXPECT_GE(dur, one_ms);
129 }
130 
131 TEST(Timekeeper, futureDelayedUnsafe) {
132  auto t1 = now();
133  auto dur = makeFuture()
134  .delayedUnsafe(one_ms)
135  .thenValue([=](auto&&) { return now() - t1; })
136  .get();
137 
138  EXPECT_GE(dur, one_ms);
139 }
140 
141 TEST(Timekeeper, futureDelayedStickyExecutor) {
142  // Check that delayed without an executor binds the inline executor.
143  {
144  auto t1 = now();
145  class TimekeeperHelper : public ThreadWheelTimekeeper {
146  public:
147  std::thread::id get_thread_id() {
148  return thread_.get_id();
149  }
150  };
151  TimekeeperHelper tk;
152  std::thread::id timekeeper_thread_id = tk.get_thread_id();
153  std::thread::id task_thread_id{};
154  auto dur = makeFuture()
155  .delayed(one_ms, &tk)
156  .thenValue([=, &task_thread_id](auto&&) {
157  task_thread_id = std::this_thread::get_id();
158  return now() - t1;
159  })
160  .get();
161 
162  EXPECT_GE(dur, one_ms);
163  EXPECT_EQ(timekeeper_thread_id, task_thread_id);
164  }
165 
166  // Check that delayed applied to an executor returns a future that binds
167  // to the same executor as was input.
168  {
169  auto t1 = now();
170  std::thread::id driver_thread_id{};
171  std::thread::id first_task_thread_id{};
172  std::thread::id second_task_thread_id{};
174  std::atomic<bool> stop_signal{false};
175  std::thread me_driver{[&me, &driver_thread_id, &stop_signal] {
176  driver_thread_id = std::this_thread::get_id();
177  while (!stop_signal) {
178  me.run();
179  }
180  }};
181  auto dur = makeSemiFuture()
182  .via(&me)
183  .thenValue([&first_task_thread_id](auto&&) {
184  first_task_thread_id = std::this_thread::get_id();
185  })
186  .delayed(one_ms)
187  .thenValue([=, &second_task_thread_id](auto&&) {
188  second_task_thread_id = std::this_thread::get_id();
189  return now() - t1;
190  })
191  .get();
192  stop_signal = true;
193  me_driver.join();
194  EXPECT_GE(dur, one_ms);
195  EXPECT_EQ(driver_thread_id, first_task_thread_id);
196  EXPECT_EQ(driver_thread_id, second_task_thread_id);
197  }
198 }
199 
200 TEST(Timekeeper, futureWithinThrows) {
201  Promise<int> p;
202  auto f =
203  p.getFuture().within(one_ms).onError([](FutureTimeout&) { return -1; });
204 
205  EXPECT_EQ(-1, std::move(f).get());
206 }
207 
208 TEST(Timekeeper, semiFutureWithinThrows) {
209  Promise<int> p;
210  auto f = p.getSemiFuture().within(one_ms).toUnsafeFuture().onError(
211  [](FutureTimeout&) { return -1; });
212 
213  EXPECT_EQ(-1, std::move(f).get());
214 }
215 
216 TEST(Timekeeper, futureWithinAlreadyComplete) {
217  auto f =
218  makeFuture(42).within(one_ms).onError([&](FutureTimeout&) { return -1; });
219 
220  EXPECT_EQ(42, std::move(f).get());
221 }
222 
223 TEST(Timekeeper, semiFutureWithinAlreadyComplete) {
224  auto f = makeSemiFuture(42).within(one_ms).toUnsafeFuture().onError(
225  [&](FutureTimeout&) { return -1; });
226 
227  EXPECT_EQ(42, std::move(f).get());
228 }
229 
230 TEST(Timekeeper, futureWithinFinishesInTime) {
231  Promise<int> p;
232  auto f = p.getFuture()
233  .within(std::chrono::minutes(1))
234  .onError([&](FutureTimeout&) { return -1; });
235  p.setValue(42);
236 
237  EXPECT_EQ(42, std::move(f).get());
238 }
239 
240 TEST(Timekeeper, semiFutureWithinFinishesInTime) {
241  Promise<int> p;
242  auto f = p.getSemiFuture()
243  .within(std::chrono::minutes(1))
244  .toUnsafeFuture()
245  .onError([&](FutureTimeout&) { return -1; });
246  p.setValue(42);
247 
248  EXPECT_EQ(42, std::move(f).get());
249 }
250 
251 TEST(Timekeeper, futureWithinVoidSpecialization) {
252  makeFuture().within(one_ms);
253 }
254 
255 TEST(Timekeeper, semiFutureWithinVoidSpecialization) {
256  makeSemiFuture().within(one_ms);
257 }
258 
259 TEST(Timekeeper, futureWithinException) {
260  Promise<Unit> p;
261  auto f = p.getFuture().within(awhile, std::runtime_error("expected"));
262  EXPECT_THROW(std::move(f).get(), std::runtime_error);
263 }
264 
265 TEST(Timekeeper, semiFutureWithinException) {
266  Promise<Unit> p;
267  auto f = p.getSemiFuture().within(awhile, std::runtime_error("expected"));
268  EXPECT_THROW(std::move(f).get(), std::runtime_error);
269 }
270 
271 TEST(Timekeeper, onTimeout) {
272  bool flag = false;
273  makeFuture(42)
274  .delayed(10 * one_ms)
275  .onTimeout(
276  zero_ms,
277  [&] {
278  flag = true;
279  return -1;
280  })
281  .get();
282  EXPECT_TRUE(flag);
283 }
284 
285 TEST(Timekeeper, onTimeoutComplete) {
286  bool flag = false;
287  makeFuture(42)
288  .onTimeout(
289  zero_ms,
290  [&] {
291  flag = true;
292  return -1;
293  })
294  .get();
295  EXPECT_FALSE(flag);
296 }
297 
298 TEST(Timekeeper, onTimeoutReturnsFuture) {
299  bool flag = false;
300  makeFuture(42)
301  .delayed(10 * one_ms)
302  .onTimeout(
303  zero_ms,
304  [&] {
305  flag = true;
306  return makeFuture(-1);
307  })
308  .get();
309  EXPECT_TRUE(flag);
310 }
311 
312 TEST(Timekeeper, onTimeoutVoid) {
313  makeFuture().delayed(one_ms).onTimeout(zero_ms, [&] {});
314  makeFuture().delayed(one_ms).onTimeout(zero_ms, [&] {
315  return makeFuture<Unit>(std::runtime_error("expected"));
316  });
317  // just testing compilation here
318 }
319 
320 TEST(Timekeeper, interruptDoesntCrash) {
321  auto f = futures::sleep(too_long);
322  f.cancel();
323 }
324 
325 TEST(Timekeeper, chainedInterruptTest) {
326  bool test = false;
327  auto f =
328  futures::sleep(milliseconds(100)).thenValue([&](auto&&) { test = true; });
329  f.cancel();
330  f.wait();
331  EXPECT_FALSE(test);
332 }
333 
334 TEST(Timekeeper, futureWithinChainedInterruptTest) {
335  bool test = false;
336  Promise<Unit> p;
337  p.setInterruptHandler([&test, &p](const exception_wrapper& ex) {
338  ex.handle(
339  [&test](const FutureCancellation& /* cancellation */) { test = true; });
340  p.setException(ex);
341  });
342  auto f = p.getFuture().within(milliseconds(100));
343  EXPECT_FALSE(test) << "Sanity check";
344  f.cancel();
345  f.wait();
346  EXPECT_TRUE(test);
347 }
348 
349 TEST(Timekeeper, semiFutureWithinChainedInterruptTest) {
350  bool test = false;
351  Promise<Unit> p;
352  p.setInterruptHandler([&test, &p](const exception_wrapper& ex) {
353  ex.handle(
354  [&test](const FutureCancellation& /* cancellation */) { test = true; });
355  p.setException(ex);
356  });
357  auto f = p.getSemiFuture().within(milliseconds(100));
358  EXPECT_FALSE(test) << "Sanity check";
359  f.cancel();
360  f.wait();
361  EXPECT_TRUE(test);
362 }
363 
365  class ExecutorTester : public Executor {
366  public:
367  void add(Func f) override {
368  count++;
369  f();
370  }
371  std::atomic<int> count{0};
372  };
373 
374  Promise<Unit> p;
375  ExecutorTester tester;
376  auto f = p.getFuture().via(&tester).within(one_ms).thenValue([&](auto&&) {});
377  p.setValue();
378  f.wait();
379  EXPECT_EQ(2, tester.count);
380 }
381 
382 // TODO(5921764)
383 /*
384 TEST(Timekeeper, onTimeoutPropagates) {
385  bool flag = false;
386  EXPECT_THROW(
387  makeFuture(42).delayed(one_ms)
388  .onTimeout(zero_ms, [&]{ flag = true; })
389  .get(),
390  FutureTimeout);
391  EXPECT_TRUE(flag);
392 }
393 */
394 
395 TEST_F(TimekeeperFixture, atBeforeNow) {
396  auto f = timeLord_->at(now() - too_long);
397  EXPECT_TRUE(f.isReady());
398  EXPECT_FALSE(f.hasException());
399 }
400 
401 TEST_F(TimekeeperFixture, howToCastDuration) {
402  // I'm not sure whether this rounds up or down but it's irrelevant for the
403  // purpose of this example.
404  auto f = timeLord_->after(
405  std::chrono::duration_cast<Duration>(std::chrono::nanoseconds(1)));
406 }
407 
408 TEST_F(TimekeeperFixture, destruction) {
410  tk.emplace();
411  auto f = tk->after(std::chrono::seconds(10));
412  EXPECT_FALSE(f.isReady());
413  tk.clear();
414  EXPECT_TRUE(f.isReady());
415  EXPECT_TRUE(f.hasException());
416 }
void setInterruptHandler(F &&fn)
Definition: Promise-inl.h:117
auto f
void handle(CatchFns...fns)
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
std::shared_ptr< Timekeeper > getTimekeeperSingleton()
auto add
Definition: BaseTest.cpp:70
static void make_mock(std::nullptr_t=nullptr, typename Singleton< T >::TeardownFunc t=nullptr)
Definition: Singleton.h:660
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
Future< Unit > sleep(Duration dur, Timekeeper *tk)
Definition: Future.cpp:42
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::chrono::steady_clock::time_point now()
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
void setException(exception_wrapper ew)
Definition: Promise-inl.h:111
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
std::chrono::seconds const too_long(10)
static once_flag flag
Definition: Random.cpp:75
#define EXPECT_GE(val1, val2)
Definition: gtest.h:1932
PUSHMI_INLINE_VAR constexpr __adl::get_executor_fn executor
Function< void()> Func
Definition: Executor.h:27
std::shared_ptr< Timekeeper > timeLord_
std::chrono::milliseconds const one_ms(1)
std::chrono::milliseconds const zero_ms(0)
Future< T > getFuture()
Definition: Promise-inl.h:97
Value & emplace(Args &&...args)
Definition: Optional.h:231
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
int * count
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
std::enable_if< std::is_same< Unit, B >::value, void >::type setValue()
Definition: Promise.h:326
SemiFuture< T > getSemiFuture()
Definition: Promise-inl.h:88
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
Future< Unit > after(Duration) override
std::chrono::milliseconds const awhile(10)
TEST(SequencedExecutor, CPUThreadPoolExecutor)
Future< typename std::decay< T >::type > makeFuture(T &&t)
Definition: Future-inl.h:1310
SemiFuture< typename std::decay< T >::type > makeSemiFuture(T &&t)
Definition: Future-inl.h:712
void clear() noexcept
Definition: Optional.h:251