xref: /aosp_15_r20/external/cronet/base/test/repeating_test_future.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2021 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_TEST_REPEATING_TEST_FUTURE_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_TEST_REPEATING_TEST_FUTURE_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <optional>
9*6777b538SAndroid Build Coastguard Worker #include <utility>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/containers/queue.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/memory/weak_ptr.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/run_loop.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/sequence_checker.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/test/test_future_internal.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/thread_annotations.h"
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker namespace base::test {
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker // DEPRECATED!
22*6777b538SAndroid Build Coastguard Worker //
23*6777b538SAndroid Build Coastguard Worker // Please use `TestFuture` with `TestFuture::GetRepeatingCallback()` instead.
24*6777b538SAndroid Build Coastguard Worker template <typename... Types>
25*6777b538SAndroid Build Coastguard Worker class RepeatingTestFuture {
26*6777b538SAndroid Build Coastguard Worker  public:
27*6777b538SAndroid Build Coastguard Worker   using TupleType = std::tuple<std::decay_t<Types>...>;
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker   RepeatingTestFuture() = default;
30*6777b538SAndroid Build Coastguard Worker   RepeatingTestFuture(const RepeatingTestFuture&) = delete;
31*6777b538SAndroid Build Coastguard Worker   RepeatingTestFuture& operator=(const RepeatingTestFuture&) = delete;
32*6777b538SAndroid Build Coastguard Worker   RepeatingTestFuture(RepeatingTestFuture&&) = delete;
33*6777b538SAndroid Build Coastguard Worker   RepeatingTestFuture& operator=(RepeatingTestFuture&&) = delete;
34*6777b538SAndroid Build Coastguard Worker   ~RepeatingTestFuture() = default;
35*6777b538SAndroid Build Coastguard Worker 
AddValue(Types...values)36*6777b538SAndroid Build Coastguard Worker   void AddValue(Types... values) {
37*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker     elements_.push(std::make_tuple(std::forward<Types>(values)...));
40*6777b538SAndroid Build Coastguard Worker     SignalElementIsAvailable();
41*6777b538SAndroid Build Coastguard Worker   }
42*6777b538SAndroid Build Coastguard Worker 
43*6777b538SAndroid Build Coastguard Worker   // Waits until an element is available.
44*6777b538SAndroid Build Coastguard Worker   // Returns immediately if one or more elements are already available.
45*6777b538SAndroid Build Coastguard Worker   //
46*6777b538SAndroid Build Coastguard Worker   // Returns true if an element arrived, or false if a timeout happens.
47*6777b538SAndroid Build Coastguard Worker   //
48*6777b538SAndroid Build Coastguard Worker   // Directly calling Wait() is not required as Take() will also wait for
49*6777b538SAndroid Build Coastguard Worker   // the value to arrive, however you can use a direct call to Wait() to
50*6777b538SAndroid Build Coastguard Worker   // improve the error reported:
51*6777b538SAndroid Build Coastguard Worker   //
52*6777b538SAndroid Build Coastguard Worker   //   ASSERT_TRUE(queue.Wait()) << "Detailed error message";
53*6777b538SAndroid Build Coastguard Worker   //
Wait()54*6777b538SAndroid Build Coastguard Worker   [[nodiscard]] bool Wait() {
55*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker     if (IsEmpty()) {
58*6777b538SAndroid Build Coastguard Worker       WaitForANewElement();
59*6777b538SAndroid Build Coastguard Worker     }
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker     return !IsEmpty();
62*6777b538SAndroid Build Coastguard Worker   }
63*6777b538SAndroid Build Coastguard Worker 
64*6777b538SAndroid Build Coastguard Worker   // Returns a callback that when invoked will store all the argument values,
65*6777b538SAndroid Build Coastguard Worker   // and unblock any waiters.
66*6777b538SAndroid Build Coastguard Worker   // This method is templated so you can specify how you need the arguments to
67*6777b538SAndroid Build Coastguard Worker   // be passed - be it const, as reference, or anything you can think off.
68*6777b538SAndroid Build Coastguard Worker   // By default the callback accepts the arguments as `Types...`.
69*6777b538SAndroid Build Coastguard Worker   //
70*6777b538SAndroid Build Coastguard Worker   // Example usage:
71*6777b538SAndroid Build Coastguard Worker   //
72*6777b538SAndroid Build Coastguard Worker   //   RepeatingTestFuture<int, std::string> future;
73*6777b538SAndroid Build Coastguard Worker   //
74*6777b538SAndroid Build Coastguard Worker   //   // returns base::RepeatingCallback<void(int, std::string)>
75*6777b538SAndroid Build Coastguard Worker   //   future.GetCallback();
76*6777b538SAndroid Build Coastguard Worker   //
77*6777b538SAndroid Build Coastguard Worker   //   // returns base::RepeatingCallback<void(int, const std::string&)>
78*6777b538SAndroid Build Coastguard Worker   //   future.GetCallback<int, const std::string&>();
79*6777b538SAndroid Build Coastguard Worker   //
80*6777b538SAndroid Build Coastguard Worker   template <typename... CallbackArgumentsTypes>
GetCallback()81*6777b538SAndroid Build Coastguard Worker   base::RepeatingCallback<void(CallbackArgumentsTypes...)> GetCallback() {
82*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
83*6777b538SAndroid Build Coastguard Worker     return base::BindRepeating(
84*6777b538SAndroid Build Coastguard Worker         [](WeakPtr<RepeatingTestFuture<Types...>> future,
85*6777b538SAndroid Build Coastguard Worker            CallbackArgumentsTypes... values) {
86*6777b538SAndroid Build Coastguard Worker           if (future) {
87*6777b538SAndroid Build Coastguard Worker             future->AddValue(std::forward<CallbackArgumentsTypes>(values)...);
88*6777b538SAndroid Build Coastguard Worker           }
89*6777b538SAndroid Build Coastguard Worker         },
90*6777b538SAndroid Build Coastguard Worker         weak_ptr_factory_.GetWeakPtr());
91*6777b538SAndroid Build Coastguard Worker   }
92*6777b538SAndroid Build Coastguard Worker 
GetCallback()93*6777b538SAndroid Build Coastguard Worker   base::RepeatingCallback<void(Types...)> GetCallback() {
94*6777b538SAndroid Build Coastguard Worker     return GetCallback<Types...>();
95*6777b538SAndroid Build Coastguard Worker   }
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker   // Returns true if no elements are currently present. Note that consuming all
98*6777b538SAndroid Build Coastguard Worker   // elements through Take() will cause this method to return true after the
99*6777b538SAndroid Build Coastguard Worker   // last available element has been consumed.
IsEmpty()100*6777b538SAndroid Build Coastguard Worker   bool IsEmpty() const {
101*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
102*6777b538SAndroid Build Coastguard Worker 
103*6777b538SAndroid Build Coastguard Worker     return elements_.empty();
104*6777b538SAndroid Build Coastguard Worker   }
105*6777b538SAndroid Build Coastguard Worker 
106*6777b538SAndroid Build Coastguard Worker   //////////////////////////////////////////////////////////////////////////////
107*6777b538SAndroid Build Coastguard Worker   //  Accessor methods only available if each element in the future holds a
108*6777b538SAndroid Build Coastguard Worker   //  single value.
109*6777b538SAndroid Build Coastguard Worker   //////////////////////////////////////////////////////////////////////////////
110*6777b538SAndroid Build Coastguard Worker 
111*6777b538SAndroid Build Coastguard Worker   // Wait for an element to arrive, and move its value out.
112*6777b538SAndroid Build Coastguard Worker   //
113*6777b538SAndroid Build Coastguard Worker   // Will DCHECK if a timeout happens.
114*6777b538SAndroid Build Coastguard Worker   template <typename T = TupleType, internal::EnableIfSingleValue<T> = true>
Take()115*6777b538SAndroid Build Coastguard Worker   auto Take() {
116*6777b538SAndroid Build Coastguard Worker     return std::get<0>(TakeTuple());
117*6777b538SAndroid Build Coastguard Worker   }
118*6777b538SAndroid Build Coastguard Worker 
119*6777b538SAndroid Build Coastguard Worker   //////////////////////////////////////////////////////////////////////////////
120*6777b538SAndroid Build Coastguard Worker   //  Accessor methods only available if each element in the future holds
121*6777b538SAndroid Build Coastguard Worker   //  multiple values.
122*6777b538SAndroid Build Coastguard Worker   //////////////////////////////////////////////////////////////////////////////
123*6777b538SAndroid Build Coastguard Worker 
124*6777b538SAndroid Build Coastguard Worker   // Wait for an element to arrive, and move a tuple with its values out.
125*6777b538SAndroid Build Coastguard Worker   //
126*6777b538SAndroid Build Coastguard Worker   // Will DCHECK if a timeout happens.
127*6777b538SAndroid Build Coastguard Worker   template <typename T = TupleType, internal::EnableIfMultiValue<T> = true>
Take()128*6777b538SAndroid Build Coastguard Worker   TupleType Take() {
129*6777b538SAndroid Build Coastguard Worker     return TakeTuple();
130*6777b538SAndroid Build Coastguard Worker   }
131*6777b538SAndroid Build Coastguard Worker 
132*6777b538SAndroid Build Coastguard Worker  private:
133*6777b538SAndroid Build Coastguard Worker   // Wait until a new element is available.
WaitForANewElement()134*6777b538SAndroid Build Coastguard Worker   void WaitForANewElement() VALID_CONTEXT_REQUIRED(sequence_checker_) {
135*6777b538SAndroid Build Coastguard Worker     DCHECK(!run_loop_.has_value());
136*6777b538SAndroid Build Coastguard Worker 
137*6777b538SAndroid Build Coastguard Worker     // Create a new run loop.
138*6777b538SAndroid Build Coastguard Worker     run_loop_.emplace();
139*6777b538SAndroid Build Coastguard Worker     // Wait until 'run_loop_->Quit()' is called.
140*6777b538SAndroid Build Coastguard Worker     run_loop_->Run();
141*6777b538SAndroid Build Coastguard Worker     run_loop_.reset();
142*6777b538SAndroid Build Coastguard Worker   }
143*6777b538SAndroid Build Coastguard Worker 
SignalElementIsAvailable()144*6777b538SAndroid Build Coastguard Worker   void SignalElementIsAvailable() VALID_CONTEXT_REQUIRED(sequence_checker_) {
145*6777b538SAndroid Build Coastguard Worker     if (run_loop_.has_value()) {
146*6777b538SAndroid Build Coastguard Worker       run_loop_->Quit();
147*6777b538SAndroid Build Coastguard Worker     }
148*6777b538SAndroid Build Coastguard Worker   }
149*6777b538SAndroid Build Coastguard Worker 
TakeTuple()150*6777b538SAndroid Build Coastguard Worker   TupleType TakeTuple() {
151*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker     // Ensure an element is available.
154*6777b538SAndroid Build Coastguard Worker     bool success = Wait();
155*6777b538SAndroid Build Coastguard Worker     DCHECK(success) << "Waiting for an element timed out.";
156*6777b538SAndroid Build Coastguard Worker 
157*6777b538SAndroid Build Coastguard Worker     auto result = std::move(elements_.front());
158*6777b538SAndroid Build Coastguard Worker     elements_.pop();
159*6777b538SAndroid Build Coastguard Worker     return result;
160*6777b538SAndroid Build Coastguard Worker   }
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker   base::queue<TupleType> elements_ GUARDED_BY_CONTEXT(sequence_checker_);
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker   // Used by Wait() to know when AddValue() is called.
165*6777b538SAndroid Build Coastguard Worker   std::optional<base::RunLoop> run_loop_ GUARDED_BY_CONTEXT(sequence_checker_);
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker   SEQUENCE_CHECKER(sequence_checker_);
168*6777b538SAndroid Build Coastguard Worker 
169*6777b538SAndroid Build Coastguard Worker   base::WeakPtrFactory<RepeatingTestFuture<Types...>> weak_ptr_factory_{this};
170*6777b538SAndroid Build Coastguard Worker };
171*6777b538SAndroid Build Coastguard Worker 
172*6777b538SAndroid Build Coastguard Worker // Specialization so you can use `RepeatingTestFuture` to wait for a no-args
173*6777b538SAndroid Build Coastguard Worker // callback.
174*6777b538SAndroid Build Coastguard Worker template <>
175*6777b538SAndroid Build Coastguard Worker class RepeatingTestFuture<void> {
176*6777b538SAndroid Build Coastguard Worker  public:
AddValue()177*6777b538SAndroid Build Coastguard Worker   void AddValue() { implementation_.AddValue(true); }
178*6777b538SAndroid Build Coastguard Worker 
179*6777b538SAndroid Build Coastguard Worker   // Waits until the callback or `AddValue()` is invoked.
180*6777b538SAndroid Build Coastguard Worker   // Returns immediately if one or more invocations have already happened.
181*6777b538SAndroid Build Coastguard Worker   //
182*6777b538SAndroid Build Coastguard Worker   // Returns true if an invocation arrived, or false if a timeout happens.
183*6777b538SAndroid Build Coastguard Worker   //
184*6777b538SAndroid Build Coastguard Worker   // Directly calling Wait() is not required as Take() will also wait for
185*6777b538SAndroid Build Coastguard Worker   // the invocation to arrive, however you can use a direct call to Wait() to
186*6777b538SAndroid Build Coastguard Worker   // improve the error reported:
187*6777b538SAndroid Build Coastguard Worker   //
188*6777b538SAndroid Build Coastguard Worker   //   ASSERT_TRUE(queue.Wait()) << "Detailed error message";
189*6777b538SAndroid Build Coastguard Worker   //
Wait()190*6777b538SAndroid Build Coastguard Worker   [[nodiscard]] bool Wait() { return implementation_.Wait(); }
191*6777b538SAndroid Build Coastguard Worker 
192*6777b538SAndroid Build Coastguard Worker   // Returns a callback that when invoked will unblock any waiters.
GetCallback()193*6777b538SAndroid Build Coastguard Worker   base::RepeatingClosure GetCallback() {
194*6777b538SAndroid Build Coastguard Worker     return base::BindRepeating(implementation_.GetCallback(), true);
195*6777b538SAndroid Build Coastguard Worker   }
196*6777b538SAndroid Build Coastguard Worker 
197*6777b538SAndroid Build Coastguard Worker   // Returns true if no elements are currently present. Note that consuming all
198*6777b538SAndroid Build Coastguard Worker   // elements through Take() will cause this method to return true after the
199*6777b538SAndroid Build Coastguard Worker   // last available element has been consumed.
IsEmpty()200*6777b538SAndroid Build Coastguard Worker   bool IsEmpty() const { return implementation_.IsEmpty(); }
201*6777b538SAndroid Build Coastguard Worker 
202*6777b538SAndroid Build Coastguard Worker   // Waits until the callback or `AddValue()` is invoked.
203*6777b538SAndroid Build Coastguard Worker   //
204*6777b538SAndroid Build Coastguard Worker   // Will DCHECK if a timeout happens.
Take()205*6777b538SAndroid Build Coastguard Worker   void Take() { implementation_.Take(); }
206*6777b538SAndroid Build Coastguard Worker 
207*6777b538SAndroid Build Coastguard Worker  private:
208*6777b538SAndroid Build Coastguard Worker   RepeatingTestFuture<bool> implementation_;
209*6777b538SAndroid Build Coastguard Worker };
210*6777b538SAndroid Build Coastguard Worker 
211*6777b538SAndroid Build Coastguard Worker }  // namespace base::test
212*6777b538SAndroid Build Coastguard Worker 
213*6777b538SAndroid Build Coastguard Worker #endif  // BASE_TEST_REPEATING_TEST_FUTURE_H_
214