Fix copyright lines
[folly.git] / folly / experimental / observer / test / ObserverTest.cpp
index 5605f6ab69bc2380c55e69c2ac1a2997b2504c67..2a3b38bc2a79c7c8be8144bbf4032991e9b97c9d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2016-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.
@@ -16,9 +16,9 @@
 
 #include <thread>
 
-#include <folly/Baton.h>
 #include <folly/experimental/observer/SimpleObservable.h>
 #include <folly/portability/GTest.h>
+#include <folly/synchronization/Baton.h>
 
 using namespace folly::observer;
 
@@ -38,7 +38,7 @@ TEST(Observer, Observable) {
 
   observable.setValue(24);
 
-  EXPECT_TRUE(baton.timed_wait(std::chrono::seconds{1}));
+  EXPECT_TRUE(baton.try_wait_for(std::chrono::seconds{1}));
 
   EXPECT_EQ(24, **observer);
 }
@@ -62,7 +62,7 @@ TEST(Observer, MakeObserver) {
 
   observable.setValue(24);
 
-  EXPECT_TRUE(baton.timed_wait(std::chrono::seconds{1}));
+  EXPECT_TRUE(baton.try_wait_for(std::chrono::seconds{1}));
 
   EXPECT_EQ(25, **observer);
 }
@@ -93,7 +93,7 @@ TEST(Observer, MakeObserverDiamond) {
 
   observable.setValue(24);
 
-  EXPECT_TRUE(baton.timed_wait(std::chrono::seconds{1}));
+  EXPECT_TRUE(baton.try_wait_for(std::chrono::seconds{1}));
 
   EXPECT_EQ(25 * 26, **observer);
 }
@@ -136,14 +136,14 @@ TEST(Observer, NullValue) {
   observable.setValue(2);
 
   // Waiting observer shouldn't be updated
-  EXPECT_FALSE(baton.timed_wait(std::chrono::seconds{1}));
+  EXPECT_FALSE(baton.try_wait_for(std::chrono::seconds{1}));
   baton.reset();
 
   EXPECT_EQ(82, **oddObserver);
 
   observable.setValue(23);
 
-  EXPECT_TRUE(baton.timed_wait(std::chrono::seconds{1}));
+  EXPECT_TRUE(baton.try_wait_for(std::chrono::seconds{1}));
 
   EXPECT_EQ(46, **oddObserver);
 }
@@ -199,7 +199,7 @@ TEST(Observer, Cycle) {
   for (size_t i = 1; i <= 3; ++i) {
     observable.setValue(i);
 
-    EXPECT_TRUE(baton.timed_wait(std::chrono::seconds{1}));
+    EXPECT_TRUE(baton.try_wait_for(std::chrono::seconds{1}));
     baton.reset();
 
     EXPECT_EQ(i, **collectObserver);
@@ -262,3 +262,62 @@ TEST(Observer, TLObserver) {
   k = std::make_unique<folly::observer::TLObserver<int>>(createTLObserver(41));
   EXPECT_EQ(41, ***k);
 }
+
+TEST(Observer, SubscribeCallback) {
+  static auto mainThreadId = std::this_thread::get_id();
+  static std::function<void()> updatesCob;
+  static bool slowGet = false;
+  static std::atomic<size_t> getCallsStart{0};
+  static std::atomic<size_t> getCallsFinish{0};
+
+  struct Observable {
+    ~Observable() {
+      EXPECT_EQ(mainThreadId, std::this_thread::get_id());
+    }
+  };
+  struct Traits {
+    using element_type = int;
+    static std::shared_ptr<const int> get(Observable&) {
+      ++getCallsStart;
+      if (slowGet) {
+        /* sleep override */ std::this_thread::sleep_for(
+            std::chrono::seconds{2});
+      }
+      ++getCallsFinish;
+      return std::make_shared<const int>(42);
+    }
+
+    static void subscribe(Observable&, std::function<void()> cob) {
+      updatesCob = std::move(cob);
+    }
+
+    static void unsubscribe(Observable&) {}
+  };
+
+  std::thread cobThread;
+  {
+    auto observer =
+        folly::observer::ObserverCreator<Observable, Traits>().getObserver();
+
+    EXPECT_TRUE(updatesCob);
+    EXPECT_EQ(2, getCallsStart);
+    EXPECT_EQ(2, getCallsFinish);
+
+    updatesCob();
+    EXPECT_EQ(3, getCallsStart);
+    EXPECT_EQ(3, getCallsFinish);
+
+    slowGet = true;
+    cobThread = std::thread([] { updatesCob(); });
+    /* sleep override */ std::this_thread::sleep_for(std::chrono::seconds{1});
+    EXPECT_EQ(4, getCallsStart);
+    EXPECT_EQ(3, getCallsFinish);
+
+    // Observer is destroyed here
+  }
+
+  // Make sure that destroying the observer actually joined the updates callback
+  EXPECT_EQ(4, getCallsStart);
+  EXPECT_EQ(4, getCallsFinish);
+  cobThread.join();
+}