xref: /aosp_15_r20/external/cronet/base/test/test_future.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_TEST_TEST_FUTURE_H_
6 #define BASE_TEST_TEST_FUTURE_H_
7 
8 #include <memory>
9 #include <optional>
10 #include <tuple>
11 
12 #include "base/auto_reset.h"
13 #include "base/check.h"
14 #include "base/functional/bind.h"
15 #include "base/functional/callback_forward.h"
16 #include "base/functional/callback_helpers.h"
17 #include "base/memory/weak_ptr.h"
18 #include "base/run_loop.h"
19 #include "base/sequence_checker.h"
20 #include "base/strings/to_string.h"
21 #include "base/task/bind_post_task.h"
22 #include "base/task/sequenced_task_runner.h"
23 #include "base/test/test_future_internal.h"
24 #include "base/thread_annotations.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 
27 namespace base::test {
28 
29 // Helper class to test code that returns its result(s) asynchronously through a
30 // callback:
31 //
32 //    - Pass the callback provided by `GetCallback()` to the code under test.
33 //    - Wait for the callback to be invoked by calling `Wait(),` or `Get()` to
34 //      access the value(s) passed to the callback.
35 //
36 //   Example usage:
37 //
38 //     TEST_F(MyTestFixture, MyTest) {
39 //       TestFuture<ResultType> future;
40 //
41 //       object_under_test.DoSomethingAsync(future.GetCallback());
42 //
43 //       const ResultType& actual_result = future.Get();
44 //
45 //       // When you come here, DoSomethingAsync has finished and
46 //       // `actual_result` contains the result passed to the callback.
47 //     }
48 //
49 //   Example using `Wait()`:
50 //
51 //     TEST_F(MyTestFixture, MyWaitTest) {
52 //       TestFuture<ResultType> future;
53 //
54 //       object_under_test.DoSomethingAsync(future.GetCallback());
55 //
56 //       // Optional. The Get() call below will also wait until the value
57 //       // arrives, but this explicit call to Wait() can be useful if you want
58 //       // to add extra information.
59 //       ASSERT_TRUE(future.Wait()) << "Detailed error message";
60 //
61 //       const ResultType& actual_result = future.Get();
62 //     }
63 //
64 // `TestFuture` supports both single- and multiple-argument callbacks.
65 // `TestFuture` provides both index and type based accessors for multi-argument
66 // callbacks. `Get()` and `Take()` return tuples for multi-argument callbacks.
67 //
68 //   TestFuture<int, std::string> future;
69 //   future.Get<0>();   // Reads the first argument
70 //   future.Get<int>(); // Also reads the first argument
71 //   future.Get();      // Returns a `const std::tuple<int, std::string>&`
72 //
73 //   Example for a multi-argument callback:
74 //
75 //     TEST_F(MyTestFixture, MyTest) {
76 //       TestFuture<int, std::string> future;
77 //
78 //       object_under_test.DoSomethingAsync(future.GetCallback());
79 //
80 //       // You can use type based accessors:
81 //       int first_argument = future.Get<int>();
82 //       const std::string& second_argument = future.Get<std::string>();
83 //
84 //       // or index based accessors:
85 //       int first_argument = future.Get<0>();
86 //       const std::string& second_argument = future.Get<1>();
87 //     }
88 //
89 // You can also satisfy a `TestFuture` by calling `SetValue()` from the sequence
90 // on which the `TestFuture` was created. This is mostly useful when
91 // implementing an observer:
92 //
93 //     class MyTestObserver: public MyObserver {
94 //       public:
95 //         // `MyObserver` implementation:
96 //         void ObserveAnInt(int value) override {
97 //           future_.SetValue(value);
98 //         }
99 //
100 //         int Wait() { return future_.Take(); }
101 //
102 //      private:
103 //        TestFuture<int> future_;
104 //     };
105 //
106 //     TEST_F(MyTestFixture, MyTest) {
107 //       MyTestObserver observer;
108 //
109 //       object_under_test.DoSomethingAsync(observer);
110 //
111 //       int value_passed_to_observer = observer.Wait();
112 //     };
113 //
114 // `GetRepeatingCallback()` allows you to use a single `TestFuture` in code
115 // that invokes the callback multiple times.
116 // Your test must take care to consume each value before the next value
117 // arrives. You can consume the value by calling either `Take()` or `Clear()`.
118 //
119 //   Example for reusing a `TestFuture`:
120 //
121 //     TEST_F(MyTestFixture, MyReuseTest) {
122 //       TestFuture<std::string> future;
123 //
124 //       object_under_test.InstallCallback(future.GetRepeatingCallback());
125 //
126 //       object_under_test.DoSomething();
127 //       EXPECT_EQ(future.Take(), "expected-first-value");
128 //       // Because we used `Take()` the test future is ready for reuse.
129 //
130 //       object_under_test.DoSomethingElse();
131 //       EXPECT_EQ(future.Take(), "expected-second-value");
132 //     }
133 //
134 //   Example for reusing  a `TestFuture` using `Get()` + `Clear()`:
135 //
136 //     TEST_F(MyTestFixture, MyReuseTest) {
137 //       TestFuture<std::string, int> future;
138 //
139 //       object_under_test.InstallCallback(future.GetRepeatingCallback());
140 //
141 //       object_under_test.DoSomething();
142 //
143 //       EXPECT_EQ(future.Get<std::string>(), "expected-first-value");
144 //       EXPECT_EQ(future.Get<int>(), 5);
145 //       // Because we used `Get()`, the test future is not ready for reuse,
146 //       //so we need an explicit `Clear()` call.
147 //       future.Clear();
148 //
149 //       object_under_test.DoSomethingElse();
150 //       EXPECT_EQ(future.Get<std::string>(), "expected-second-value");
151 //       EXPECT_EQ(future.Get<int>(), 2);
152 //     }
153 //
154 // Finally, `TestFuture` also supports no-args callbacks:
155 //
156 //   Example for no-args callbacks:
157 //
158 //     TEST_F(MyTestFixture, MyTest) {
159 //       TestFuture<void> signal;
160 //
161 //       object_under_test.DoSomethingAsync(signal.GetCallback());
162 //
163 //       EXPECT_TRUE(signal.Wait());
164 //       // When you come here you know the callback was invoked and the async
165 //       // code is ready.
166 //     }
167 //
168 // All access to this class and its callbacks must be made from the sequence on
169 // which the `TestFuture` was constructed.
170 //
171 template <typename... Types>
172 class TestFuture {
173  public:
174   using TupleType = std::tuple<std::decay_t<Types>...>;
175 
176   static_assert(std::tuple_size_v<TupleType> > 0,
177                 "Don't use TestFuture<> but use TestFuture<void> instead");
178 
179   TestFuture() = default;
180   TestFuture(const TestFuture&) = delete;
181   TestFuture& operator=(const TestFuture&) = delete;
182   ~TestFuture() = default;
183 
184   // Waits for the value to arrive.
185   //
186   // Returns true if the value arrived, or false if a timeout happens.
187   //
188   // Directly calling Wait() is not required as Get()/Take() will also wait for
189   // the value to arrive, however you can use a direct call to Wait() to
190   // improve the error reported:
191   //
192   //   ASSERT_TRUE(queue.Wait()) << "Detailed error message";
193   //
Wait()194   [[nodiscard]] bool Wait() {
195     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
196 
197     if (values_) {
198       return true;
199     }
200 
201     // Wait for the value to arrive.
202     RunLoop loop;
203     AutoReset<RepeatingClosure> quit_loop(&ready_signal_, loop.QuitClosure());
204     loop.Run();
205 
206     return IsReady();
207   }
208 
209   // Returns true if the value has arrived.
IsReady()210   bool IsReady() const {
211     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
212     return values_.has_value();
213   }
214 
215   // Waits for the value to arrive, and returns the I-th value.
216   //
217   // Will CHECK if a timeout happens.
218   //
219   // Example usage:
220   //
221   //   TestFuture<int, std::string> future;
222   //   int first = future.Get<0>();
223   //   std::string second = future.Get<1>();
224   //
225   template <std::size_t I,
226             typename T = TupleType,
227             internal::EnableIfOneOrMoreValues<T> = true>
Get()228   const auto& Get() {
229     return std::get<I>(GetTuple());
230   }
231 
232   // Waits for the value to arrive, and returns the value with the given type.
233   //
234   // Will CHECK if a timeout happens.
235   //
236   // Example usage:
237   //
238   //   TestFuture<int, std::string> future;
239   //   int first = future.Get<int>();
240   //   std::string second = future.Get<std::string>();
241   //
242   template <typename Type>
Get()243   const auto& Get() {
244     return std::get<Type>(GetTuple());
245   }
246 
247   // Returns a callback that when invoked will store all the argument values,
248   // and unblock any waiters. The callback must be invoked on the sequence the
249   // TestFuture was created on.
250   //
251   // Templated so you can specify how you need the arguments to be passed -
252   // const, reference, .... Defaults to simply `Types...`.
253   //
254   // Example usage:
255   //
256   //   TestFuture<int, std::string> future;
257   //
258   //   // Without specifying the callback argument types, this returns
259   //   // base::OnceCallback<void(int, std::string)>.
260   //   future.GetCallback();
261   //
262   //   // By explicitly specifying the callback argument types, this returns
263   //   // base::OnceCallback<void(int, const std::string&)>.
264   //   future.GetCallback<int, const std::string&>();
265   //
266   template <typename... CallbackArgumentsTypes>
GetCallback()267   OnceCallback<void(CallbackArgumentsTypes...)> GetCallback() {
268     return GetRepeatingCallback<CallbackArgumentsTypes...>();
269   }
270 
GetCallback()271   OnceCallback<void(Types...)> GetCallback() { return GetCallback<Types...>(); }
272 
273   // Returns a repeating callback that when invoked will store all the argument
274   // values, and unblock any waiters. The callback must be invoked on the
275   // sequence the TestFuture was created on.
276   //
277   // You must take care that the stored value is consumed before the callback
278   // is invoked a second time. You can consume the value by calling either
279   // `Take()` or `Clear()`.
280   //
281   // Example usage:
282   //
283   //   TestFuture<std::string> future;
284   //
285   //   object_under_test.InstallCallback(future.GetRepeatingCallback());
286   //
287   //   object_under_test.DoSomething();
288   //   EXPECT_EQ(future.Take(), "expected-first-value");
289   //   // Because we used `Take()` the test future is ready for reuse.
290   //
291   //   object_under_test.DoSomethingElse();
292   //   // We can also use `Get()` + `Clear()` to reuse the callback.
293   //   EXPECT_EQ(future.Get(), "expected-second-value");
294   //   future.Clear();
295   //
296   //   object_under_test.DoSomethingElse();
297   //   EXPECT_EQ(future.Take(), "expected-third-value");
298   //
299   template <typename... CallbackArgumentsTypes>
GetRepeatingCallback()300   RepeatingCallback<void(CallbackArgumentsTypes...)> GetRepeatingCallback() {
301     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
302     return BindRepeating(
303         [](WeakPtr<TestFuture<Types...>> future,
304            CallbackArgumentsTypes... values) {
305           if (future) {
306             future->SetValue(std::forward<CallbackArgumentsTypes>(values)...);
307           }
308         },
309         weak_ptr_factory_.GetWeakPtr());
310   }
311 
GetRepeatingCallback()312   RepeatingCallback<void(Types...)> GetRepeatingCallback() {
313     return GetRepeatingCallback<Types...>();
314   }
315 
316   // Returns a callback that can be invoked on any sequence. When invoked it
317   // will post a task to the sequence the TestFuture was created on, to store
318   // all the argument values, and unblock any waiters.
319   //
320   // Templated so you can specify how you need the arguments to be passed -
321   // const, reference, .... Defaults to simply `Types...`.
322   //
323   // Example usage:
324   //
325   //   TestFuture<int, std::string> future;
326   //
327   //   // Without specifying the callback argument types, this returns
328   //   // base::OnceCallback<void(int, std::string)>.
329   //   auto callback = future.GetSequenceBoundCallback();
330   //
331   //   // By explicitly specifying the callback argument types, this returns
332   //   // base::OnceCallback<void(int, const std::string&)>.
333   //   auto callback =
334   //       future.GetSequenceBoundCallback<int, const std::string&>();
335   //
336   //   // AsyncOperation invokes `callback` with a result.
337   //   other_task_runner->PostTask(FROM_HERE, base::BindOnce(&AsyncOperation,
338   //                                              std::move(callback));
339   //
340   //   future.Wait();
341   //
342   template <typename... CallbackArgumentsTypes>
GetSequenceBoundCallback()343   OnceCallback<void(CallbackArgumentsTypes...)> GetSequenceBoundCallback() {
344     return GetSequenceBoundRepeatingCallback<CallbackArgumentsTypes...>();
345   }
346 
GetSequenceBoundCallback()347   OnceCallback<void(Types...)> GetSequenceBoundCallback() {
348     return GetSequenceBoundCallback<Types...>();
349   }
350 
351   // Returns a repeating callback that can be invoked on any sequence. When
352   // invoked it will post a task to the sequence the TestFuture was created on,
353   // to store all the argument values, and unblock any waiters.
354   //
355   // You must take care that the stored value is consumed before the callback
356   // is invoked a second time. You can consume the value by calling either
357   // `Take()` or `Clear()`.
358   //
359   // Example usage:
360   //
361   //   base::SequenceBound<Object> object_under_test(other_task_runner);
362   //   TestFuture<std::string> future;
363   //
364   //   object_under_test.AsyncCall(&Object::InstallCallback,
365   //                               future.GetSequenceBoundRepeatingCallback());
366   //
367   //   object_under_test.AsyncCall(&DoSomething);
368   //   EXPECT_EQ(future.Take(), "expected-first-value");
369   //   // Because we used `Take()` the test future is ready for reuse.
370   //
371   //   object_under_test.AsyncCall(&DoSomethingElse);
372   //   // We can also use `Get()` + `Clear()` to reuse the callback.
373   //   EXPECT_EQ(future.Get(), "expected-second-value");
374   //   future.Clear();
375   //
376   //   object_under_test.AsyncCall(&DoSomethingElse);
377   //   EXPECT_EQ(future.Take(), "expected-third-value");
378   //
379   template <typename... CallbackArgumentsTypes>
380   RepeatingCallback<void(CallbackArgumentsTypes...)>
GetSequenceBoundRepeatingCallback()381   GetSequenceBoundRepeatingCallback() {
382     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
383     return BindPostTask(base::SequencedTaskRunner::GetCurrentDefault(),
384                         GetRepeatingCallback<CallbackArgumentsTypes...>());
385   }
386 
GetSequenceBoundRepeatingCallback()387   RepeatingCallback<void(Types...)> GetSequenceBoundRepeatingCallback() {
388     return GetSequenceBoundRepeatingCallback<Types...>();
389   }
390 
391   // Sets the value of the future.
392   // This will unblock any pending Wait() or Get() call.
SetValue(Types...values)393   void SetValue(Types... values) {
394     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
395 
396     auto new_values = std::make_tuple(std::forward<Types>(values)...);
397 
398     EXPECT_FALSE(values_.has_value())
399         << "Received new value " << ToString(new_values)  //
400         << " before old value " << ToString(GetTuple())
401         << " was consumed through Take() or Clear().";
402 
403     values_ = std::move(new_values);
404 
405     ready_signal_.Run();
406   }
407 
408   // Clears the future, allowing it to be reused and accept a new value.
409   //
410   // All outstanding callbacks issued through `GetCallback()` remain valid.
Clear()411   void Clear() {
412     if (IsReady()) {
413       std::ignore = Take();
414     }
415   }
416 
417   //////////////////////////////////////////////////////////////////////////////
418   //  Accessor methods only available if the future holds a single value.
419   //////////////////////////////////////////////////////////////////////////////
420 
421   // Waits for the value to arrive, and returns a reference to it.
422   //
423   // Will CHECK if a timeout happens.
424   template <typename T = TupleType, internal::EnableIfSingleValue<T> = true>
Get()425   [[nodiscard]] const auto& Get() {
426     return std::get<0>(GetTuple());
427   }
428 
429   // Waits for the value to arrive, and returns it.
430   //
431   // Will CHECK if a timeout happens.
432   template <typename T = TupleType, internal::EnableIfSingleValue<T> = true>
Take()433   [[nodiscard]] auto Take() {
434     return std::get<0>(TakeTuple());
435   }
436 
437   //////////////////////////////////////////////////////////////////////////////
438   //  Accessor methods only available if the future holds multiple values.
439   //////////////////////////////////////////////////////////////////////////////
440 
441   // Waits for the values to arrive, and returns a tuple with the values.
442   //
443   // Will CHECK if a timeout happens.
444   template <typename T = TupleType, internal::EnableIfMultiValue<T> = true>
Get()445   [[nodiscard]] const TupleType& Get() {
446     return GetTuple();
447   }
448 
449   // Waits for the values to arrive, and moves a tuple with the values out.
450   //
451   // Will CHECK if a timeout happens.
452   template <typename T = TupleType, internal::EnableIfMultiValue<T> = true>
Take()453   [[nodiscard]] TupleType Take() {
454     return TakeTuple();
455   }
456 
457  private:
GetTuple()458   [[nodiscard]] const TupleType& GetTuple() {
459     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
460     bool success = Wait();
461     CHECK(success) << "Waiting for value timed out.";
462     return values_.value();
463   }
464 
TakeTuple()465   [[nodiscard]] TupleType TakeTuple() {
466     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
467     bool success = Wait();
468     CHECK(success) << "Waiting for value timed out.";
469 
470     return std::exchange(values_, {}).value();
471   }
472 
473   SEQUENCE_CHECKER(sequence_checker_);
474 
475   base::RepeatingClosure ready_signal_ GUARDED_BY_CONTEXT(sequence_checker_) =
476       base::DoNothing();
477 
478   std::optional<TupleType> values_ GUARDED_BY_CONTEXT(sequence_checker_);
479 
480   WeakPtrFactory<TestFuture<Types...>> weak_ptr_factory_{this};
481 };
482 
483 // Specialization so you can use `TestFuture` to wait for a no-args callback.
484 //
485 // This specialization offers a subset of the methods provided on the base
486 // `TestFuture`, as there is no value to be returned.
487 template <>
488 class TestFuture<void> {
489  public:
490   // Waits until the callback or `SetValue()` is invoked.
491   //
492   // Fails your test if a timeout happens, but you can check the return value
493   // to improve the error reported:
494   //
495   //   ASSERT_TRUE(future.Wait()) << "Detailed error message";
Wait()496   [[nodiscard]] bool Wait() { return implementation_.Wait(); }
497 
498   // Same as above, then clears the future, allowing it to be reused and accept
499   // a new value.
WaitAndClear()500   [[nodiscard]] bool WaitAndClear() {
501     auto result = Wait();
502     Clear();
503     return result;
504   }
505 
506   // Waits until the callback or `SetValue()` is invoked.
Get()507   void Get() { std::ignore = implementation_.Get(); }
508 
509   // Returns true if the callback or `SetValue()` was invoked.
IsReady()510   bool IsReady() const { return implementation_.IsReady(); }
511 
512   // Returns a callback that when invoked will unblock any waiters.
GetCallback()513   OnceClosure GetCallback() {
514     return BindOnce(implementation_.GetCallback(), true);
515   }
516 
517   // Returns a callback that when invoked will unblock any waiters.
GetRepeatingCallback()518   RepeatingClosure GetRepeatingCallback() {
519     return BindRepeating(implementation_.GetRepeatingCallback(), true);
520   }
521 
522   // Returns a callback that when invoked on any sequence will unblock any
523   // waiters.
GetSequenceBoundCallback()524   OnceClosure GetSequenceBoundCallback() {
525     return BindOnce(implementation_.GetSequenceBoundCallback(), true);
526   }
527 
528   // Returns a callback that when invoked on any sequence will unblock any
529   // waiters.
GetSequenceBoundRepeatingCallback()530   RepeatingClosure GetSequenceBoundRepeatingCallback() {
531     return BindRepeating(implementation_.GetSequenceBoundRepeatingCallback(),
532                          true);
533   }
534 
535   // Indicates this `TestFuture` is ready, and unblocks any waiters.
SetValue()536   void SetValue() { implementation_.SetValue(true); }
537 
538   // Clears the future, allowing it to be reused and accept a new value.
539   //
540   // All outstanding callbacks issued through `GetCallback()` remain valid.
Clear()541   void Clear() { implementation_.Clear(); }
542 
543  private:
544   TestFuture<bool> implementation_;
545 };
546 
547 }  // namespace base::test
548 
549 #endif  // BASE_TEST_TEST_FUTURE_H_
550