Fix copyright lines
[folly.git] / folly / futures / test / TimekeeperTest.cpp
index 2ede467355f3171051ac86d3c9b9a2ab88f0d7d5..3c5464a4a22f6b5db50adb6a8bb4f963d9c4cffe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2014-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <gtest/gtest.h>
 
 #include <folly/futures/Timekeeper.h>
-#include <unistd.h>
+#include <folly/Singleton.h>
+#include <folly/futures/ThreadWheelTimekeeper.h>
+#include <folly/portability/GTest.h>
 
-using namespace folly::wangle;
-using namespace std::chrono;
-using folly::wangle::Timekeeper;
-using Duration = folly::wangle::Duration;
+using namespace folly;
+using std::chrono::milliseconds;
 
+std::chrono::milliseconds const zero_ms(0);
 std::chrono::milliseconds const one_ms(1);
 std::chrono::milliseconds const awhile(10);
+std::chrono::seconds const too_long(10);
 
 std::chrono::steady_clock::time_point now() {
   return std::chrono::steady_clock::now();
@@ -32,15 +33,13 @@ std::chrono::steady_clock::time_point now() {
 
 struct TimekeeperFixture : public testing::Test {
   TimekeeperFixture() :
-    timeLord_(folly::wangle::detail::getTimekeeperSingleton())
+    timeLord_(folly::detail::getTimekeeperSingleton())
   {}
 
-  Timekeeper* timeLord_;
+  std::shared_ptr<Timekeeper> timeLord_;
 };
 
 TEST_F(TimekeeperFixture, after) {
-  Duration waited(0);
-
   auto t1 = now();
   auto f = timeLord_->after(awhile);
   EXPECT_FALSE(f.isReady());
@@ -52,8 +51,9 @@ TEST_F(TimekeeperFixture, after) {
 
 TEST(Timekeeper, futureGet) {
   Promise<int> p;
-  std::thread([&]{ p.setValue(42); }).detach();
+  auto t = std::thread([&]{ p.setValue(42); });
   EXPECT_EQ(42, p.getFuture().get());
+  t.join();
 }
 
 TEST(Timekeeper, futureGetBeforeTimeout) {
@@ -65,13 +65,13 @@ TEST(Timekeeper, futureGetBeforeTimeout) {
   // runs it by hand they're not sitting there forever wondering why it's
   // blocked, and get a useful error message instead. If it does get flaky,
   // empirically increase the timeout to the point where it's very improbable.
-  EXPECT_EQ(42, p.getFuture().get(seconds(2)));
+  EXPECT_EQ(42, p.getFuture().get(std::chrono::seconds(2)));
   t.join();
 }
 
 TEST(Timekeeper, futureGetTimeout) {
   Promise<int> p;
-  EXPECT_THROW(p.getFuture().get(Duration(1)), folly::wangle::TimedOut);
+  EXPECT_THROW(p.getFuture().get(one_ms), folly::TimedOut);
 }
 
 TEST(Timekeeper, futureSleep) {
@@ -80,6 +80,24 @@ TEST(Timekeeper, futureSleep) {
   EXPECT_GE(now() - t1, one_ms);
 }
 
+TEST(Timekeeper, futureSleepHandlesNullTimekeeperSingleton) {
+  Singleton<ThreadWheelTimekeeper>::make_mock([] { return nullptr; });
+  SCOPE_EXIT {
+    Singleton<ThreadWheelTimekeeper>::make_mock();
+  };
+  EXPECT_THROW(futures::sleep(one_ms).get(), NoTimekeeper);
+}
+
+TEST(Timekeeper, futureWithinHandlesNullTimekeeperSingleton) {
+  Singleton<ThreadWheelTimekeeper>::make_mock([] { return nullptr; });
+  SCOPE_EXIT {
+    Singleton<ThreadWheelTimekeeper>::make_mock();
+  };
+  Promise<int> p;
+  auto f = p.getFuture().within(one_ms);
+  EXPECT_THROW(f.get(), NoTimekeeper);
+}
+
 TEST(Timekeeper, futureDelayed) {
   auto t1 = now();
   auto dur = makeFuture()
@@ -122,7 +140,101 @@ TEST(Timekeeper, futureWithinVoidSpecialization) {
 }
 
 TEST(Timekeeper, futureWithinException) {
-  Promise<void> p;
+  Promise<Unit> p;
   auto f = p.getFuture().within(awhile, std::runtime_error("expected"));
   EXPECT_THROW(f.get(), std::runtime_error);
 }
+
+TEST(Timekeeper, onTimeout) {
+  bool flag = false;
+  makeFuture(42).delayed(10 * one_ms)
+    .onTimeout(zero_ms, [&]{ flag = true; return -1; })
+    .get();
+  EXPECT_TRUE(flag);
+}
+
+TEST(Timekeeper, onTimeoutComplete) {
+  bool flag = false;
+  makeFuture(42)
+    .onTimeout(zero_ms, [&]{ flag = true; return -1; })
+    .get();
+  EXPECT_FALSE(flag);
+}
+
+TEST(Timekeeper, onTimeoutReturnsFuture) {
+  bool flag = false;
+  makeFuture(42).delayed(10 * one_ms)
+    .onTimeout(zero_ms, [&]{ flag = true; return makeFuture(-1); })
+    .get();
+  EXPECT_TRUE(flag);
+}
+
+TEST(Timekeeper, onTimeoutVoid) {
+  makeFuture().delayed(one_ms)
+    .onTimeout(zero_ms, [&]{
+     });
+  makeFuture().delayed(one_ms)
+    .onTimeout(zero_ms, [&]{
+       return makeFuture<Unit>(std::runtime_error("expected"));
+     });
+  // just testing compilation here
+}
+
+TEST(Timekeeper, interruptDoesntCrash) {
+  auto f = futures::sleep(too_long);
+  f.cancel();
+}
+
+TEST(Timekeeper, chainedInterruptTest) {
+  bool test = false;
+  auto f = futures::sleep(milliseconds(100)).then([&](){
+    test = true;
+  });
+  f.cancel();
+  f.wait();
+  EXPECT_FALSE(test);
+}
+
+TEST(Timekeeper, executor) {
+  class ExecutorTester : public Executor {
+   public:
+    void add(Func f) override {
+      count++;
+      f();
+    }
+    std::atomic<int> count{0};
+  };
+
+  Promise<Unit> p;
+  ExecutorTester tester;
+  auto f = p.getFuture().via(&tester).within(one_ms).then([&](){});
+  p.setValue();
+  f.wait();
+  EXPECT_EQ(2, tester.count);
+}
+
+// TODO(5921764)
+/*
+TEST(Timekeeper, onTimeoutPropagates) {
+  bool flag = false;
+  EXPECT_THROW(
+    makeFuture(42).delayed(one_ms)
+      .onTimeout(zero_ms, [&]{ flag = true; })
+      .get(),
+    TimedOut);
+  EXPECT_TRUE(flag);
+}
+*/
+
+TEST_F(TimekeeperFixture, atBeforeNow) {
+  auto f = timeLord_->at(now() - too_long);
+  EXPECT_TRUE(f.isReady());
+  EXPECT_FALSE(f.hasException());
+}
+
+TEST_F(TimekeeperFixture, howToCastDuration) {
+  // I'm not sure whether this rounds up or down but it's irrelevant for the
+  // purpose of this example.
+  auto f = timeLord_->after(std::chrono::duration_cast<Duration>(
+      std::chrono::nanoseconds(1)));
+}