1 | /* |
2 | * Copyright 2015-present Facebook, Inc. |
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 <queue> |
18 | |
19 | #include <folly/executors/InlineExecutor.h> |
20 | #include <folly/futures/Future.h> |
21 | #include <folly/io/async/EventBase.h> |
22 | #include <folly/portability/GTest.h> |
23 | #include <folly/synchronization/Baton.h> |
24 | |
25 | using namespace folly; |
26 | using std::vector; |
27 | using std::chrono::milliseconds; |
28 | |
29 | TEST(Wait, waitImmediate) { |
30 | makeFuture().wait(); |
31 | auto done = makeFuture(42).wait().value(); |
32 | EXPECT_EQ(42, done); |
33 | |
34 | vector<int> v{1, 2, 3}; |
35 | auto done_v = makeFuture(v).wait().value(); |
36 | EXPECT_EQ(v.size(), done_v.size()); |
37 | EXPECT_EQ(v, done_v); |
38 | |
39 | vector<Future<Unit>> v_f; |
40 | v_f.push_back(makeFuture()); |
41 | v_f.push_back(makeFuture()); |
42 | auto done_v_f = collectAllSemiFuture(v_f).toUnsafeFuture().wait().value(); |
43 | EXPECT_EQ(2, done_v_f.size()); |
44 | |
45 | vector<Future<bool>> v_fb; |
46 | v_fb.push_back(makeFuture(true)); |
47 | v_fb.push_back(makeFuture(false)); |
48 | auto fut = collectAll(v_fb); |
49 | auto done_v_fb = std::move(fut.wait().value()); |
50 | EXPECT_EQ(2, done_v_fb.size()); |
51 | } |
52 | |
53 | TEST(Wait, wait) { |
54 | Promise<int> p; |
55 | Future<int> f = p.getFuture(); |
56 | std::atomic<bool> flag{false}; |
57 | std::atomic<int> result{1}; |
58 | std::atomic<std::thread::id> id; |
59 | |
60 | std::thread th( |
61 | [&](Future<int>&& tf) { |
62 | auto n = std::move(tf).thenTry([&](Try<int>&& t) { |
63 | id = std::this_thread::get_id(); |
64 | return t.value(); |
65 | }); |
66 | flag = true; |
67 | result.store(n.wait().value()); |
68 | }, |
69 | std::move(f)); |
70 | while (!flag) { |
71 | } |
72 | EXPECT_EQ(result.load(), 1); |
73 | p.setValue(42); |
74 | th.join(); |
75 | // validate that the callback ended up executing in this thread, which |
76 | // is more to ensure that this test actually tests what it should |
77 | EXPECT_EQ(id, std::this_thread::get_id()); |
78 | EXPECT_EQ(result.load(), 42); |
79 | } |
80 | |
81 | struct MoveFlag { |
82 | MoveFlag() = default; |
83 | MoveFlag& operator=(const MoveFlag&) = delete; |
84 | MoveFlag(const MoveFlag&) = delete; |
85 | MoveFlag(MoveFlag&& other) noexcept { |
86 | other.moved = true; |
87 | } |
88 | bool moved{false}; |
89 | }; |
90 | |
91 | TEST(Wait, waitReplacesSelf) { |
92 | // wait |
93 | { |
94 | // lvalue |
95 | auto f1 = makeFuture(MoveFlag()); |
96 | f1.wait(); |
97 | EXPECT_FALSE(f1.value().moved); |
98 | |
99 | // rvalue |
100 | auto f2 = makeFuture(MoveFlag()).wait(); |
101 | EXPECT_FALSE(f2.value().moved); |
102 | } |
103 | |
104 | // wait(Duration) |
105 | { |
106 | // lvalue |
107 | auto f1 = makeFuture(MoveFlag()); |
108 | f1.wait(milliseconds(1)); |
109 | EXPECT_FALSE(f1.value().moved); |
110 | |
111 | // rvalue |
112 | auto f2 = makeFuture(MoveFlag()).wait(milliseconds(1)); |
113 | EXPECT_FALSE(f2.value().moved); |
114 | } |
115 | |
116 | // waitVia |
117 | { |
118 | folly::EventBase eb; |
119 | // lvalue |
120 | auto f1 = makeFuture(MoveFlag()); |
121 | f1.waitVia(&eb); |
122 | EXPECT_FALSE(f1.value().moved); |
123 | |
124 | // rvalue |
125 | auto f2 = makeFuture(MoveFlag()).waitVia(&eb); |
126 | EXPECT_FALSE(f2.value().moved); |
127 | } |
128 | } |
129 | |
130 | TEST(Wait, waitWithDuration) { |
131 | { |
132 | Promise<int> p; |
133 | Future<int> f = p.getFuture(); |
134 | f.wait(milliseconds(1)); |
135 | EXPECT_FALSE(f.isReady()); |
136 | p.setValue(1); |
137 | EXPECT_TRUE(f.isReady()); |
138 | } |
139 | { |
140 | Promise<int> p; |
141 | Future<int> f = p.getFuture(); |
142 | p.setValue(1); |
143 | f.wait(milliseconds(1)); |
144 | EXPECT_TRUE(f.isReady()); |
145 | } |
146 | { |
147 | vector<Future<bool>> v_fb; |
148 | v_fb.push_back(makeFuture(true)); |
149 | v_fb.push_back(makeFuture(false)); |
150 | auto f = collectAll(v_fb); |
151 | f.wait(milliseconds(1)); |
152 | EXPECT_TRUE(f.isReady()); |
153 | EXPECT_EQ(2, f.value().size()); |
154 | } |
155 | { |
156 | vector<Future<bool>> v_fb; |
157 | Promise<bool> p1; |
158 | Promise<bool> p2; |
159 | v_fb.push_back(p1.getFuture()); |
160 | v_fb.push_back(p2.getFuture()); |
161 | auto f = collectAll(v_fb); |
162 | f.wait(milliseconds(1)); |
163 | EXPECT_FALSE(f.isReady()); |
164 | p1.setValue(true); |
165 | EXPECT_FALSE(f.isReady()); |
166 | p2.setValue(true); |
167 | EXPECT_TRUE(f.isReady()); |
168 | } |
169 | { |
170 | auto f = makeFuture().wait(milliseconds(1)); |
171 | EXPECT_TRUE(f.isReady()); |
172 | } |
173 | |
174 | { |
175 | Promise<Unit> p; |
176 | auto start = std::chrono::steady_clock::now(); |
177 | auto f = p.getFuture().wait(milliseconds(100)); |
178 | auto elapsed = std::chrono::steady_clock::now() - start; |
179 | EXPECT_GE(elapsed, milliseconds(100)); |
180 | EXPECT_FALSE(f.isReady()); |
181 | p.setValue(); |
182 | EXPECT_TRUE(f.isReady()); |
183 | } |
184 | |
185 | { |
186 | // Try to trigger the race where the resultant Future is not yet complete |
187 | // even if we didn't hit the timeout, and make sure we deal with it properly |
188 | Promise<Unit> p; |
189 | folly::Baton<> b; |
190 | auto t = std::thread([&] { |
191 | b.post(); |
192 | /* sleep override */ std::this_thread::sleep_for(milliseconds(100)); |
193 | p.setValue(); |
194 | }); |
195 | b.wait(); |
196 | auto f = p.getFuture().wait(std::chrono::seconds(3600)); |
197 | EXPECT_TRUE(f.isReady()); |
198 | t.join(); |
199 | } |
200 | |
201 | { |
202 | // `Future::wait(Duration) &` when promise is fulfilled during the wait |
203 | Promise<int> p; |
204 | |
205 | auto f = p.getFuture(); |
206 | EXPECT_FALSE(f.isReady()); |
207 | |
208 | folly::Baton<> b; |
209 | auto t = std::thread([&] { |
210 | b.post(); |
211 | /* sleep override */ std::this_thread::sleep_for(milliseconds(100)); |
212 | p.setValue(42); |
213 | }); |
214 | b.wait(); |
215 | |
216 | f.wait(std::chrono::seconds(10)); |
217 | EXPECT_TRUE(f.valid()); |
218 | EXPECT_TRUE(f.isReady()); |
219 | EXPECT_EQ(f.value(), 42); |
220 | |
221 | t.join(); |
222 | EXPECT_TRUE(f.isReady()); |
223 | EXPECT_EQ(f.value(), 42); |
224 | } |
225 | |
226 | { |
227 | // `Future::wait(Duration) &&` when promise is fulfilled during the wait |
228 | Promise<int> p; |
229 | |
230 | auto f1 = p.getFuture(); |
231 | EXPECT_FALSE(f1.isReady()); |
232 | |
233 | folly::Baton<> b; |
234 | auto t = std::thread([&] { |
235 | b.post(); |
236 | /* sleep override */ std::this_thread::sleep_for(milliseconds(100)); |
237 | p.setValue(42); |
238 | }); |
239 | b.wait(); |
240 | |
241 | auto f2 = std::move(f1).wait(std::chrono::seconds(10)); |
242 | EXPECT_FALSE(f1.valid()); |
243 | EXPECT_TRUE(f2.valid()); |
244 | EXPECT_TRUE(f2.isReady()); |
245 | EXPECT_EQ(f2.value(), 42); |
246 | |
247 | t.join(); |
248 | EXPECT_TRUE(f2.valid()); |
249 | EXPECT_TRUE(f2.isReady()); |
250 | EXPECT_EQ(f2.value(), 42); |
251 | } |
252 | |
253 | { |
254 | // `SemiFuture::get(Duration) &&` when promise is fulfilled during the get |
255 | Promise<int> p; |
256 | |
257 | auto f = p.getSemiFuture(); |
258 | EXPECT_FALSE(f.isReady()); |
259 | |
260 | folly::Baton<> b; |
261 | auto t = std::thread([&] { |
262 | b.post(); |
263 | /* sleep override */ std::this_thread::sleep_for(milliseconds(100)); |
264 | p.setValue(42); |
265 | }); |
266 | b.wait(); |
267 | |
268 | EXPECT_EQ(std::move(f).get(std::chrono::seconds(10)), 42); |
269 | |
270 | t.join(); |
271 | } |
272 | } |
273 | |
274 | TEST(Wait, multipleWait) { |
275 | auto f = futures::sleep(milliseconds(100)); |
276 | for (size_t i = 0; i < 5; ++i) { |
277 | EXPECT_FALSE(f.isReady()); |
278 | f.wait(milliseconds(3)); |
279 | } |
280 | EXPECT_FALSE(f.isReady()); |
281 | f.wait(); |
282 | EXPECT_TRUE(f.isReady()); |
283 | f.wait(); |
284 | EXPECT_TRUE(f.isReady()); |
285 | } |
286 | |
287 | TEST(Wait, WaitPlusThen) { |
288 | // Validate expected behavior of `f.wait(...).then([](auto&){...})`. |
289 | // There are 10 sub-cases: |
290 | // - Future fulfilled {prior to, during} call to wait(). |
291 | // - Future fulfilled {prior to, during, after} call to wait(dur). |
292 | // - then repeat those 5 cases for SemiFuture |
293 | |
294 | { |
295 | // Sub-case: Future fulfilled before `wait()` is called. |
296 | // Expect call to `.then()` to succeed & continuation to run immediately. |
297 | Promise<int> p; |
298 | auto f = p.getFuture(); |
299 | p.setValue(42); |
300 | EXPECT_TRUE(f.isReady()); |
301 | EXPECT_EQ(f.value(), 42); |
302 | f.wait(); |
303 | auto continuation = 0; |
304 | EXPECT_NO_THROW( |
305 | std::move(f).thenValue([&](auto&& v) { continuation = v; })); |
306 | EXPECT_EQ(continuation, 42); |
307 | } |
308 | |
309 | { |
310 | // Sub-case: Future fulfilled after `wait()` actually has to wait. |
311 | // Expect call to `.then()` to fail (throw std::logic_error). |
312 | Promise<int> p; |
313 | auto f = p.getFuture(); |
314 | |
315 | folly::Baton<> b; |
316 | auto t = std::thread([&] { |
317 | b.post(); |
318 | /* sleep override */ std::this_thread::sleep_for(milliseconds(100)); |
319 | p.setValue(42); |
320 | }); |
321 | b.wait(); |
322 | |
323 | EXPECT_FALSE(f.isReady()); // deterministically passes in practice |
324 | f.wait(); |
325 | EXPECT_TRUE(f.isReady()); |
326 | auto continuation = 0; |
327 | EXPECT_NO_THROW( |
328 | std::move(f).thenValue([&](auto&& v) { continuation = v; })); |
329 | EXPECT_EQ(continuation, 42); |
330 | t.join(); |
331 | } |
332 | |
333 | { |
334 | // Sub-case: Future fulfilled before `wait(dur)` is called. |
335 | // Expect call to `.then()` to succeed & continuation to run immediately. |
336 | Promise<int> p; |
337 | auto f = p.getFuture(); |
338 | p.setValue(42); |
339 | EXPECT_TRUE(f.isReady()); |
340 | EXPECT_EQ(f.value(), 42); |
341 | f.wait(std::chrono::seconds(10)); |
342 | auto continuation = 0; |
343 | EXPECT_NO_THROW( |
344 | std::move(f).thenValue([&](auto&& v) { continuation = v; })); |
345 | EXPECT_EQ(continuation, 42); |
346 | } |
347 | |
348 | { |
349 | // Sub-case: Future fulfilled after `wait(dur)` actually starts waiting. |
350 | // Expect call to `.then()` to succeed & continuation to when result ready. |
351 | Promise<int> p; |
352 | auto f = p.getFuture(); |
353 | |
354 | folly::Baton<> b; |
355 | auto t = std::thread([&] { |
356 | b.post(); |
357 | /* sleep override */ std::this_thread::sleep_for(milliseconds(100)); |
358 | p.setValue(42); |
359 | }); |
360 | b.wait(); |
361 | |
362 | EXPECT_FALSE(f.isReady()); // deterministically passes in practice |
363 | f.wait(std::chrono::seconds(10)); |
364 | EXPECT_TRUE(f.isReady()); // deterministically passes in practice |
365 | auto continuation = 0; |
366 | EXPECT_NO_THROW( |
367 | std::move(f).thenValue([&](auto&& v) { continuation = v; })); |
368 | EXPECT_EQ(continuation, 42); |
369 | t.join(); |
370 | } |
371 | |
372 | { |
373 | // Sub-case: Future not fulfilled - `wait(dur)` times out. |
374 | // Expect call to `.then()` to succeed; continuation to not run. |
375 | Promise<int> p; |
376 | auto f = p.getFuture(); |
377 | f.wait(milliseconds(1)); |
378 | auto continuation = 0; |
379 | EXPECT_NO_THROW( |
380 | std::move(f).thenValue([&](auto&& v) { continuation = v; })); |
381 | EXPECT_EQ(continuation, 0); |
382 | } |
383 | |
384 | { |
385 | // Sub-case: SemiFuture fulfilled before `wait()` is called. |
386 | // Expect call to `.then()` to succeed & continuation to run immediately. |
387 | Promise<int> p; |
388 | auto f = p.getSemiFuture(); |
389 | p.setValue(42); |
390 | EXPECT_TRUE(f.isReady()); |
391 | EXPECT_EQ(f.value(), 42); |
392 | f.wait(); |
393 | auto continuation = 0; |
394 | InlineExecutor e; |
395 | auto f2 = std::move(f).via(&e); |
396 | EXPECT_NO_THROW( |
397 | std::move(f2).thenValue([&](auto&& v) { continuation = v; })); |
398 | EXPECT_EQ(continuation, 42); |
399 | } |
400 | |
401 | { |
402 | // Sub-case: SemiFuture fulfilled after `wait()` actually has to wait. |
403 | // Expect call to `.then()` to fail (throw std::logic_error). |
404 | Promise<int> p; |
405 | auto f = p.getSemiFuture(); |
406 | |
407 | folly::Baton<> b; |
408 | auto t = std::thread([&] { |
409 | b.post(); |
410 | /* sleep override */ std::this_thread::sleep_for(milliseconds(100)); |
411 | p.setValue(42); |
412 | }); |
413 | b.wait(); |
414 | |
415 | EXPECT_FALSE(f.isReady()); // deterministically passes in practice |
416 | f.wait(); |
417 | EXPECT_TRUE(f.isReady()); |
418 | auto continuation = 0; |
419 | InlineExecutor e; |
420 | auto f2 = std::move(f).via(&e); |
421 | EXPECT_NO_THROW( |
422 | std::move(f2).thenValue([&](auto&& v) { continuation = v; })); |
423 | EXPECT_EQ(continuation, 42); |
424 | t.join(); |
425 | } |
426 | } |
427 | |