Remove extra `int main`s from unit tests.
[folly.git] / folly / test / SingletonTest.cpp
index dbdb579b6ac7d378755ccc9e8c21c91d423eeff8..b36b47091123d28b265683fc470faf7c506cfac0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,8 +18,7 @@
 
 #include <folly/Singleton.h>
 #include <folly/io/async/EventBase.h>
-
-#include <folly/Benchmark.h>
+#include <folly/test/SingletonTestStructs.h>
 
 #include <glog/logging.h>
 #include <gtest/gtest.h>
 
 using namespace folly;
 
-// A simple class that tracks how often instances of the class and
-// subclasses are created, and the ordering.  Also tracks a global
-// unique counter for each object.
-std::atomic<size_t> global_counter(19770326);
-struct Watchdog {
-  static std::vector<Watchdog*> creation_order;
-  Watchdog() : serial_number(++global_counter) {
-    creation_order.push_back(this);
-  }
-
-  ~Watchdog() {
-    if (creation_order.back() != this) {
-      throw std::out_of_range("Watchdog destruction order mismatch");
-    }
-    creation_order.pop_back();
-  }
-
-  const size_t serial_number;
-  size_t livingWatchdogCount() const { return creation_order.size(); }
-
-  Watchdog(const Watchdog&) = delete;
-  Watchdog& operator=(const Watchdog&) = delete;
-  Watchdog(Watchdog&&) noexcept = default;
-};
-
-std::vector<Watchdog*> Watchdog::creation_order;
-
-// Some basic types we use for tracking.
-struct ChildWatchdog : public Watchdog {};
-struct GlobalWatchdog : public Watchdog {};
-struct UnregisteredWatchdog : public Watchdog {};
-
-namespace {
-Singleton<GlobalWatchdog> global_watchdog;
-}
-
-// Test basic global usage (the default way singletons will generally
-// be used).
-TEST(Singleton, BasicGlobalUsage) {
-  EXPECT_EQ(Watchdog::creation_order.size(), 0);
-  EXPECT_EQ(SingletonVault::singleton()->registeredSingletonCount(), 1);
-  EXPECT_EQ(SingletonVault::singleton()->livingSingletonCount(), 0);
-
-  {
-    std::shared_ptr<GlobalWatchdog> wd1 = Singleton<GlobalWatchdog>::try_get();
-    EXPECT_NE(wd1, nullptr);
-    EXPECT_EQ(Watchdog::creation_order.size(), 1);
-    std::shared_ptr<GlobalWatchdog> wd2 = Singleton<GlobalWatchdog>::try_get();
-    EXPECT_NE(wd2, nullptr);
-    EXPECT_EQ(wd1.get(), wd2.get());
-    EXPECT_EQ(Watchdog::creation_order.size(), 1);
-  }
-
-  SingletonVault::singleton()->destroyInstances();
-  EXPECT_EQ(Watchdog::creation_order.size(), 0);
-}
-
 TEST(Singleton, MissingSingleton) {
   EXPECT_DEATH([]() { auto u = Singleton<UnregisteredWatchdog>::try_get(); }(),
       "");
@@ -117,6 +59,7 @@ TEST(Singleton, BasicUsage) {
     EXPECT_NE(s2, nullptr);
 
     EXPECT_EQ(s1, s2);
+    EXPECT_EQ(s1.get(), SingletonBasicUsage<Watchdog>::try_get_fast().get());
 
     std::shared_ptr<ChildWatchdog> s3 =
       SingletonBasicUsage<ChildWatchdog>::try_get();
@@ -444,14 +387,14 @@ template <typename T, typename Tag = detail::DefaultTag>
 using SingletonCreationError = Singleton<T, Tag, CreationErrorTag>;
 
 TEST(Singleton, SingletonCreationError) {
-  auto& vault = *SingletonVault::singleton<CreationErrorTag>();
+  SingletonVault::singleton<CreationErrorTag>();
   SingletonCreationError<ErrorConstructor> error_once_singleton;
 
   // first time should error out
-  EXPECT_THROW(error_once_singleton.get_weak().lock(), std::runtime_error);
+  EXPECT_THROW(error_once_singleton.try_get(), std::runtime_error);
 
   // second time it'll work fine
-  error_once_singleton.get_weak().lock();
+  error_once_singleton.try_get();
   SUCCEED();
 }
 
@@ -466,7 +409,7 @@ TEST(Singleton, SingletonConcurrencyStress) {
   std::vector<std::thread> ts;
   for (size_t i = 0; i < 100; ++i) {
     ts.emplace_back([&]() {
-        slowpoke_singleton.get_weak().lock();
+        slowpoke_singleton.try_get();
       });
   }
 
@@ -496,6 +439,8 @@ TEST(Singleton, SingletonEagerInitSync) {
                   [&] {didEagerInit = true; return new std::string("foo"); })
               .shouldEagerInit();
   vault.registrationComplete();
+  EXPECT_FALSE(didEagerInit);
+  vault.doEagerInit();
   EXPECT_TRUE(didEagerInit);
   sing.get_weak();  // (avoid compile error complaining about unused var 'sing')
 }
@@ -512,10 +457,12 @@ TEST(Singleton, SingletonEagerInitAsync) {
                   [&] {didEagerInit = true; return new std::string("foo"); })
               .shouldEagerInit();
   folly::EventBase eb;
-  vault.setEagerInitExecutor(&eb);
+  folly::Baton<> done;
   vault.registrationComplete();
   EXPECT_FALSE(didEagerInit);
+  vault.doEagerInitVia(eb, &done);
   eb.loop();
+  done.wait();
   EXPECT_TRUE(didEagerInit);
   sing.get_weak();  // (avoid compile error complaining about unused var 'sing')
 }
@@ -582,23 +529,23 @@ TEST(Singleton, SingletonEagerInitParallel) {
     initCounter.store(0);
 
     {
-      boost::barrier barrier(kThreads + 1);
+      std::vector<std::shared_ptr<std::thread>> threads;
+      boost::barrier barrier(kThreads);
       TestEagerInitParallelExecutor exe(kThreads);
-      vault.setEagerInitExecutor(&exe);
-      vault.registrationComplete(false);
+      vault.registrationComplete();
 
       EXPECT_EQ(0, initCounter.load());
 
       for (size_t j = 0; j < kThreads; j++) {
-        exe.add([&] {
-          barrier.wait();
-          vault.startEagerInit();
+        threads.push_back(std::make_shared<std::thread>([&] {
           barrier.wait();
-        });
+          vault.doEagerInitVia(exe);
+        }));
       }
 
-      barrier.wait();  // to await all threads' readiness
-      barrier.wait();  // to await all threads' completion
+      for (auto thread : threads) {
+        thread->join();
+      }
     }
 
     EXPECT_EQ(1, initCounter.load());
@@ -607,20 +554,6 @@ TEST(Singleton, SingletonEagerInitParallel) {
   }
 }
 
-// Benchmarking a normal singleton vs a Meyers singleton vs a Folly
-// singleton.  Meyers are insanely fast, but (hopefully) Folly
-// singletons are fast "enough."
-int* getMeyersSingleton() {
-  static auto ret = new int(0);
-  return ret;
-}
-
-int normal_singleton_value = 0;
-int* getNormalSingleton() {
-  doNotOptimizeAway(&normal_singleton_value);
-  return &normal_singleton_value;
-}
-
 struct MockTag {};
 template <typename T, typename Tag = detail::DefaultTag>
 using SingletonMock = Singleton <T, Tag, MockTag>;
@@ -647,55 +580,3 @@ TEST(Singleton, MockTest) {
   // If serial_count value is the same, then singleton was not replaced.
   EXPECT_NE(serial_count_first, serial_count_mock);
 }
-
-struct BenchmarkSingleton {
-  int val = 0;
-};
-
-BENCHMARK(NormalSingleton, n) {
-  for (size_t i = 0; i < n; ++i) {
-    doNotOptimizeAway(getNormalSingleton());
-  }
-}
-
-BENCHMARK_RELATIVE(MeyersSingleton, n) {
-  for (size_t i = 0; i < n; ++i) {
-    doNotOptimizeAway(getMeyersSingleton());
-  }
-}
-
-struct BenchmarkTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonBenchmark = Singleton <T, Tag, BenchmarkTag>;
-
-struct GetTag{};
-struct GetWeakTag{};
-
-SingletonBenchmark<BenchmarkSingleton, GetTag> benchmark_singleton_get;
-SingletonBenchmark<BenchmarkSingleton, GetWeakTag> benchmark_singleton_get_weak;
-
-BENCHMARK_RELATIVE(FollySingleton, n) {
-  for (size_t i = 0; i < n; ++i) {
-    SingletonBenchmark<BenchmarkSingleton, GetTag>::try_get();
-  }
-}
-
-BENCHMARK_RELATIVE(FollySingletonWeak, n) {
-  for (size_t i = 0; i < n; ++i) {
-    SingletonBenchmark<BenchmarkSingleton, GetWeakTag>::get_weak();
-  }
-}
-
-int main(int argc, char* argv[]) {
-  testing::InitGoogleTest(&argc, argv);
-  google::InitGoogleLogging(argv[0]);
-  gflags::ParseCommandLineFlags(&argc, &argv, true);
-
-  SingletonVault::singleton()->registrationComplete();
-
-  auto ret = RUN_ALL_TESTS();
-  if (!ret) {
-    folly::runBenchmarksOnFlag();
-  }
-  return ret;
-}