Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/test/test_common/global.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include "source/common/common/lock_guard.h"
4
#include "source/common/common/thread.h"
5
6
#include "absl/container/flat_hash_map.h"
7
8
namespace Envoy {
9
namespace Test {
10
11
/**
12
 * Helper class for managing Global<Type>s.
13
 *
14
 * This class is instantiated as a process-scoped singleton. It manages a map
15
 * from type-name to weak_ptr<GlobalHelper::Singleton>. That map accumulates
16
 * over a process lifetime and never shrinks. However, the weak_ptr will
17
 * generally be cleared after each test, as all shared_ptr references held in
18
 * Global<Type> instances are destroyed. This way, each unit-test gets a fresh
19
 * start.
20
 */
21
class Globals {
22
public:
23
  /**
24
   * Walks through all global singletons and ensures that none of them are
25
   * active. No singletons should be allocated at the end of unit tests, so
26
   * this is called at the end of Envoy::TestRunner::runTests().
27
   *
28
   * @return std::string empty string if quiescent, otherwise newline-separated
29
   *    error messages.
30
   */
31
0
  static std::string describeActiveSingletons() {
32
0
    return instance().describeActiveSingletonsHelper();
33
0
  }
34
35
  /**
36
   * Manages Singleton objects that are cleaned up after all references are
37
   * dropped. This class must not be templatized because as a map value where
38
   * every singleton in the map represents a different type. Instead we
39
   * templatize the ptr() and ref() methods.
40
   */
41
  struct Singleton {
42
169k
    virtual ~Singleton() = default;
43
    virtual void* ptrHelper() PURE;
44
9.37M
    template <class Type> Type* ptr() { return static_cast<Type*>(ptrHelper()); }
Envoy::Event::SingletonTimeSystemHelper* Envoy::Test::Globals::Singleton::ptr<Envoy::Event::SingletonTimeSystemHelper>()
Line
Count
Source
44
5.60M
    template <class Type> Type* ptr() { return static_cast<Type*>(ptrHelper()); }
Envoy::Stats::TestUtil::TestSymbolTableHelper* Envoy::Test::Globals::Singleton::ptr<Envoy::Stats::TestUtil::TestSymbolTableHelper>()
Line
Count
Source
44
3.77M
    template <class Type> Type* ptr() { return static_cast<Type*>(ptrHelper()); }
45
3.77M
    template <class Type> Type& ref() { return *ptr<Type>(); }
46
  };
47
  using SingletonSharedPtr = std::shared_ptr<Singleton>;
48
49
  /**
50
   * @return Type a singleton instance of Type. T must be default-constructible.
51
   */
52
4.98M
  template <class Type> static SingletonSharedPtr get() { return instance().getHelper<Type>(); }
std::__1::shared_ptr<Envoy::Test::Globals::Singleton> Envoy::Test::Globals::get<Envoy::Event::SingletonTimeSystemHelper>()
Line
Count
Source
52
644k
  template <class Type> static SingletonSharedPtr get() { return instance().getHelper<Type>(); }
std::__1::shared_ptr<Envoy::Test::Globals::Singleton> Envoy::Test::Globals::get<Envoy::Stats::TestUtil::TestSymbolTableHelper>()
Line
Count
Source
52
4.34M
  template <class Type> static SingletonSharedPtr get() { return instance().getHelper<Type>(); }
53
54
  ~Globals() = delete; // Globals is constructed once and never destroyed.
55
56
private:
57
  /**
58
   * Templatized derived class of Singleton which holds the Type object and is
59
   * responsible for deleting it using the correct destructor.
60
   */
61
  template <class Type> struct TypedSingleton : public Singleton {
62
169k
    ~TypedSingleton() override = default;
Envoy::Test::Globals::TypedSingleton<Envoy::Event::SingletonTimeSystemHelper>::~TypedSingleton()
Line
Count
Source
62
89.8k
    ~TypedSingleton() override = default;
Envoy::Test::Globals::TypedSingleton<Envoy::Stats::TestUtil::TestSymbolTableHelper>::~TypedSingleton()
Line
Count
Source
62
79.4k
    ~TypedSingleton() override = default;
63
9.37M
    void* ptrHelper() override { return ptr_.get(); }
Envoy::Test::Globals::TypedSingleton<Envoy::Event::SingletonTimeSystemHelper>::ptrHelper()
Line
Count
Source
63
5.60M
    void* ptrHelper() override { return ptr_.get(); }
Envoy::Test::Globals::TypedSingleton<Envoy::Stats::TestUtil::TestSymbolTableHelper>::ptrHelper()
Line
Count
Source
63
3.77M
    void* ptrHelper() override { return ptr_.get(); }
64
65
  private:
66
    std::unique_ptr<Type> ptr_{std::make_unique<Type>()};
67
  };
68
69
46
  Globals() = default; // Construct via Globals::instance().
70
71
  /**
72
   * @return Globals& a singleton for Globals.
73
   */
74
  static Globals& instance();
75
76
4.98M
  template <class Type> SingletonSharedPtr getHelper() {
77
4.98M
    Thread::LockGuard map_lock(map_mutex_);
78
4.98M
    std::weak_ptr<Singleton>& weak_singleton_ref = singleton_map_[typeid(Type).name()];
79
4.98M
    SingletonSharedPtr singleton = weak_singleton_ref.lock();
80
81
4.98M
    if (singleton == nullptr) {
82
169k
      singleton = std::make_shared<TypedSingleton<Type>>();
83
169k
      weak_singleton_ref = singleton;
84
169k
    }
85
4.98M
    return singleton;
86
4.98M
  }
std::__1::shared_ptr<Envoy::Test::Globals::Singleton> Envoy::Test::Globals::getHelper<Envoy::Event::SingletonTimeSystemHelper>()
Line
Count
Source
76
644k
  template <class Type> SingletonSharedPtr getHelper() {
77
644k
    Thread::LockGuard map_lock(map_mutex_);
78
644k
    std::weak_ptr<Singleton>& weak_singleton_ref = singleton_map_[typeid(Type).name()];
79
644k
    SingletonSharedPtr singleton = weak_singleton_ref.lock();
80
81
644k
    if (singleton == nullptr) {
82
89.8k
      singleton = std::make_shared<TypedSingleton<Type>>();
83
89.8k
      weak_singleton_ref = singleton;
84
89.8k
    }
85
644k
    return singleton;
86
644k
  }
std::__1::shared_ptr<Envoy::Test::Globals::Singleton> Envoy::Test::Globals::getHelper<Envoy::Stats::TestUtil::TestSymbolTableHelper>()
Line
Count
Source
76
4.34M
  template <class Type> SingletonSharedPtr getHelper() {
77
4.34M
    Thread::LockGuard map_lock(map_mutex_);
78
4.34M
    std::weak_ptr<Singleton>& weak_singleton_ref = singleton_map_[typeid(Type).name()];
79
4.34M
    SingletonSharedPtr singleton = weak_singleton_ref.lock();
80
81
4.34M
    if (singleton == nullptr) {
82
79.4k
      singleton = std::make_shared<TypedSingleton<Type>>();
83
79.4k
      weak_singleton_ref = singleton;
84
79.4k
    }
85
4.34M
    return singleton;
86
4.34M
  }
87
88
  std::string describeActiveSingletonsHelper();
89
90
  Thread::MutexBasicLockable map_mutex_;
91
  absl::flat_hash_map<std::string, std::weak_ptr<Singleton>>
92
      singleton_map_ ABSL_GUARDED_BY(map_mutex_);
93
};
94
95
/**
96
 * Helps manage classes that need to be instantiated once per server. In
97
 * production they must be plumbed through call/class hierarchy, but
98
 * in test-code the zero-arg-constructor Mock pattern makes this impractical.
99
 * Instead we use self-cleaning singletons.
100
 *
101
 * Say for example you need a FooImpl plumbed through the system. In production
102
 * code you must propagate a FooImpl through constructors to provide access
103
 * where needed. For tests, everywhere a common FooImpl is required,
104
 * instantiate:
105
 *
106
 *   Global<FooImpl> foo;
107
 *
108
 * You can then access the singleton FooImpl via foo.get(). The underlying
109
 * FooImpl is ref-counted, and when the last TestGlobal is freed, the singleton
110
 * FooImpl will be destructed and the singleton pointer nulled.
111
 *
112
 * The templated type must have a zero-arg constructor. Templatizing this on an
113
 * int will compile, but will be hard to use as the memory will be uninitialized
114
 * and you will not know when instantiating it whether it needs to be
115
 * initialized.
116
 */
117
template <class Type> class Global {
118
public:
119
4.98M
  Global() : singleton_(Globals::get<Type>()) {}
Envoy::Test::Global<Envoy::Event::SingletonTimeSystemHelper>::Global()
Line
Count
Source
119
644k
  Global() : singleton_(Globals::get<Type>()) {}
Envoy::Test::Global<Envoy::Stats::TestUtil::TestSymbolTableHelper>::Global()
Line
Count
Source
119
4.34M
  Global() : singleton_(Globals::get<Type>()) {}
120
3.77M
  Type& get() { return singleton_->ref<Type>(); }
121
0
  const Type& get() const { return singleton_->ref<Type>(); }
122
5.60M
  Type* operator->() { return singleton_->ptr<Type>(); }
123
  Type& operator*() { return singleton_->ref<Type>(); }
124
125
private:
126
  Globals::SingletonSharedPtr singleton_;
127
};
128
129
} // namespace Test
130
} // namespace Envoy