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