proxygen
SingletonTest.cpp File Reference
#include <thread>
#include <boost/thread/barrier.hpp>
#include <glog/logging.h>
#include <folly/Singleton.h>
#include <folly/experimental/io/FsUtil.h>
#include <folly/io/async/EventBase.h>
#include <folly/portability/GMock.h>
#include <folly/portability/GTest.h>
#include <folly/test/SingletonTestStructs.h>
#include <folly/Subprocess.h>

Go to the source code of this file.

Classes

struct  BasicUsageTag
 
struct  DirectUsageTag
 
struct  NamedUsageTag
 
struct  NaughtyUsageTag
 
struct  NaughtyUsageTag2
 
struct  SharedPtrUsageTag
 
struct  NeedyTag
 
struct  NeededSingleton
 
struct  NeedySingleton
 
struct  SelfNeedyTag
 
struct  SelfNeedySingleton
 
class  Slowpoke
 
struct  ConcurrencyTag
 
struct  ErrorConstructor
 
struct  CreationErrorTag
 
struct  ConcurrencyStressTag
 
struct  MockTag
 
struct  X
 
struct  ConcurrentCreationDestructionTag
 
struct  SlowpokeNeedySingleton
 
struct  MainThreadDestructorTag
 
struct  ThreadLoggingSingleton
 

Typedefs

template<typename T , typename Tag = detail::DefaultTag>
using SingletonBasicUsage = Singleton< T, Tag, BasicUsageTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonDirectUsage = Singleton< T, Tag, DirectUsageTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonNamedUsage = Singleton< T, Tag, NamedUsageTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonNaughtyUsage = Singleton< T, Tag, NaughtyUsageTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonNaughtyUsage2 = Singleton< T, Tag, NaughtyUsageTag2 >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonSharedPtrUsage = Singleton< T, Tag, SharedPtrUsageTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonNeedy = Singleton< T, Tag, NeedyTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonSelfNeedy = Singleton< T, Tag, SelfNeedyTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonConcurrency = Singleton< T, Tag, ConcurrencyTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonCreationError = Singleton< T, Tag, CreationErrorTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonConcurrencyStress = Singleton< T, Tag, ConcurrencyStressTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonEagerInitSync = Singleton< T, Tag, EagerInitSyncTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonEagerInitAsync = Singleton< T, Tag, EagerInitAsyncTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonEagerInitParallel = Singleton< T, Tag, EagerInitParallelTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonMock = Singleton< T, Tag, MockTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonConcurrentCreationDestruction = Singleton< T, Tag, ConcurrentCreationDestructionTag >
 
template<typename T , typename Tag = detail::DefaultTag>
using SingletonMainThreadDestructor = Singleton< T, Tag, MainThreadDestructorTag >
 

Functions

 TEST (Singleton, MissingSingleton)
 
 TEST (Singleton, BasicUsage)
 
 TEST (Singleton, DirectUsage)
 
 TEST (Singleton, NamedUsage)
 
 TEST (Singleton, NaughtyUsage)
 
 TEST (Singleton, SharedPtrUsage)
 
 TEST (Singleton, SingletonDependencies)
 
 TEST (Singleton, SingletonConcurrency)
 
 TEST (Singleton, SingletonCreationError)
 
 TEST (Singleton, SingletonConcurrencyStress)
 
 TEST (Singleton, SingletonEagerInitSync)
 
 TEST (Singleton, SingletonEagerInitAsync)
 
 TEST (Singleton, SingletonEagerInitParallel)
 
 TEST (Singleton, MockTest)
 
 TEST (Singleton, DoubleRegistrationLogging)
 
 TEST (Singleton, CustomCreator)
 
 TEST (Singleton, ConcurrentCreationDestruction)
 
 TEST (Singleton, MainThreadDestructor)
 
 TEST (Singleton, DoubleMakeMockAfterTryGet)
 

Variables

folly::Singleton< Xsingleton_x ([](){return new X(42,"foo");})
 
folly::Baton slowpokeNeedySingletonBaton
 

Typedef Documentation

template<typename T , typename Tag = detail::DefaultTag>
using SingletonBasicUsage = Singleton<T, Tag, BasicUsageTag>

Definition at line 44 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonConcurrency = Singleton<T, Tag, ConcurrencyTag>

Definition at line 365 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonConcurrencyStress = Singleton<T, Tag, ConcurrencyStressTag>

Definition at line 423 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonConcurrentCreationDestruction = Singleton<T, Tag, ConcurrentCreationDestructionTag>

Definition at line 666 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonCreationError = Singleton<T, Tag, CreationErrorTag>

Definition at line 407 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonDirectUsage = Singleton<T, Tag, DirectUsageTag>

Definition at line 88 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonEagerInitAsync = Singleton<T, Tag, EagerInitAsyncTag>

Definition at line 473 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonEagerInitParallel = Singleton<T, Tag, EagerInitParallelTag>

Definition at line 532 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonEagerInitSync = Singleton<T, Tag, EagerInitSyncTag>

Definition at line 453 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonMainThreadDestructor = Singleton<T, Tag, MainThreadDestructorTag>

Definition at line 699 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonMock = Singleton<T, Tag, MockTag>

Definition at line 584 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonNamedUsage = Singleton<T, Tag, NamedUsageTag>

Definition at line 113 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonNaughtyUsage = Singleton<T, Tag, NaughtyUsageTag>

Definition at line 155 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonNaughtyUsage2 = Singleton<T, Tag, NaughtyUsageTag2>

Definition at line 158 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonNeedy = Singleton<T, Tag, NeedyTag>

Definition at line 310 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonSelfNeedy = Singleton<T, Tag, SelfNeedyTag>

Definition at line 323 of file SingletonTest.cpp.

template<typename T , typename Tag = detail::DefaultTag>
using SingletonSharedPtrUsage = Singleton<T, Tag, SharedPtrUsageTag>

Definition at line 188 of file SingletonTest.cpp.

Function Documentation

TEST ( Singleton  ,
MissingSingleton   
)

Definition at line 37 of file SingletonTest.cpp.

37  {
38  EXPECT_DEATH(
39  []() { auto u = Singleton<UnregisteredWatchdog>::try_get(); }(), "");
40 }
TEST ( Singleton  ,
BasicUsage   
)

Definition at line 49 of file SingletonTest.cpp.

References EXPECT_EQ, EXPECT_NE, folly::ReadMostlySharedPtr< T, RefCount >::get(), folly::Singleton< T, Tag, VaultTag >::try_get(), and folly::Singleton< T, Tag, VaultTag >::try_get_fast().

49  {
50  auto& vault = *SingletonVault::singleton<BasicUsageTag>();
51 
52  EXPECT_EQ(vault.registeredSingletonCount(), 0);
53  SingletonBasicUsage<Watchdog> watchdog_singleton;
54  EXPECT_EQ(vault.registeredSingletonCount(), 1);
55 
56  SingletonBasicUsage<ChildWatchdog> child_watchdog_singleton;
57  EXPECT_EQ(vault.registeredSingletonCount(), 2);
58 
59  vault.registrationComplete();
60 
61  // limit a scope to release references so we can destroy them later
62  {
63  std::shared_ptr<Watchdog> s1 = SingletonBasicUsage<Watchdog>::try_get();
64  EXPECT_NE(s1, nullptr);
65 
66  std::shared_ptr<Watchdog> s2 = SingletonBasicUsage<Watchdog>::try_get();
67  EXPECT_NE(s2, nullptr);
68 
69  EXPECT_EQ(s1, s2);
71 
72  std::shared_ptr<ChildWatchdog> s3 =
74  EXPECT_NE(s3, nullptr);
75  EXPECT_NE(s2, s3);
76 
77  EXPECT_EQ(vault.registeredSingletonCount(), 2);
78  EXPECT_EQ(vault.livingSingletonCount(), 2);
79  }
80 
81  vault.destroyInstances();
82  EXPECT_EQ(vault.registeredSingletonCount(), 2);
83  EXPECT_EQ(vault.livingSingletonCount(), 0);
84 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
static std::shared_ptr< T > try_get()
Definition: Singleton.h:598
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
static folly::ReadMostlySharedPtr< T > try_get_fast()
Definition: Singleton.h:602
TEST ( Singleton  ,
DirectUsage   
)

Definition at line 90 of file SingletonTest.cpp.

References EXPECT_EQ, EXPECT_NE, and folly::Singleton< T, Tag, VaultTag >::try_get().

90  {
91  auto& vault = *SingletonVault::singleton<DirectUsageTag>();
92 
93  EXPECT_EQ(vault.registeredSingletonCount(), 0);
94 
95  // Verify we can get to the underlying singletons via directly using
96  // the singleton definition.
98  struct TestTag {};
100  EXPECT_EQ(vault.registeredSingletonCount(), 2);
101  vault.registrationComplete();
102 
103  EXPECT_NE(watchdog.try_get(), nullptr);
104  EXPECT_EQ(watchdog.try_get(), SingletonDirectUsage<Watchdog>::try_get());
105  EXPECT_NE(watchdog.try_get(), named_watchdog.try_get());
106  EXPECT_EQ(watchdog.try_get()->livingWatchdogCount(), 2);
107 
108  vault.destroyInstances();
109 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
static std::shared_ptr< T > try_get()
Definition: Singleton.h:598
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
TEST ( Singleton  ,
NamedUsage   
)

Definition at line 115 of file SingletonTest.cpp.

References EXPECT_EQ, EXPECT_NE, and folly::Singleton< T, Tag, VaultTag >::try_get().

115  {
116  auto& vault = *SingletonVault::singleton<NamedUsageTag>();
117 
118  EXPECT_EQ(vault.registeredSingletonCount(), 0);
119 
120  // Define two named Watchdog singletons and one unnamed singleton.
121  struct Watchdog1 {};
122  struct Watchdog2 {};
123  typedef detail::DefaultTag Watchdog3;
124  SingletonNamedUsage<Watchdog, Watchdog1> watchdog1_singleton;
125  EXPECT_EQ(vault.registeredSingletonCount(), 1);
126  SingletonNamedUsage<Watchdog, Watchdog2> watchdog2_singleton;
127  EXPECT_EQ(vault.registeredSingletonCount(), 2);
128  SingletonNamedUsage<Watchdog, Watchdog3> watchdog3_singleton;
129  EXPECT_EQ(vault.registeredSingletonCount(), 3);
130 
131  vault.registrationComplete();
132  {
133  // Verify our three singletons are distinct and non-nullptr.
135  EXPECT_EQ(s1, watchdog1_singleton.try_get());
137  EXPECT_EQ(s2, watchdog2_singleton.try_get());
138  EXPECT_NE(s1, s2);
140  EXPECT_EQ(s3, watchdog3_singleton.try_get());
141  EXPECT_NE(s3, s1);
142  EXPECT_NE(s3, s2);
143 
144  // Verify the "default" singleton is the same as the DefaultTag-tagged
145  // singleton.
147  EXPECT_EQ(s4, watchdog3_singleton.try_get());
148  }
149 
150  vault.destroyInstances();
151 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
static std::shared_ptr< T > try_get()
Definition: Singleton.h:598
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
TEST ( Singleton  ,
NaughtyUsage   
)

Definition at line 162 of file SingletonTest.cpp.

162  {
163  auto& vault = *SingletonVault::singleton<NaughtyUsageTag>();
164 
165  vault.registrationComplete();
166 
167  // Unregistered.
168  EXPECT_DEATH(Singleton<Watchdog>::try_get(), "");
169  EXPECT_DEATH(SingletonNaughtyUsage<Watchdog>::try_get(), "");
170 
171  vault.destroyInstances();
172 
173  auto& vault2 = *SingletonVault::singleton<NaughtyUsageTag2>();
174 
175  EXPECT_DEATH(SingletonNaughtyUsage2<Watchdog>::try_get(), "");
176  SingletonNaughtyUsage2<Watchdog> watchdog_singleton;
177 
178  // double registration
179  EXPECT_DEATH([]() { SingletonNaughtyUsage2<Watchdog> w2; }(), "");
180  vault2.destroyInstances();
181 
182  // double registration after destroy
183  EXPECT_DEATH([]() { SingletonNaughtyUsage2<Watchdog> w3; }(), "");
184 }
TEST ( Singleton  ,
SharedPtrUsage   
)

Definition at line 191 of file SingletonTest.cpp.

References EXPECT_EQ, EXPECT_FALSE, EXPECT_NE, EXPECT_TRUE, folly::Singleton< T, Tag, VaultTag >::get_weak(), folly::kIsSanitizeAddress, folly::gen::move, now(), ptr, folly::pushmi::detail::t, and folly::Singleton< T, Tag, VaultTag >::try_get().

191  {
192  struct WatchdogHolder {
193  ~WatchdogHolder() {
194  if (watchdog) {
195  LOG(ERROR) << "The following log message with stack trace is expected";
196  }
197  }
198 
199  std::shared_ptr<Watchdog> watchdog;
200  };
201 
202  auto& vault = *SingletonVault::singleton<SharedPtrUsageTag>();
203 
204  EXPECT_EQ(vault.registeredSingletonCount(), 0);
205  std::vector<std::unique_ptr<Watchdog>> watchdog_instances;
206  SingletonSharedPtrUsage<Watchdog> watchdog_singleton(
207  [&] {
208  watchdog_instances.push_back(std::make_unique<Watchdog>());
209  return watchdog_instances.back().get();
210  },
211  [&](Watchdog* ptr) {
212  // Make sure that only second instance is destroyed. First instance is
213  // expected to be leaked.
214  EXPECT_EQ(watchdog_instances[1].get(), ptr);
215  watchdog_instances[1].reset();
216  });
217  EXPECT_EQ(vault.registeredSingletonCount(), 1);
218 
219  SingletonSharedPtrUsage<ChildWatchdog> child_watchdog_singleton;
220  EXPECT_EQ(vault.registeredSingletonCount(), 2);
221 
222  struct ATag {};
223  SingletonSharedPtrUsage<Watchdog, ATag> named_watchdog_singleton;
224 
225  SingletonSharedPtrUsage<WatchdogHolder> watchdog_holder_singleton;
226 
227  vault.registrationComplete();
228 
229  // Initilize holder singleton first, so that it's the last one to be
230  // destroyed.
231  watchdog_holder_singleton.try_get();
232 
234  EXPECT_NE(s1, nullptr);
235 
237  EXPECT_NE(s2, nullptr);
238 
239  EXPECT_EQ(s1, s2);
240 
242 
243  auto shared_s1 = weak_s1.lock();
244  EXPECT_EQ(shared_s1.get(), s1);
245  EXPECT_EQ(shared_s1.use_count(), 2);
246 
247  auto old_serial = shared_s1->serial_number;
248 
249  {
251  auto locked = named_weak_s1.lock();
252  EXPECT_NE(locked.get(), shared_s1.get());
253  }
254 
255  // We should release externally locked shared_ptr, otherwise it will be
256  // considered a leak
257  watchdog_holder_singleton.try_get()->watchdog = std::move(shared_s1);
258 
259  LOG(ERROR) << "The following log message regarding shared_ptr is expected";
260  {
261  auto start_time = std::chrono::steady_clock::now();
262  vault.destroyInstances();
263  auto duration = std::chrono::steady_clock::now() - start_time;
264  EXPECT_TRUE(
265  duration > std::chrono::seconds{4} &&
266  duration < std::chrono::seconds{folly::kIsSanitizeAddress ? 30 : 6});
267  }
268  EXPECT_EQ(vault.registeredSingletonCount(), 4);
269  EXPECT_EQ(vault.livingSingletonCount(), 0);
270 
271  EXPECT_TRUE(weak_s1.expired());
272 
274  EXPECT_FALSE(empty_s1.lock());
275 
276  vault.reenableInstances();
277 
278  {
279  // Singleton should be re-created only after reenableInstances() was called.
281  // Track serial number rather than pointer since the memory could be
282  // re-used when we create new_s1.
283  EXPECT_NE(new_s1->serial_number, old_serial);
284  }
285 
286  auto new_s1_weak = SingletonSharedPtrUsage<Watchdog>::get_weak();
287  auto new_s1_shared = new_s1_weak.lock();
288  std::thread t([new_s1_shared]() mutable {
289  std::this_thread::sleep_for(std::chrono::seconds{2});
290  new_s1_shared.reset();
291  });
292  new_s1_shared.reset();
293  {
294  auto start_time = std::chrono::steady_clock::now();
295  vault.destroyInstances();
296  auto duration = std::chrono::steady_clock::now() - start_time;
297  EXPECT_TRUE(
298  duration > std::chrono::seconds{1} &&
299  duration < std::chrono::seconds{3});
300  }
301  EXPECT_TRUE(new_s1_weak.expired());
302  t.join();
303 }
void * ptr
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
std::chrono::steady_clock::time_point now()
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
constexpr bool kIsSanitizeAddress
Definition: Portability.h:118
static std::shared_ptr< T > try_get()
Definition: Singleton.h:598
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
static std::weak_ptr< T > get_weak()
Definition: Singleton.h:587
TEST ( Singleton  ,
SingletonDependencies   
)

Definition at line 332 of file SingletonTest.cpp.

References EXPECT_EQ, and folly::Singleton< T, Tag, VaultTag >::try_get().

332  {
333  SingletonNeedy<NeededSingleton> needed_singleton;
334  SingletonNeedy<NeedySingleton> needy_singleton;
335  auto& needy_vault = *SingletonVault::singleton<NeedyTag>();
336 
337  needy_vault.registrationComplete();
338 
339  EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
340  EXPECT_EQ(needy_vault.livingSingletonCount(), 0);
341 
343  EXPECT_EQ(needy_vault.livingSingletonCount(), 2);
344 
345  SingletonSelfNeedy<SelfNeedySingleton> self_needy_singleton;
346  auto& self_needy_vault = *SingletonVault::singleton<SelfNeedyTag>();
347 
348  self_needy_vault.registrationComplete();
349  EXPECT_DEATH(
351 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
static std::shared_ptr< T > try_get()
Definition: Singleton.h:598
TEST ( Singleton  ,
SingletonConcurrency   
)

Definition at line 367 of file SingletonTest.cpp.

References EXPECT_EQ, i, mutex, folly::pushmi::detail::t, threads, and folly::Singleton< T, Tag, VaultTag >::try_get().

367  {
368  auto& vault = *SingletonVault::singleton<ConcurrencyTag>();
369  SingletonConcurrency<Slowpoke> slowpoke_singleton;
370  vault.registrationComplete();
371 
372  std::mutex gatekeeper;
373  gatekeeper.lock();
374  auto func = [&gatekeeper]() {
375  gatekeeper.lock();
376  gatekeeper.unlock();
378  };
379 
380  EXPECT_EQ(vault.livingSingletonCount(), 0);
381  std::vector<std::thread> threads;
382  for (int i = 0; i < 100; ++i) {
383  threads.emplace_back(func);
384  }
385  // If circular dependency checks fail, the unlock would trigger a
386  // crash. Instead, it succeeds, and we have exactly one living
387  // singleton.
388  gatekeeper.unlock();
389  for (auto& t : threads) {
390  t.join();
391  }
392  EXPECT_EQ(vault.livingSingletonCount(), 1);
393 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
std::vector< std::thread::id > threads
static std::shared_ptr< T > try_get()
Definition: Singleton.h:598
std::mutex mutex
TEST ( Singleton  ,
SingletonCreationError   
)

Definition at line 409 of file SingletonTest.cpp.

References EXPECT_THROW, SUCCEED, and folly::Singleton< T, Tag, VaultTag >::try_get().

409  {
410  SingletonCreationError<ErrorConstructor> error_once_singleton;
411  SingletonVault::singleton<CreationErrorTag>()->registrationComplete();
412 
413  // first time should error out
414  EXPECT_THROW(error_once_singleton.try_get(), std::runtime_error);
415 
416  // second time it'll work fine
417  error_once_singleton.try_get();
418  SUCCEED();
419 }
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
#define SUCCEED()
Definition: gtest.h:1831
static std::shared_ptr< T > try_get()
Definition: Singleton.h:598

Definition at line 425 of file SingletonTest.cpp.

References i, and folly::pushmi::detail::t.

425  {
426  auto& vault = *SingletonVault::singleton<ConcurrencyStressTag>();
427  SingletonConcurrencyStress<Slowpoke> slowpoke_singleton;
428  vault.registrationComplete();
429 
430  std::vector<std::thread> ts;
431  for (size_t i = 0; i < 100; ++i) {
432  ts.emplace_back([&]() { slowpoke_singleton.try_get(); });
433  }
434 
435  for (size_t i = 0; i < 100; ++i) {
436  std::chrono::milliseconds d(20);
437 
438  std::this_thread::sleep_for(d);
439  vault.destroyInstances();
440  std::this_thread::sleep_for(d);
441  vault.destroyInstances();
442  }
443 
444  for (auto& t : ts) {
445  t.join();
446  }
447 }
TEST ( Singleton  ,
SingletonEagerInitSync   
)

Definition at line 454 of file SingletonTest.cpp.

References EXPECT_FALSE, EXPECT_TRUE, and string.

454  {
455  auto& vault = *SingletonVault::singleton<EagerInitSyncTag>();
456  bool didEagerInit = false;
457  auto sing = SingletonEagerInitSync<std::string>([&] {
458  didEagerInit = true;
459  return new std::string("foo");
460  })
461  .shouldEagerInit();
462  vault.registrationComplete();
463  EXPECT_FALSE(didEagerInit);
464  vault.doEagerInit();
465  EXPECT_TRUE(didEagerInit);
466  sing.get_weak(); // (avoid compile error complaining about unused var 'sing')
467 }
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
const char * string
Definition: Conv.cpp:212
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862

Definition at line 474 of file SingletonTest.cpp.

References add, counter_, EXPECT_FALSE, EXPECT_TRUE, i, folly::EventBase::loop(), folly::gen::move, string, and folly::Baton< MayBlock, Atom >::wait().

474  {
475  auto& vault = *SingletonVault::singleton<EagerInitAsyncTag>();
476  bool didEagerInit = false;
477  auto sing = SingletonEagerInitAsync<std::string>([&] {
478  didEagerInit = true;
479  return new std::string("foo");
480  })
481  .shouldEagerInit();
482  folly::EventBase eb;
483  folly::Baton<> done;
484  vault.registrationComplete();
485  EXPECT_FALSE(didEagerInit);
486  vault.doEagerInitVia(eb, &done);
487  eb.loop();
488  done.wait();
489  EXPECT_TRUE(didEagerInit);
490  sing.get_weak(); // (avoid compile error complaining about unused var 'sing')
491 }
FOLLY_ALWAYS_INLINE void wait(const WaitOptions &opt=wait_options()) noexcept
Definition: Baton.h:170
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
const char * string
Definition: Conv.cpp:212
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862

Definition at line 533 of file SingletonTest.cpp.

References exe, EXPECT_EQ, i, SCOPE_EXIT, string, and threads.

533  {
534  const static size_t kIters = 1000;
535  const static size_t kThreads = 20;
536 
537  std::atomic<size_t> initCounter{0};
538 
539  auto& vault = *SingletonVault::singleton<EagerInitParallelTag>();
540 
542  ++initCounter;
543  return new std::string("");
544  })
545  .shouldEagerInit();
546 
547  for (size_t i = 0; i < kIters; i++) {
548  SCOPE_EXIT {
549  // clean up each time
550  vault.destroyInstances();
551  vault.reenableInstances();
552  };
553 
554  initCounter.store(0);
555 
556  {
557  std::vector<std::shared_ptr<std::thread>> threads;
558  boost::barrier barrier(kThreads);
559  TestEagerInitParallelExecutor exe(kThreads);
560  vault.registrationComplete();
561 
562  EXPECT_EQ(0, initCounter.load());
563 
564  for (size_t j = 0; j < kThreads; j++) {
565  threads.push_back(std::make_shared<std::thread>([&] {
566  barrier.wait();
567  vault.doEagerInitVia(exe);
568  }));
569  }
570 
571  for (auto thread : threads) {
572  thread->join();
573  }
574  }
575 
576  EXPECT_EQ(1, initCounter.load());
577 
578  sing.get_weak(); // (avoid compile error complaining about unused var)
579  }
580 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
std::vector< std::thread::id > threads
const char * string
Definition: Conv.cpp:212
InlineExecutor exe
Definition: Benchmark.cpp:337
TEST ( Singleton  ,
MockTest   
)

Definition at line 588 of file SingletonTest.cpp.

References EXPECT_EQ, EXPECT_NE, folly::Singleton< T, Tag, VaultTag >::make_mock(), and folly::Singleton< T, Tag, VaultTag >::try_get().

588  {
589  auto& vault = *SingletonVault::singleton<MockTag>();
590 
591  SingletonMock<Watchdog> watchdog_singleton;
592  vault.registrationComplete();
593 
594  // Registring singletons after registrationComplete called works
595  // with make_mock (but not with Singleton ctor).
596  EXPECT_EQ(vault.registeredSingletonCount(), 1);
597  int serial_count_first = SingletonMock<Watchdog>::try_get()->serial_number;
598 
599  // Override existing mock using make_mock.
601 
602  EXPECT_EQ(vault.registeredSingletonCount(), 1);
603  int serial_count_mock = SingletonMock<Watchdog>::try_get()->serial_number;
604 
605  // If serial_count value is the same, then singleton was not replaced.
606  EXPECT_NE(serial_count_first, serial_count_mock);
607 
608  // Override existing mock using make_mock one more time
610 
611  EXPECT_EQ(vault.registeredSingletonCount(), 1);
612  int serial_count_mock2 = SingletonMock<Watchdog>::try_get()->serial_number;
613 
614  // If serial_count value is the same, then singleton was not replaced.
615  EXPECT_NE(serial_count_first, serial_count_mock2);
616  EXPECT_NE(serial_count_mock, serial_count_mock2);
617 
618  vault.destroyInstances();
619 }
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
static std::shared_ptr< T > try_get()
Definition: Singleton.h:598
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
TEST ( Singleton  ,
DoubleRegistrationLogging   
)

Definition at line 623 of file SingletonTest.cpp.

References folly::Subprocess::Options::closeOtherFds(), folly::fs::executable_path(), EXPECT_EQ, EXPECT_THAT, folly::Subprocess::Options::pipeStderr(), testing::StartsWith(), folly::Subprocess::Options::stdinFd(), folly::Subprocess::Options::stdoutFd(), folly::gen::sub(), and gmock_test_utils::Subprocess.

623  {
624  const auto basename = "singleton_double_registration";
625  const auto sub = fs::executable_path().remove_filename() / basename;
626  auto p = Subprocess(
627  std::vector<std::string>{sub.string()},
629  .stdinFd(Subprocess::CLOSE)
630  .stdoutFd(Subprocess::CLOSE)
631  .pipeStderr()
632  .closeOtherFds());
633  auto err = p.communicate("").second;
634  auto res = p.wait();
635  EXPECT_EQ(ProcessReturnCode::KILLED, res.state());
636  EXPECT_EQ(SIGABRT, res.killSignal());
637  EXPECT_THAT(err, testing::StartsWith("Double registration of singletons"));
638 }
Sub sub(Sink sink)
Definition: Parallel.h:104
PolymorphicMatcher< internal::StartsWithMatcher< internal::string > > StartsWith(const internal::string &prefix)
path executable_path()
Definition: FsUtil.cpp:72
Options & stdinFd(int action)
Definition: Subprocess.h:326
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
#define EXPECT_THAT(value, matcher)
Options & stdoutFd(int action)
Definition: Subprocess.h:333
TEST ( Singleton  ,
CustomCreator   
)

Definition at line 653 of file SingletonTest.cpp.

References X::a1, X::a2, EXPECT_EQ, EXPECT_NE, singleton_x, and string.

653  {
654  X x1;
655  std::shared_ptr<X> x2p = singleton_x.try_get();
656  EXPECT_NE(nullptr, x2p);
657  EXPECT_NE(x1.a1, x2p->a1);
658  EXPECT_NE(x1.a2, x2p->a2);
659  EXPECT_EQ(42, x2p->a1);
660  EXPECT_EQ(std::string("foo"), x2p->a2);
661 }
const std::string a2
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
folly::Singleton< X > singleton_x([](){return new X(42,"foo");})
const char * string
Definition: Conv.cpp:212
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
const int a1
TEST ( Singleton  ,
ConcurrentCreationDestruction   
)

Definition at line 681 of file SingletonTest.cpp.

References folly::Singleton< T, Tag, VaultTag >::try_get(), and folly::Baton< MayBlock, Atom >::wait().

681  {
682  auto& vault = *SingletonVault::singleton<ConcurrentCreationDestructionTag>();
685  vault.registrationComplete();
686 
687  std::thread needyThread([&] { needySingleton.try_get(); });
688 
690 
691  vault.destroyInstances();
692 
693  needyThread.join();
694 }
FOLLY_ALWAYS_INLINE void wait(const WaitOptions &opt=wait_options()) noexcept
Definition: Baton.h:170
static std::shared_ptr< T > try_get()
Definition: Singleton.h:598
folly::Baton slowpokeNeedySingletonBaton
TEST ( Singleton  ,
MainThreadDestructor   
)

Definition at line 716 of file SingletonTest.cpp.

References ThreadLoggingSingleton::destroyThread, EXPECT_EQ, ThreadLoggingSingleton::initThread, folly::singleton, and folly::pushmi::detail::t.

716  {
717  auto& vault = *SingletonVault::singleton<MainThreadDestructorTag>();
719 
720  vault.registrationComplete();
721  EXPECT_EQ(std::thread::id(), ThreadLoggingSingleton::initThread);
722 
723  singleton.try_get();
724  EXPECT_EQ(std::this_thread::get_id(), ThreadLoggingSingleton::initThread);
725 
726  std::thread t([instance = singleton.try_get()] {
727  /* sleep override */ std::this_thread::sleep_for(
728  std::chrono::milliseconds{100});
729  });
730 
732 
733  vault.destroyInstances();
734  EXPECT_EQ(std::this_thread::get_id(), ThreadLoggingSingleton::destroyThread);
735 
736  t.join();
737 }
static std::thread::id initThread
static Singleton< ShutdownSocketSet, PrivateTag > singleton
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
static std::thread::id destroyThread
TEST ( Singleton  ,
DoubleMakeMockAfterTryGet   
)

Definition at line 739 of file SingletonTest.cpp.

References EXPECT_EQ.

739  {
740  // to keep track of calls to ctor and dtor below
741  struct Counts {
742  size_t ctor = 0;
743  size_t dtor = 0;
744  };
745 
746  // a test type which keeps track of its ctor and dtor calls
747  struct VaultTag {};
748  struct PrivateTag {};
749  struct Object {
750  explicit Object(Counts& counts) : counts_(counts) {
751  ++counts_.ctor;
752  }
753  ~Object() {
754  ++counts_.dtor;
755  }
756  Counts& counts_;
757  };
758  using SingletonObject = Singleton<Object, PrivateTag, VaultTag>;
759 
760  // register everything
761  Counts counts;
762  auto& vault = *SingletonVault::singleton<VaultTag>();
763  auto new_object = [&] { return new Object(counts); };
764  SingletonObject object_(new_object);
765  vault.registrationComplete();
766 
767  // no eager inits, nada (sanity)
768  EXPECT_EQ(0, counts.ctor);
769  EXPECT_EQ(0, counts.dtor);
770 
771  // explicit request, ctor
772  SingletonObject::try_get();
773  EXPECT_EQ(1, counts.ctor);
774  EXPECT_EQ(0, counts.dtor);
775 
776  // first make_mock, dtor (ctor is lazy)
777  SingletonObject::make_mock(new_object);
778  EXPECT_EQ(1, counts.ctor);
779  EXPECT_EQ(1, counts.dtor);
780 
781  // second make_mock, nada (dtor already ran, ctor is lazy)
782  SingletonObject::make_mock(new_object);
783  EXPECT_EQ(1, counts.ctor);
784  EXPECT_EQ(1, counts.dtor);
785 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922

Variable Documentation

folly::Singleton<X> singleton_x([](){return new X(42,"foo");})

Referenced by TEST().

folly::Baton slowpokeNeedySingletonBaton

Definition at line 668 of file SingletonTest.cpp.