userver: userver/testsuite/cache_control.hpp Source File
Loading...
Searching...
No Matches
cache_control.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/testsuite/cache_control.hpp
4/// @brief @copybrief testsuite::CacheControl
5
6#include <functional>
7#include <memory>
8#include <string>
9#include <type_traits>
10#include <unordered_set>
11
12#include <userver/cache/update_type.hpp>
13#include <userver/components/component_fwd.hpp>
14#include <userver/utils/assert.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace cache {
20struct Config;
21} // namespace cache
22
23namespace components::impl {
24class ComponentBase;
25} // namespace components::impl
26
27namespace testsuite {
28
29namespace impl {
30enum class PeriodicUpdatesMode { kDefault, kEnabled, kDisabled };
31} // namespace impl
32
33class CacheResetRegistration;
34
35/// @brief Testsuite interface for caches and cache-like components.
36///
37/// If a component stores transient state that may be carried between tests,
38/// or stores caches that may become stale, then it should register its resetter
39/// here. Example:
40///
41/// @snippet testsuite/cache_control_test.cpp sample
42///
43/// Testsuite will then call this hook in the beginning of each test.
44/// You can also reset a specific cache in testsuite explicitly as follows:
45///
46/// @code
47/// service_client.invalidate_caches(names=['your-cache-name'])
48/// @endcode
49///
50/// CacheControl is normally acquired through testsuite::FindCacheControl.
51///
52/// All methods are coro-safe.
53class CacheControl final {
54 public:
55 /// @brief Register a cache reset function. The returned handle must be kept
56 /// alive to keep supporting cache resetting.
57 ///
58 /// @warning The function should be called in the component's constructor
59 /// *after* all FindComponent calls. This ensures that reset will first be
60 /// called for dependencies, then for dependent components.
61 template <typename Component>
62 CacheResetRegistration RegisterCache(Component* self, std::string_view name,
63 void (Component::*reset_method)());
64
65 /// @brief Reset all the registered caches.
66 ///
67 /// @a update_type is used by caches derived from
68 /// @a component::CachingComponentBase.
70 cache::UpdateType update_type,
71 const std::unordered_set<std::string>& force_incremental_names,
72 const std::unordered_set<std::string>& exclude_names);
73
74 /// @brief Reset caches with the specified @a names.
75 ///
76 /// @a update_type is used by caches derived from
77 /// @a component::CachingComponentBase.
79 cache::UpdateType update_type,
80 std::unordered_set<std::string> reset_only_names,
81 const std::unordered_set<std::string>& force_incremental_names);
82
83 /// @cond
84 // For internal use only.
85 explicit CacheControl(impl::PeriodicUpdatesMode);
86 ~CacheControl();
87
88 CacheControl(CacheControl&&) = delete;
89 CacheControl& operator=(CacheControl&&) = delete;
90
91 // For internal use only.
92 bool IsPeriodicUpdateEnabled(const cache::Config& cache_config,
93 const std::string& cache_name) const;
94
95 // For internal use only.
96 CacheResetRegistration RegisterPeriodicCache(cache::CacheUpdateTrait& cache);
97
98 private:
99 friend class CacheResetRegistration;
100
101 struct CacheInfo final {
102 std::string name;
103 std::function<void(cache::UpdateType)> reset;
104 bool needs_span{true};
105 components::impl::ComponentBase* component = nullptr;
106 };
107
108 struct CacheInfoNode;
109 using CacheInfoIterator = CacheInfoNode*;
110
111 CacheInfoIterator DoRegisterCache(CacheInfo&& info);
112
113 void UnregisterCache(CacheInfoIterator) noexcept;
114
115 static void DoResetCache(const CacheInfo& info,
116 cache::UpdateType update_type);
117
118 struct Impl;
119 std::unique_ptr<Impl> impl_;
120};
121
122/// @brief RAII helper for testsuite registration. Must be kept alive to keep
123/// supporting cache resetting.
124/// @warning Make sure to always place CacheResetRegistration after the rest of
125/// the component's fields.
126/// @see testsuite::CacheControl
127class [[nodiscard]] CacheResetRegistration final {
128 public:
129 CacheResetRegistration() noexcept;
130
131 CacheResetRegistration(CacheResetRegistration&&) noexcept;
132 CacheResetRegistration& operator=(CacheResetRegistration&&) noexcept;
133 ~CacheResetRegistration();
134
135 /// Unregister the cache component explicitly.
136 /// `Unregister` is called in the destructor automatically.
137 void Unregister() noexcept;
138
139 /// @cond
140 // For internal use only.
141 CacheResetRegistration(CacheControl&, CacheControl::CacheInfoIterator);
142 /// @endcond
143
144 private:
145 CacheControl* cache_control_{nullptr};
146 CacheControl::CacheInfoIterator cache_info_iterator_{};
147};
148
149/// The method for acquiring testsuite::CacheControl in the component system.
150///
151/// @see testsuite::RegisterCache
152CacheControl& FindCacheControl(const components::ComponentContext& context);
153
154/// The method for registering a cache from component constructor.
155template <typename Component>
156CacheResetRegistration RegisterCache(
157 const components::ComponentConfig& config,
158 const components::ComponentContext& context, Component* self,
159 void (Component::*reset_method)()) {
160 auto& cc = testsuite::FindCacheControl(context);
161 return cc.RegisterCache(self, components::GetCurrentComponentName(config),
162 reset_method);
163}
164
165template <typename Component>
166CacheResetRegistration CacheControl::RegisterCache(
167 Component* self, std::string_view name, void (Component::*reset_method)()) {
168 static_assert(std::is_base_of_v<components::impl::ComponentBase, Component>,
169 "CacheControl can only be used with components");
170 UASSERT(self);
171 UASSERT(reset_method);
172
173 CacheInfo info;
174 info.component = self;
175 info.name = std::string{name};
176 info.reset = [self, reset_method]([[maybe_unused]] cache::UpdateType) {
177 (self->*reset_method)();
178 };
179 info.needs_span = true;
180
181 auto iter = DoRegisterCache(std::move(info));
182 return CacheResetRegistration(*this, std::move(iter));
183}
184
185} // namespace testsuite
186
187USERVER_NAMESPACE_END