xref: /aosp_15_r20/external/federated-compute/fcp/base/future_test.cc (revision 14675a029014e728ec732f129a32e299b2da0601)
1*14675a02SAndroid Build Coastguard Worker /*
2*14675a02SAndroid Build Coastguard Worker  * Copyright 2019 Google LLC
3*14675a02SAndroid Build Coastguard Worker  *
4*14675a02SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*14675a02SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*14675a02SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*14675a02SAndroid Build Coastguard Worker  *
8*14675a02SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*14675a02SAndroid Build Coastguard Worker  *
10*14675a02SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*14675a02SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*14675a02SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*14675a02SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*14675a02SAndroid Build Coastguard Worker  * limitations under the License.
15*14675a02SAndroid Build Coastguard Worker  */
16*14675a02SAndroid Build Coastguard Worker 
17*14675a02SAndroid Build Coastguard Worker #include "fcp/base/future.h"
18*14675a02SAndroid Build Coastguard Worker 
19*14675a02SAndroid Build Coastguard Worker #include <functional>
20*14675a02SAndroid Build Coastguard Worker #include <memory>
21*14675a02SAndroid Build Coastguard Worker #include <thread>  // NOLINT(build/c++11)
22*14675a02SAndroid Build Coastguard Worker #include <type_traits>
23*14675a02SAndroid Build Coastguard Worker #include <utility>
24*14675a02SAndroid Build Coastguard Worker 
25*14675a02SAndroid Build Coastguard Worker #include "gmock/gmock.h"
26*14675a02SAndroid Build Coastguard Worker #include "gtest/gtest.h"
27*14675a02SAndroid Build Coastguard Worker #include "absl/base/thread_annotations.h"
28*14675a02SAndroid Build Coastguard Worker #include "absl/synchronization/barrier.h"
29*14675a02SAndroid Build Coastguard Worker #include "absl/time/time.h"
30*14675a02SAndroid Build Coastguard Worker #include "fcp/base/meta.h"
31*14675a02SAndroid Build Coastguard Worker #include "fcp/base/move_to_lambda.h"
32*14675a02SAndroid Build Coastguard Worker 
33*14675a02SAndroid Build Coastguard Worker namespace fcp {
34*14675a02SAndroid Build Coastguard Worker namespace thread {
35*14675a02SAndroid Build Coastguard Worker 
36*14675a02SAndroid Build Coastguard Worker using ::testing::Eq;
37*14675a02SAndroid Build Coastguard Worker 
38*14675a02SAndroid Build Coastguard Worker // Future::Wait and Future::Take sometimes block. We'd like to test thread
39*14675a02SAndroid Build Coastguard Worker // interleavings where these calls block before being woken up. In the absence
40*14675a02SAndroid Build Coastguard Worker // of instrumentation of the underlying synchronization primitives, we just use
41*14675a02SAndroid Build Coastguard Worker // this arbitrary delay before unblocking operations (the other thread
42*14675a02SAndroid Build Coastguard Worker // "probably" has time to block). Note that the other ordering (Promise::Set
43*14675a02SAndroid Build Coastguard Worker // before Future::Take etc.) is easy to guarantee.
44*14675a02SAndroid Build Coastguard Worker constexpr absl::Duration kArbitraryDelay = absl::Milliseconds(50);
45*14675a02SAndroid Build Coastguard Worker 
Delay()46*14675a02SAndroid Build Coastguard Worker void Delay() { absl::SleepFor(kArbitraryDelay); }
47*14675a02SAndroid Build Coastguard Worker 
48*14675a02SAndroid Build Coastguard Worker // Freely copyable test value. We put in a 'valid' value and hope to find it
49*14675a02SAndroid Build Coastguard Worker // again.
50*14675a02SAndroid Build Coastguard Worker enum class V { kInvalid, kValid };
51*14675a02SAndroid Build Coastguard Worker 
52*14675a02SAndroid Build Coastguard Worker // Move-only test value (we use this for Promise and Future, to make sure they
53*14675a02SAndroid Build Coastguard Worker // are compatible with move-only types - typically the harder case). This
54*14675a02SAndroid Build Coastguard Worker // corresponds to V:
55*14675a02SAndroid Build Coastguard Worker //   Value present (not moved) <=> kValid
56*14675a02SAndroid Build Coastguard Worker //   Value moved <=> kInvalid
57*14675a02SAndroid Build Coastguard Worker // The TakeV / SetV wrappers below actually do those conversions, since the test
58*14675a02SAndroid Build Coastguard Worker // assertions (e.g. Eq matcher) are difficult to use with move-only types.
59*14675a02SAndroid Build Coastguard Worker using UV = UniqueValue<Unit>;
60*14675a02SAndroid Build Coastguard Worker 
61*14675a02SAndroid Build Coastguard Worker static_assert(!std::is_copy_constructible<UV>::value,
62*14675a02SAndroid Build Coastguard Worker               "Expected to be move-only");
63*14675a02SAndroid Build Coastguard Worker 
TakeV(Future<UV> future)64*14675a02SAndroid Build Coastguard Worker std::optional<V> TakeV(Future<UV> future) {
65*14675a02SAndroid Build Coastguard Worker   std::optional<UV> maybe_uv = std::move(future).Take();
66*14675a02SAndroid Build Coastguard Worker   if (maybe_uv.has_value()) {
67*14675a02SAndroid Build Coastguard Worker     UniqueValue<Unit> uv = *std::move(maybe_uv);
68*14675a02SAndroid Build Coastguard Worker     return uv.has_value() ? V::kValid : V::kInvalid;
69*14675a02SAndroid Build Coastguard Worker   } else {
70*14675a02SAndroid Build Coastguard Worker     return std::nullopt;
71*14675a02SAndroid Build Coastguard Worker   }
72*14675a02SAndroid Build Coastguard Worker }
73*14675a02SAndroid Build Coastguard Worker 
SetV(Promise<UV> promise)74*14675a02SAndroid Build Coastguard Worker void SetV(Promise<UV> promise) { std::move(promise).Set(UV(Unit{})); }
75*14675a02SAndroid Build Coastguard Worker 
MakeBarrier()76*14675a02SAndroid Build Coastguard Worker absl::Barrier MakeBarrier() { return absl::Barrier(2); }
77*14675a02SAndroid Build Coastguard Worker 
RunThreads(std::vector<std::function<void ()>> fns)78*14675a02SAndroid Build Coastguard Worker void RunThreads(std::vector<std::function<void()>> fns) {
79*14675a02SAndroid Build Coastguard Worker   std::vector<std::thread> threads;
80*14675a02SAndroid Build Coastguard Worker   for (auto& fn : fns) {
81*14675a02SAndroid Build Coastguard Worker     threads.push_back(std::thread(std::move(fn)));
82*14675a02SAndroid Build Coastguard Worker   }
83*14675a02SAndroid Build Coastguard Worker 
84*14675a02SAndroid Build Coastguard Worker   for (auto& thread : threads) {
85*14675a02SAndroid Build Coastguard Worker     thread.join();
86*14675a02SAndroid Build Coastguard Worker   }
87*14675a02SAndroid Build Coastguard Worker }
88*14675a02SAndroid Build Coastguard Worker 
RunThreadsWithFuture(std::function<void (Promise<UV>)> promise_fn,std::function<void (Future<UV>)> future_fn)89*14675a02SAndroid Build Coastguard Worker void RunThreadsWithFuture(std::function<void(Promise<UV>)> promise_fn,
90*14675a02SAndroid Build Coastguard Worker                           std::function<void(Future<UV>)> future_fn) {
91*14675a02SAndroid Build Coastguard Worker   FuturePair<UV> pair = MakeFuture<UV>();
92*14675a02SAndroid Build Coastguard Worker 
93*14675a02SAndroid Build Coastguard Worker   MoveToLambdaWrapper<Promise<UV>> promise_capture =
94*14675a02SAndroid Build Coastguard Worker       MoveToLambda(std::move(pair.promise));
95*14675a02SAndroid Build Coastguard Worker   auto promise_fn_wrapped = [promise_capture, promise_fn]() mutable {
96*14675a02SAndroid Build Coastguard Worker     promise_fn(std::move(*promise_capture));
97*14675a02SAndroid Build Coastguard Worker   };
98*14675a02SAndroid Build Coastguard Worker 
99*14675a02SAndroid Build Coastguard Worker   MoveToLambdaWrapper<Future<UV>> future_capture =
100*14675a02SAndroid Build Coastguard Worker       MoveToLambda(std::move(pair.future));
101*14675a02SAndroid Build Coastguard Worker   auto future_fn_wrapped = [future_capture, future_fn]() mutable {
102*14675a02SAndroid Build Coastguard Worker     future_fn(std::move(*future_capture));
103*14675a02SAndroid Build Coastguard Worker   };
104*14675a02SAndroid Build Coastguard Worker 
105*14675a02SAndroid Build Coastguard Worker   RunThreads({std::move(promise_fn_wrapped), std::move(future_fn_wrapped)});
106*14675a02SAndroid Build Coastguard Worker }
107*14675a02SAndroid Build Coastguard Worker 
TEST(FutureTest,WaitTimeouts)108*14675a02SAndroid Build Coastguard Worker TEST(FutureTest, WaitTimeouts) {
109*14675a02SAndroid Build Coastguard Worker   absl::Barrier waited = MakeBarrier();
110*14675a02SAndroid Build Coastguard Worker   absl::Barrier set = MakeBarrier();
111*14675a02SAndroid Build Coastguard Worker 
112*14675a02SAndroid Build Coastguard Worker   auto promise_fn = [&](Promise<UV> promise) {
113*14675a02SAndroid Build Coastguard Worker     waited.Block();
114*14675a02SAndroid Build Coastguard Worker     SetV(std::move(promise));
115*14675a02SAndroid Build Coastguard Worker     set.Block();
116*14675a02SAndroid Build Coastguard Worker   };
117*14675a02SAndroid Build Coastguard Worker 
118*14675a02SAndroid Build Coastguard Worker   auto future_fn = [&](Future<UV> future) {
119*14675a02SAndroid Build Coastguard Worker     // Before set: Timeout should elapse
120*14675a02SAndroid Build Coastguard Worker     EXPECT_FALSE(future.Wait(absl::Milliseconds(1)))
121*14675a02SAndroid Build Coastguard Worker         << "Future shouldn't be ready yet";
122*14675a02SAndroid Build Coastguard Worker     waited.Block();
123*14675a02SAndroid Build Coastguard Worker     set.Block();
124*14675a02SAndroid Build Coastguard Worker     // After set: Zero timeout should be sufficient
125*14675a02SAndroid Build Coastguard Worker     EXPECT_TRUE(future.Wait(absl::ZeroDuration()))
126*14675a02SAndroid Build Coastguard Worker         << "Future should be ready without waiting";
127*14675a02SAndroid Build Coastguard Worker   };
128*14675a02SAndroid Build Coastguard Worker 
129*14675a02SAndroid Build Coastguard Worker   RunThreadsWithFuture(std::move(promise_fn), std::move(future_fn));
130*14675a02SAndroid Build Coastguard Worker }
131*14675a02SAndroid Build Coastguard Worker 
TEST(FutureTest,TakeAfterSet)132*14675a02SAndroid Build Coastguard Worker TEST(FutureTest, TakeAfterSet) {
133*14675a02SAndroid Build Coastguard Worker   absl::Barrier set = MakeBarrier();
134*14675a02SAndroid Build Coastguard Worker 
135*14675a02SAndroid Build Coastguard Worker   auto promise_fn = [&](Promise<UV> promise) {
136*14675a02SAndroid Build Coastguard Worker     SetV(std::move(promise));
137*14675a02SAndroid Build Coastguard Worker     set.Block();
138*14675a02SAndroid Build Coastguard Worker   };
139*14675a02SAndroid Build Coastguard Worker 
140*14675a02SAndroid Build Coastguard Worker   auto future_fn = [&](Future<UV> future) {
141*14675a02SAndroid Build Coastguard Worker     set.Block();
142*14675a02SAndroid Build Coastguard Worker     EXPECT_THAT(TakeV(std::move(future)), Eq(V::kValid));
143*14675a02SAndroid Build Coastguard Worker   };
144*14675a02SAndroid Build Coastguard Worker 
145*14675a02SAndroid Build Coastguard Worker   RunThreadsWithFuture(std::move(promise_fn), std::move(future_fn));
146*14675a02SAndroid Build Coastguard Worker }
147*14675a02SAndroid Build Coastguard Worker 
TEST(FutureTest,TakeProbablyBeforeSet)148*14675a02SAndroid Build Coastguard Worker TEST(FutureTest, TakeProbablyBeforeSet) {
149*14675a02SAndroid Build Coastguard Worker   auto promise_fn = [](Promise<UV> promise) {
150*14675a02SAndroid Build Coastguard Worker     Delay();
151*14675a02SAndroid Build Coastguard Worker     SetV(std::move(promise));
152*14675a02SAndroid Build Coastguard Worker   };
153*14675a02SAndroid Build Coastguard Worker 
154*14675a02SAndroid Build Coastguard Worker   auto future_fn = [](Future<UV> future) {
155*14675a02SAndroid Build Coastguard Worker     EXPECT_THAT(TakeV(std::move(future)), Eq(V::kValid));
156*14675a02SAndroid Build Coastguard Worker   };
157*14675a02SAndroid Build Coastguard Worker 
158*14675a02SAndroid Build Coastguard Worker   RunThreadsWithFuture(std::move(promise_fn), std::move(future_fn));
159*14675a02SAndroid Build Coastguard Worker }
160*14675a02SAndroid Build Coastguard Worker 
TEST(FutureTest,AbandonWhileProbablyTaking)161*14675a02SAndroid Build Coastguard Worker TEST(FutureTest, AbandonWhileProbablyTaking) {
162*14675a02SAndroid Build Coastguard Worker   auto promise_fn = [](Promise<UV> promise) {
163*14675a02SAndroid Build Coastguard Worker     Delay();
164*14675a02SAndroid Build Coastguard Worker     { Promise<UV> dies = std::move(promise); }
165*14675a02SAndroid Build Coastguard Worker   };
166*14675a02SAndroid Build Coastguard Worker 
167*14675a02SAndroid Build Coastguard Worker   auto future_fn = [](Future<UV> future) {
168*14675a02SAndroid Build Coastguard Worker     EXPECT_THAT(std::move(future).Take(), Eq(std::nullopt));
169*14675a02SAndroid Build Coastguard Worker   };
170*14675a02SAndroid Build Coastguard Worker 
171*14675a02SAndroid Build Coastguard Worker   RunThreadsWithFuture(std::move(promise_fn), std::move(future_fn));
172*14675a02SAndroid Build Coastguard Worker }
173*14675a02SAndroid Build Coastguard Worker 
TEST(FutureTest,SetWhileProbablyWaiting)174*14675a02SAndroid Build Coastguard Worker TEST(FutureTest, SetWhileProbablyWaiting) {
175*14675a02SAndroid Build Coastguard Worker   auto promise_fn = [](Promise<UV> promise) {
176*14675a02SAndroid Build Coastguard Worker     Delay();
177*14675a02SAndroid Build Coastguard Worker     SetV(std::move(promise));
178*14675a02SAndroid Build Coastguard Worker   };
179*14675a02SAndroid Build Coastguard Worker 
180*14675a02SAndroid Build Coastguard Worker   auto future_fn = [](Future<UV> future) {
181*14675a02SAndroid Build Coastguard Worker     EXPECT_TRUE(future.Wait(absl::InfiniteDuration()));
182*14675a02SAndroid Build Coastguard Worker   };
183*14675a02SAndroid Build Coastguard Worker 
184*14675a02SAndroid Build Coastguard Worker   RunThreadsWithFuture(std::move(promise_fn), std::move(future_fn));
185*14675a02SAndroid Build Coastguard Worker }
186*14675a02SAndroid Build Coastguard Worker 
TEST(FutureTest,AbandonWhileProbablyWaiting)187*14675a02SAndroid Build Coastguard Worker TEST(FutureTest, AbandonWhileProbablyWaiting) {
188*14675a02SAndroid Build Coastguard Worker   auto promise_fn = [](Promise<UV> promise) {
189*14675a02SAndroid Build Coastguard Worker     Delay();
190*14675a02SAndroid Build Coastguard Worker     { Promise<UV> dies = std::move(promise); }
191*14675a02SAndroid Build Coastguard Worker   };
192*14675a02SAndroid Build Coastguard Worker 
193*14675a02SAndroid Build Coastguard Worker   auto future_fn = [](Future<UV> future) {
194*14675a02SAndroid Build Coastguard Worker     EXPECT_TRUE(future.Wait(absl::InfiniteDuration()));
195*14675a02SAndroid Build Coastguard Worker   };
196*14675a02SAndroid Build Coastguard Worker 
197*14675a02SAndroid Build Coastguard Worker   RunThreadsWithFuture(std::move(promise_fn), std::move(future_fn));
198*14675a02SAndroid Build Coastguard Worker }
199*14675a02SAndroid Build Coastguard Worker 
200*14675a02SAndroid Build Coastguard Worker }  // namespace thread
201*14675a02SAndroid Build Coastguard Worker }  // namespace fcp
202