proxygen
SingletonTest.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 <thread>
18 
19 #include <boost/thread/barrier.hpp>
20 #include <glog/logging.h>
21 
22 #include <folly/Singleton.h>
28 
29 #ifndef _MSC_VER
30 #include <folly/Subprocess.h>
31 #endif
32 
33 FOLLY_GNU_DISABLE_WARNING("-Wdeprecated-declarations")
34 
35 using namespace folly;
36 
37 TEST(Singleton, MissingSingleton) {
38  EXPECT_DEATH(
39  []() { auto u = Singleton<UnregisteredWatchdog>::try_get(); }(), "");
40 }
41 
42 struct BasicUsageTag {};
43 template <typename T, typename Tag = detail::DefaultTag>
45 
46 // Exercise some basic codepaths ensuring registration order and
47 // destruction order happen as expected, that instances are created
48 // when expected, etc etc.
49 TEST(Singleton, BasicUsage) {
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 }
85 
86 struct DirectUsageTag {};
87 template <typename T, typename Tag = detail::DefaultTag>
89 
90 TEST(Singleton, DirectUsage) {
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 }
110 
111 struct NamedUsageTag {};
112 template <typename T, typename Tag = detail::DefaultTag>
114 
115 TEST(Singleton, NamedUsage) {
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 }
152 
153 struct NaughtyUsageTag {};
154 template <typename T, typename Tag = detail::DefaultTag>
157 template <typename T, typename Tag = detail::DefaultTag>
159 
160 // Some pathological cases such as getting unregistered singletons,
161 // double registration, etc.
162 TEST(Singleton, NaughtyUsage) {
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 }
185 
187 template <typename T, typename Tag = detail::DefaultTag>
189 
190 // TODO (anob): revisit this test
191 TEST(Singleton, SharedPtrUsage) {
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 }
304 
305 // Some classes to test singleton dependencies. NeedySingleton has a
306 // dependency on NeededSingleton, which happens during its
307 // construction.
308 struct NeedyTag {};
309 template <typename T, typename Tag = detail::DefaultTag>
311 
312 struct NeededSingleton {};
316  EXPECT_NE(unused, nullptr);
317  }
318 };
319 
320 // Ensure circular dependencies fail -- a singleton that needs itself, whoops.
321 struct SelfNeedyTag {};
322 template <typename T, typename Tag = detail::DefaultTag>
324 
328  EXPECT_NE(unused, nullptr);
329  }
330 };
331 
332 TEST(Singleton, SingletonDependencies) {
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 }
352 
353 // A test to ensure multiple threads contending on singleton creation
354 // properly wait for creation rather than thinking it is a circular
355 // dependency.
356 class Slowpoke : public Watchdog {
357  public:
359  std::this_thread::sleep_for(std::chrono::milliseconds(10));
360  }
361 };
362 
363 struct ConcurrencyTag {};
364 template <typename T, typename Tag = detail::DefaultTag>
366 
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 }
394 
396  static size_t constructCount_;
398  if ((constructCount_++) == 0) {
399  throw std::runtime_error("first time fails");
400  }
401  }
402 };
404 
406 template <typename T, typename Tag = detail::DefaultTag>
408 
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 }
420 
422 template <typename T, typename Tag = detail::DefaultTag>
424 
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 }
448 
449 namespace {
450 struct EagerInitSyncTag {};
451 } // namespace
452 template <typename T, typename Tag = detail::DefaultTag>
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 }
468 
469 namespace {
470 struct EagerInitAsyncTag {};
471 } // namespace
472 template <typename T, typename Tag = detail::DefaultTag>
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 }
492 
493 namespace {
494 class TestEagerInitParallelExecutor : public folly::Executor {
495  public:
496  explicit TestEagerInitParallelExecutor(const size_t threadCount) {
497  eventBases_.reserve(threadCount);
498  threads_.reserve(threadCount);
499  for (size_t i = 0; i < threadCount; i++) {
500  eventBases_.push_back(std::make_shared<folly::EventBase>());
501  auto eb = eventBases_.back();
502  threads_.emplace_back(
503  std::make_shared<std::thread>([eb] { eb->loopForever(); }));
504  }
505  }
506 
507  ~TestEagerInitParallelExecutor() override {
508  for (auto eb : eventBases_) {
509  eb->runInEventBaseThread([eb] { eb->terminateLoopSoon(); });
510  }
511  for (auto thread : threads_) {
512  thread->join();
513  }
514  }
515 
516  void add(folly::Func func) override {
517  const auto index = (counter_++) % eventBases_.size();
518  eventBases_[index]->add(std::move(func));
519  }
520 
521  private:
522  std::vector<std::shared_ptr<folly::EventBase>> eventBases_;
523  std::vector<std::shared_ptr<std::thread>> threads_;
524  std::atomic<size_t> counter_{0};
525 };
526 } // namespace
527 
528 namespace {
529 struct EagerInitParallelTag {};
530 } // namespace
531 template <typename T, typename Tag = detail::DefaultTag>
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 }
581 
582 struct MockTag {};
583 template <typename T, typename Tag = detail::DefaultTag>
585 
586 // Verify that existing Singleton's can be overridden
587 // using the make_mock functionality.
588 TEST(Singleton, MockTest) {
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 }
620 
621 #ifndef _MSC_VER
622 // Subprocess isn't currently supported under MSVC.
623 TEST(Singleton, DoubleRegistrationLogging) {
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 }
639 #endif
640 
641 // Singleton using a non default constructor test/example:
642 struct X {
643  X() : X(-1, "unset") {}
644  X(int a1_, std::string a2_) : a1(a1_), a2(a2_) {
645  LOG(INFO) << "X(" << a1 << "," << a2 << ")";
646  }
647  const int a1;
649 };
650 
651 folly::Singleton<X> singleton_x([]() { return new X(42, "foo"); });
652 
653 TEST(Singleton, CustomCreator) {
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 }
662 
664 template <typename T, typename Tag = detail::DefaultTag>
667 
669 
672  slowpokeNeedySingletonBaton.post();
673  /* sleep override */ std::this_thread::sleep_for(
674  std::chrono::milliseconds(100));
675  auto unused =
677  EXPECT_NE(unused, nullptr);
678  }
679 };
680 
681 TEST(Singleton, ConcurrentCreationDestruction) {
682  auto& vault = *SingletonVault::singleton<ConcurrentCreationDestructionTag>();
685  vault.registrationComplete();
686 
687  std::thread needyThread([&] { needySingleton.try_get(); });
688 
689  slowpokeNeedySingletonBaton.wait();
690 
691  vault.destroyInstances();
692 
693  needyThread.join();
694 }
695 
697 template <typename T, typename Tag = detail::DefaultTag>
700 
703  initThread = std::this_thread::get_id();
704  }
705 
707  destroyThread = std::this_thread::get_id();
708  }
709 
710  static std::thread::id initThread;
711  static std::thread::id destroyThread;
712 };
713 std::thread::id ThreadLoggingSingleton::initThread{};
714 std::thread::id ThreadLoggingSingleton::destroyThread{};
715 
716 TEST(Singleton, MainThreadDestructor) {
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 }
738 
739 TEST(Singleton, DoubleMakeMockAfterTryGet) {
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 }
void * ptr
Sub sub(Sink sink)
Definition: Parallel.h:104
static std::thread::id initThread
#define FOLLY_GNU_DISABLE_WARNING(warningName)
Definition: Portability.h:180
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
PolymorphicMatcher< internal::StartsWithMatcher< internal::string > > StartsWith(const internal::string &prefix)
static Singleton< ShutdownSocketSet, PrivateTag > singleton
path executable_path()
Definition: FsUtil.cpp:72
auto add
Definition: BaseTest.cpp:70
static void make_mock(std::nullptr_t=nullptr, typename Singleton< T >::TeardownFunc t=nullptr)
Definition: Singleton.h:660
const std::string a2
Options & stdinFd(int action)
Definition: Subprocess.h:326
#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
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
X(int a1_, std::string a2_)
std::vector< std::thread::id > threads
FOLLY_ALWAYS_INLINE void wait(const WaitOptions &opt=wait_options()) noexcept
Definition: Baton.h:170
#define SUCCEED()
Definition: gtest.h:1831
TEST(Singleton, MissingSingleton)
folly::Singleton< X > singleton_x([](){return new X(42,"foo");})
void post() noexcept
Definition: Baton.h:123
#define X(name, r, bit)
Definition: CpuId.h:108
static std::shared_ptr< T > try_get()
Definition: Singleton.h:598
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
#define EXPECT_THAT(value, matcher)
std::mutex mutex
folly::Baton slowpokeNeedySingletonBaton
const char * string
Definition: Conv.cpp:212
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
static std::thread::id destroyThread
Options & stdoutFd(int action)
Definition: Subprocess.h:333
InlineExecutor exe
Definition: Benchmark.cpp:337
static folly::ReadMostlySharedPtr< T > try_get_fast()
Definition: Singleton.h:602
const int a1
folly::detail::CompressionCounter * counter_
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
static std::weak_ptr< T > get_weak()
Definition: Singleton.h:587
static size_t constructCount_