fix SingletonTest
[folly.git] / folly / test / SingletonTest.cpp
1 /*
2  * Copyright 2017 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>
23 #include <folly/experimental/io/FsUtil.h>
24 #include <folly/io/async/EventBase.h>
25 #include <folly/portability/GMock.h>
26 #include <folly/portability/GTest.h>
27 #include <folly/test/SingletonTestStructs.h>
28
29 #ifndef _MSC_VER
30 #include <folly/Subprocess.h>
31 #endif
32
33 FOLLY_GCC_DISABLE_WARNING("-Wdeprecated-declarations")
34
35 using namespace folly;
36
37 TEST(Singleton, MissingSingleton) {
38   EXPECT_DEATH([]() { auto u = Singleton<UnregisteredWatchdog>::try_get(); }(),
39       "");
40 }
41
42 struct BasicUsageTag {};
43 template <typename T, typename Tag = detail::DefaultTag>
44 using SingletonBasicUsage = Singleton <T, Tag, BasicUsageTag>;
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);
70     EXPECT_EQ(s1.get(), SingletonBasicUsage<Watchdog>::try_get_fast().get());
71
72     std::shared_ptr<ChildWatchdog> s3 =
73       SingletonBasicUsage<ChildWatchdog>::try_get();
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>
88 using SingletonDirectUsage = Singleton <T, Tag, DirectUsageTag>;
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.
97   SingletonDirectUsage<Watchdog> watchdog;
98   struct TestTag {};
99   SingletonDirectUsage<Watchdog, TestTag> named_watchdog;
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>
113 using SingletonNamedUsage = Singleton <T, Tag, NamedUsageTag>;
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.
134     auto s1 = SingletonNamedUsage<Watchdog, Watchdog1>::try_get();
135     EXPECT_EQ(s1, watchdog1_singleton.try_get());
136     auto s2 = SingletonNamedUsage<Watchdog, Watchdog2>::try_get();
137     EXPECT_EQ(s2, watchdog2_singleton.try_get());
138     EXPECT_NE(s1, s2);
139     auto s3 = SingletonNamedUsage<Watchdog, Watchdog3>::try_get();
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.
146     auto s4 = SingletonNamedUsage<Watchdog>::try_get();
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>
155 using SingletonNaughtyUsage = Singleton <T, Tag, NaughtyUsageTag>;
156 struct NaughtyUsageTag2 {};
157 template <typename T, typename Tag = detail::DefaultTag>
158 using SingletonNaughtyUsage2 = Singleton <T, Tag, NaughtyUsageTag2>;
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
186 struct SharedPtrUsageTag {};
187 template <typename T, typename Tag = detail::DefaultTag>
188 using SingletonSharedPtrUsage = Singleton <T, Tag, SharedPtrUsageTag>;
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
233   auto s1 = SingletonSharedPtrUsage<Watchdog>::try_get().get();
234   EXPECT_NE(s1, nullptr);
235
236   auto s2 = SingletonSharedPtrUsage<Watchdog>::try_get().get();
237   EXPECT_NE(s2, nullptr);
238
239   EXPECT_EQ(s1, s2);
240
241   auto weak_s1 = SingletonSharedPtrUsage<Watchdog>::get_weak();
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   {
250     auto named_weak_s1 =
251       SingletonSharedPtrUsage<Watchdog, ATag>::get_weak();
252     auto locked = named_weak_s1.lock();
253     EXPECT_NE(locked.get(), shared_s1.get());
254   }
255
256   // We should release externally locked shared_ptr, otherwise it will be
257   // considered a leak
258   watchdog_holder_singleton.try_get()->watchdog = std::move(shared_s1);
259
260   LOG(ERROR) << "The following log message regarding shared_ptr is expected";
261   {
262     auto start_time = std::chrono::steady_clock::now();
263     vault.destroyInstances();
264     auto duration = std::chrono::steady_clock::now() - start_time;
265     EXPECT_TRUE(
266         duration > std::chrono::seconds{4} &&
267         duration < std::chrono::seconds{folly::kIsSanitizeAddress ? 30 : 6});
268   }
269   EXPECT_EQ(vault.registeredSingletonCount(), 4);
270   EXPECT_EQ(vault.livingSingletonCount(), 0);
271
272   EXPECT_TRUE(weak_s1.expired());
273
274   auto empty_s1 = SingletonSharedPtrUsage<Watchdog>::get_weak();
275   EXPECT_FALSE(empty_s1.lock());
276
277   vault.reenableInstances();
278
279   {
280     // Singleton should be re-created only after reenableInstances() was called.
281     auto new_s1 = SingletonSharedPtrUsage<Watchdog>::try_get();
282     // Track serial number rather than pointer since the memory could be
283     // re-used when we create new_s1.
284     EXPECT_NE(new_s1->serial_number, old_serial);
285   }
286
287   auto new_s1_weak = SingletonSharedPtrUsage<Watchdog>::get_weak();
288   auto new_s1_shared = new_s1_weak.lock();
289   std::thread t([new_s1_shared]() mutable {
290       std::this_thread::sleep_for(std::chrono::seconds{2});
291       new_s1_shared.reset();
292     });
293   new_s1_shared.reset();
294   {
295     auto start_time = std::chrono::steady_clock::now();
296     vault.destroyInstances();
297     auto duration = std::chrono::steady_clock::now() - start_time;
298     EXPECT_TRUE(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>
310 using SingletonNeedy = Singleton <T, Tag, NeedyTag>;
311
312 struct NeededSingleton {};
313 struct NeedySingleton {
314   NeedySingleton() {
315     auto unused = SingletonNeedy<NeededSingleton>::try_get();
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>
323 using SingletonSelfNeedy = Singleton <T, Tag, SelfNeedyTag>;
324
325 struct SelfNeedySingleton {
326   SelfNeedySingleton() {
327     auto unused = SingletonSelfNeedy<SelfNeedySingleton>::try_get();
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
342   auto needy = SingletonNeedy<NeedySingleton>::try_get();
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([]() { SingletonSelfNeedy<SelfNeedySingleton>::try_get(); }(),
350       "");
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:
358   Slowpoke() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); }
359 };
360
361 struct ConcurrencyTag {};
362 template <typename T, typename Tag = detail::DefaultTag>
363 using SingletonConcurrency = Singleton <T, Tag, ConcurrencyTag>;
364
365 TEST(Singleton, SingletonConcurrency) {
366   auto& vault = *SingletonVault::singleton<ConcurrencyTag>();
367   SingletonConcurrency<Slowpoke> slowpoke_singleton;
368   vault.registrationComplete();
369
370   std::mutex gatekeeper;
371   gatekeeper.lock();
372   auto func = [&gatekeeper]() {
373     gatekeeper.lock();
374     gatekeeper.unlock();
375     auto unused = SingletonConcurrency<Slowpoke>::try_get();
376   };
377
378   EXPECT_EQ(vault.livingSingletonCount(), 0);
379   std::vector<std::thread> threads;
380   for (int i = 0; i < 100; ++i) {
381     threads.emplace_back(func);
382   }
383   // If circular dependency checks fail, the unlock would trigger a
384   // crash.  Instead, it succeeds, and we have exactly one living
385   // singleton.
386   gatekeeper.unlock();
387   for (auto& t : threads) {
388     t.join();
389   }
390   EXPECT_EQ(vault.livingSingletonCount(), 1);
391 }
392
393 struct ErrorConstructor {
394   static size_t constructCount_;
395   ErrorConstructor() {
396     if ((constructCount_++) == 0) {
397       throw std::runtime_error("first time fails");
398     }
399   }
400 };
401 size_t ErrorConstructor::constructCount_(0);
402
403 struct CreationErrorTag {};
404 template <typename T, typename Tag = detail::DefaultTag>
405 using SingletonCreationError = Singleton<T, Tag, CreationErrorTag>;
406
407 TEST(Singleton, SingletonCreationError) {
408   SingletonCreationError<ErrorConstructor> error_once_singleton;
409   SingletonVault::singleton<CreationErrorTag>()->registrationComplete();
410
411   // first time should error out
412   EXPECT_THROW(error_once_singleton.try_get(), std::runtime_error);
413
414   // second time it'll work fine
415   error_once_singleton.try_get();
416   SUCCEED();
417 }
418
419 struct ConcurrencyStressTag {};
420 template <typename T, typename Tag = detail::DefaultTag>
421 using SingletonConcurrencyStress = Singleton <T, Tag, ConcurrencyStressTag>;
422
423 TEST(Singleton, SingletonConcurrencyStress) {
424   auto& vault = *SingletonVault::singleton<ConcurrencyStressTag>();
425   SingletonConcurrencyStress<Slowpoke> slowpoke_singleton;
426   vault.registrationComplete();
427
428   std::vector<std::thread> ts;
429   for (size_t i = 0; i < 100; ++i) {
430     ts.emplace_back([&]() {
431         slowpoke_singleton.try_get();
432       });
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>
453 using SingletonEagerInitSync = Singleton<T, Tag, EagerInitSyncTag>;
454 TEST(Singleton, SingletonEagerInitSync) {
455   auto& vault = *SingletonVault::singleton<EagerInitSyncTag>();
456   bool didEagerInit = false;
457   auto sing = SingletonEagerInitSync<std::string>(
458                   [&] {didEagerInit = true; return new std::string("foo"); })
459               .shouldEagerInit();
460   vault.registrationComplete();
461   EXPECT_FALSE(didEagerInit);
462   vault.doEagerInit();
463   EXPECT_TRUE(didEagerInit);
464   sing.get_weak();  // (avoid compile error complaining about unused var 'sing')
465 }
466
467 namespace {
468 struct EagerInitAsyncTag {};
469 } // namespace
470 template <typename T, typename Tag = detail::DefaultTag>
471 using SingletonEagerInitAsync = Singleton<T, Tag, EagerInitAsyncTag>;
472 TEST(Singleton, SingletonEagerInitAsync) {
473   auto& vault = *SingletonVault::singleton<EagerInitAsyncTag>();
474   bool didEagerInit = false;
475   auto sing = SingletonEagerInitAsync<std::string>(
476                   [&] {didEagerInit = true; return new std::string("foo"); })
477               .shouldEagerInit();
478   folly::EventBase eb;
479   folly::Baton<> done;
480   vault.registrationComplete();
481   EXPECT_FALSE(didEagerInit);
482   vault.doEagerInitVia(eb, &done);
483   eb.loop();
484   done.wait();
485   EXPECT_TRUE(didEagerInit);
486   sing.get_weak();  // (avoid compile error complaining about unused var 'sing')
487 }
488
489 namespace {
490 class TestEagerInitParallelExecutor : public folly::Executor {
491  public:
492   explicit TestEagerInitParallelExecutor(const size_t threadCount) {
493     eventBases_.reserve(threadCount);
494     threads_.reserve(threadCount);
495     for (size_t i = 0; i < threadCount; i++) {
496       eventBases_.push_back(std::make_shared<folly::EventBase>());
497       auto eb = eventBases_.back();
498       threads_.emplace_back(std::make_shared<std::thread>(
499           [eb] { eb->loopForever(); }));
500     }
501   }
502
503   ~TestEagerInitParallelExecutor() override {
504     for (auto eb : eventBases_) {
505       eb->runInEventBaseThread([eb] { eb->terminateLoopSoon(); });
506     }
507     for (auto thread : threads_) {
508       thread->join();
509     }
510   }
511
512   void add(folly::Func func) override {
513     const auto index = (counter_ ++) % eventBases_.size();
514     eventBases_[index]->add(std::move(func));
515   }
516
517  private:
518   std::vector<std::shared_ptr<folly::EventBase>> eventBases_;
519   std::vector<std::shared_ptr<std::thread>> threads_;
520   std::atomic<size_t> counter_ {0};
521 };
522 } // namespace
523
524 namespace {
525 struct EagerInitParallelTag {};
526 } // namespace
527 template <typename T, typename Tag = detail::DefaultTag>
528 using SingletonEagerInitParallel = Singleton<T, Tag, EagerInitParallelTag>;
529 TEST(Singleton, SingletonEagerInitParallel) {
530   const static size_t kIters = 1000;
531   const static size_t kThreads = 20;
532
533   std::atomic<size_t> initCounter;
534
535   auto& vault = *SingletonVault::singleton<EagerInitParallelTag>();
536
537   auto sing = SingletonEagerInitParallel<std::string>(
538                   [&] {++initCounter; return new std::string(""); })
539               .shouldEagerInit();
540
541   for (size_t i = 0; i < kIters; i++) {
542     SCOPE_EXIT {
543       // clean up each time
544       vault.destroyInstances();
545       vault.reenableInstances();
546     };
547
548     initCounter.store(0);
549
550     {
551       std::vector<std::shared_ptr<std::thread>> threads;
552       boost::barrier barrier(kThreads);
553       TestEagerInitParallelExecutor exe(kThreads);
554       vault.registrationComplete();
555
556       EXPECT_EQ(0, initCounter.load());
557
558       for (size_t j = 0; j < kThreads; j++) {
559         threads.push_back(std::make_shared<std::thread>([&] {
560           barrier.wait();
561           vault.doEagerInitVia(exe);
562         }));
563       }
564
565       for (auto thread : threads) {
566         thread->join();
567       }
568     }
569
570     EXPECT_EQ(1, initCounter.load());
571
572     sing.get_weak();  // (avoid compile error complaining about unused var)
573   }
574 }
575
576 struct MockTag {};
577 template <typename T, typename Tag = detail::DefaultTag>
578 using SingletonMock = Singleton <T, Tag, MockTag>;
579
580 // Verify that existing Singleton's can be overridden
581 // using the make_mock functionality.
582 TEST(Singleton, MockTest) {
583   auto& vault = *SingletonVault::singleton<MockTag>();
584
585   SingletonMock<Watchdog> watchdog_singleton;
586   vault.registrationComplete();
587
588   // Registring singletons after registrationComplete called works
589   // with make_mock (but not with Singleton ctor).
590   EXPECT_EQ(vault.registeredSingletonCount(), 1);
591   int serial_count_first = SingletonMock<Watchdog>::try_get()->serial_number;
592
593   // Override existing mock using make_mock.
594   SingletonMock<Watchdog>::make_mock();
595
596   EXPECT_EQ(vault.registeredSingletonCount(), 1);
597   int serial_count_mock = SingletonMock<Watchdog>::try_get()->serial_number;
598
599   // If serial_count value is the same, then singleton was not replaced.
600   EXPECT_NE(serial_count_first, serial_count_mock);
601
602   // Override existing mock using make_mock one more time
603   SingletonMock<Watchdog>::make_mock();
604
605   EXPECT_EQ(vault.registeredSingletonCount(), 1);
606   int serial_count_mock2 = SingletonMock<Watchdog>::try_get()->serial_number;
607
608   // If serial_count value is the same, then singleton was not replaced.
609   EXPECT_NE(serial_count_first, serial_count_mock2);
610   EXPECT_NE(serial_count_mock, serial_count_mock2);
611
612   vault.destroyInstances();
613 }
614
615 #ifndef _MSC_VER
616 // Subprocess isn't currently supported under MSVC.
617 TEST(Singleton, DoubleRegistrationLogging) {
618   const auto basename = "singleton_double_registration";
619   const auto sub = fs::executable_path().remove_filename() / basename;
620   auto p = Subprocess(
621       std::vector<std::string>{sub.string()},
622       Subprocess::Options()
623           .stdinFd(Subprocess::CLOSE)
624           .stdoutFd(Subprocess::CLOSE)
625           .pipeStderr()
626           .closeOtherFds());
627   auto err = p.communicate("").second;
628   auto res = p.wait();
629   EXPECT_EQ(ProcessReturnCode::KILLED, res.state());
630   EXPECT_EQ(SIGABRT, res.killSignal());
631   EXPECT_THAT(err, testing::StartsWith("Double registration of singletons"));
632 }
633 #endif
634
635 // Singleton using a non default constructor test/example:
636 struct X {
637   X() : X(-1, "unset") {}
638   X(int a1, std::string a2) : a1(a1), a2(a2) {
639     LOG(INFO) << "X(" << a1 << "," << a2 << ")";
640   }
641   const int a1;
642   const std::string a2;
643 };
644
645 folly::Singleton<X> singleton_x([]() { return new X(42, "foo"); });
646
647 TEST(Singleton, CustomCreator) {
648   X x1;
649   std::shared_ptr<X> x2p = singleton_x.try_get();
650   EXPECT_NE(nullptr, x2p);
651   EXPECT_NE(x1.a1, x2p->a1);
652   EXPECT_NE(x1.a2, x2p->a2);
653   EXPECT_EQ(42, x2p->a1);
654   EXPECT_EQ(std::string("foo"), x2p->a2);
655 }
656
657 struct ConcurrentCreationDestructionTag {};
658 template <typename T, typename Tag = detail::DefaultTag>
659 using SingletonConcurrentCreationDestruction =
660     Singleton<T, Tag, ConcurrentCreationDestructionTag>;
661
662 folly::Baton<> slowpokeNeedySingletonBaton;
663
664 struct SlowpokeNeedySingleton {
665   SlowpokeNeedySingleton() {
666     slowpokeNeedySingletonBaton.post();
667     /* sleep override */ std::this_thread::sleep_for(
668         std::chrono::milliseconds(100));
669     auto unused =
670         SingletonConcurrentCreationDestruction<NeededSingleton>::try_get();
671     EXPECT_NE(unused, nullptr);
672   }
673 };
674
675 TEST(Singleton, ConcurrentCreationDestruction) {
676   auto& vault = *SingletonVault::singleton<ConcurrentCreationDestructionTag>();
677   SingletonConcurrentCreationDestruction<NeededSingleton> neededSingleton;
678   SingletonConcurrentCreationDestruction<SlowpokeNeedySingleton> needySingleton;
679   vault.registrationComplete();
680
681   std::thread needyThread([&] { needySingleton.try_get(); });
682
683   slowpokeNeedySingletonBaton.wait();
684
685   vault.destroyInstances();
686
687   needyThread.join();
688 }
689
690 struct MainThreadDestructorTag {};
691 template <typename T, typename Tag = detail::DefaultTag>
692 using SingletonMainThreadDestructor =
693     Singleton<T, Tag, MainThreadDestructorTag>;
694
695 struct ThreadLoggingSingleton {
696   ThreadLoggingSingleton() {
697     initThread = std::this_thread::get_id();
698   }
699
700   ~ThreadLoggingSingleton() {
701     destroyThread = std::this_thread::get_id();
702   }
703
704   static std::thread::id initThread;
705   static std::thread::id destroyThread;
706 };
707 std::thread::id ThreadLoggingSingleton::initThread{};
708 std::thread::id ThreadLoggingSingleton::destroyThread{};
709
710 TEST(Singleton, MainThreadDestructor) {
711   auto& vault = *SingletonVault::singleton<MainThreadDestructorTag>();
712   SingletonMainThreadDestructor<ThreadLoggingSingleton> singleton;
713
714   vault.registrationComplete();
715   EXPECT_EQ(std::thread::id(), ThreadLoggingSingleton::initThread);
716
717   singleton.try_get();
718   EXPECT_EQ(std::this_thread::get_id(), ThreadLoggingSingleton::initThread);
719
720   std::thread t([instance = singleton.try_get()] {
721     /* sleep override */ std::this_thread::sleep_for(
722         std::chrono::milliseconds{100});
723   });
724
725   EXPECT_EQ(std::thread::id(), ThreadLoggingSingleton::destroyThread);
726
727   vault.destroyInstances();
728   EXPECT_EQ(std::this_thread::get_id(), ThreadLoggingSingleton::destroyThread);
729
730   t.join();
731 }
732
733 TEST(Singleton, DoubleMakeMockAfterTryGet) {
734   // to keep track of calls to ctor and dtor below
735   struct Counts {
736     size_t ctor = 0;
737     size_t dtor = 0;
738   };
739
740   // a test type which keeps track of its ctor and dtor calls
741   struct VaultTag {};
742   struct PrivateTag {};
743   struct Object {
744     explicit Object(Counts& counts) : counts_(counts) {
745       ++counts_.ctor;
746     }
747     ~Object() {
748       ++counts_.dtor;
749     }
750     Counts& counts_;
751   };
752   using SingletonObject = Singleton<Object, PrivateTag, VaultTag>;
753
754   // register everything
755   Counts counts;
756   auto& vault = *SingletonVault::singleton<VaultTag>();
757   auto new_object = [&] { return new Object(counts); };
758   SingletonObject object_(new_object);
759   vault.registrationComplete();
760
761   // no eager inits, nada (sanity)
762   EXPECT_EQ(0, counts.ctor);
763   EXPECT_EQ(0, counts.dtor);
764
765   // explicit request, ctor
766   SingletonObject::try_get();
767   EXPECT_EQ(1, counts.ctor);
768   EXPECT_EQ(0, counts.dtor);
769
770   // first make_mock, dtor (ctor is lazy)
771   SingletonObject::make_mock(new_object);
772   EXPECT_EQ(1, counts.ctor);
773   EXPECT_EQ(1, counts.dtor);
774
775   // second make_mock, nada (dtor already ran, ctor is lazy)
776   SingletonObject::make_mock(new_object);
777   EXPECT_EQ(1, counts.ctor);
778   EXPECT_EQ(1, counts.dtor);
779 }