]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/tests/unit/futures_test.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / seastar / tests / unit / futures_test.cc
1 /*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 /*
19 * Copyright (C) 2014 Cloudius Systems, Ltd.
20 */
21
22 #include <seastar/testing/test_case.hh>
23
24 #include <seastar/core/shared_ptr.hh>
25 #include <seastar/core/future-util.hh>
26 #include <seastar/core/sleep.hh>
27 #include <seastar/core/do_with.hh>
28 #include <seastar/core/shared_future.hh>
29 #include <seastar/core/thread.hh>
30 #include <seastar/core/print.hh>
31 #include <boost/iterator/counting_iterator.hpp>
32 #include <seastar/testing/thread_test_case.hh>
33
34 using namespace seastar;
35 using namespace std::chrono_literals;
36
37 class expected_exception : std::runtime_error {
38 public:
39 expected_exception() : runtime_error("expected") {}
40 };
41
42 #ifdef __clang__
43 #pragma clang diagnostic push
44 #pragma clang diagnostic ignored "-Wself-move"
45 #endif
46 SEASTAR_TEST_CASE(test_self_move) {
47 future_state<std::unique_ptr<int>> s1;
48 s1.set(std::make_unique<int>(42));
49 s1 = std::move(s1); // no crash, but the value of s1 is not defined.
50
51 future_state<std::unique_ptr<int>> s2;
52 s2.set(std::make_unique<int>(42));
53 std::swap(s2, s2);
54 BOOST_REQUIRE_EQUAL(*std::get<0>(std::move(s2).get()), 42);
55
56 promise<std::unique_ptr<int>> p1;
57 p1.set_value(std::make_unique<int>(42));
58 p1 = std::move(p1); // no crash, but the value of p1 is not defined.
59
60 promise<std::unique_ptr<int>> p2;
61 p2.set_value(std::make_unique<int>(42));
62 std::swap(p2, p2);
63 BOOST_REQUIRE_EQUAL(*p2.get_future().get0(), 42);
64
65 auto f1 = make_ready_future<std::unique_ptr<int>>(std::make_unique<int>(42));
66 f1 = std::move(f1); // no crash, but the value of f1 is not defined.
67
68 auto f2 = make_ready_future<std::unique_ptr<int>>(std::make_unique<int>(42));
69 std::swap(f2, f2);
70 BOOST_REQUIRE_EQUAL(*f2.get0(), 42);
71
72 return make_ready_future<>();
73 }
74 #ifdef __clang__
75 #pragma clang diagnostic pop
76 #endif
77
78 static subscription<int> get_empty_subscription(std::function<future<> (int)> func) {
79 stream<int> s;
80 auto ret = s.listen(func);
81 s.close();
82 return ret;
83 }
84
85 SEASTAR_TEST_CASE(test_stream) {
86 auto sub = get_empty_subscription([](int x) {
87 return make_ready_future<>();
88 });
89 return sub.done();
90 }
91
92 SEASTAR_TEST_CASE(test_stream_drop_sub) {
93 auto s = make_lw_shared<stream<int>>();
94 compat::optional<future<>> ret;
95 {
96 auto sub = s->listen([](int x) {
97 return make_ready_future<>();
98 });
99 *ret = sub.done();
100 // It is ok to drop the subscription when we only want the competition future.
101 }
102 return s->produce(42).then([ret = std::move(*ret), s] () mutable {
103 s->close();
104 return std::move(ret);
105 });
106 }
107
108 SEASTAR_TEST_CASE(test_set_future_state_with_tuple) {
109 future_state<int> s1;
110 promise<int> p1;
111 const std::tuple<int> v1(42);
112 s1.set(v1);
113 p1.set_value(v1);
114
115 future_state<int, int> s2;
116 promise<int, int> p2;
117 const std::tuple<int, int> v2(41, 42);
118 s2.set(v2);
119 p2.set_value(v2);
120
121 return make_ready_future<>();
122 }
123
124 SEASTAR_TEST_CASE(test_set_value_throw_in_copy) {
125 struct throw_in_copy {
126 throw_in_copy() noexcept = default;
127 throw_in_copy(throw_in_copy&& x) noexcept {
128 }
129 throw_in_copy(const throw_in_copy& x) {
130 throw 42;
131 }
132 };
133 promise<throw_in_copy> p1;
134 throw_in_copy v;
135 BOOST_REQUIRE_THROW(p1.set_value(v), int);
136 return make_ready_future<>();
137 }
138
139 SEASTAR_TEST_CASE(test_finally_is_called_on_success_and_failure) {
140 auto finally1 = make_shared<bool>();
141 auto finally2 = make_shared<bool>();
142
143 return make_ready_future().then([] {
144 }).finally([=] {
145 *finally1 = true;
146 }).then([] {
147 throw std::runtime_error("");
148 }).finally([=] {
149 *finally2 = true;
150 }).then_wrapped([=] (auto&& f) {
151 BOOST_REQUIRE(*finally1);
152 BOOST_REQUIRE(*finally2);
153
154 // Should be failed.
155 try {
156 f.get();
157 BOOST_REQUIRE(false);
158 } catch (...) {}
159 });
160 }
161
162 SEASTAR_TEST_CASE(test_get_on_promise) {
163 auto p = promise<uint32_t>();
164 p.set_value(10);
165 BOOST_REQUIRE_EQUAL(10u, p.get_future().get0());
166 return make_ready_future();
167 }
168
169 SEASTAR_TEST_CASE(test_finally_waits_for_inner) {
170 auto finally = make_shared<bool>();
171 auto p = make_shared<promise<>>();
172
173 auto f = make_ready_future().then([] {
174 }).finally([=] {
175 return p->get_future().then([=] {
176 *finally = true;
177 });
178 }).then([=] {
179 BOOST_REQUIRE(*finally);
180 });
181 BOOST_REQUIRE(!*finally);
182 p->set_value();
183 return f;
184 }
185
186 SEASTAR_TEST_CASE(test_finally_is_called_on_success_and_failure__not_ready_to_armed) {
187 auto finally1 = make_shared<bool>();
188 auto finally2 = make_shared<bool>();
189
190 promise<> p;
191 auto f = p.get_future().finally([=] {
192 *finally1 = true;
193 }).then([] {
194 throw std::runtime_error("");
195 }).finally([=] {
196 *finally2 = true;
197 }).then_wrapped([=] (auto &&f) {
198 BOOST_REQUIRE(*finally1);
199 BOOST_REQUIRE(*finally2);
200 try {
201 f.get();
202 } catch (...) {} // silence exceptional future ignored messages
203 });
204
205 p.set_value();
206 return f;
207 }
208
209 SEASTAR_TEST_CASE(test_exception_from_finally_fails_the_target) {
210 promise<> pr;
211 auto f = pr.get_future().finally([=] {
212 throw std::runtime_error("");
213 }).then([] {
214 BOOST_REQUIRE(false);
215 }).then_wrapped([] (auto&& f) {
216 try {
217 f.get();
218 } catch (...) {} // silence exceptional future ignored messages
219 });
220
221 pr.set_value();
222 return f;
223 }
224
225 SEASTAR_TEST_CASE(test_exception_from_finally_fails_the_target_on_already_resolved) {
226 return make_ready_future().finally([=] {
227 throw std::runtime_error("");
228 }).then([] {
229 BOOST_REQUIRE(false);
230 }).then_wrapped([] (auto&& f) {
231 try {
232 f.get();
233 } catch (...) {} // silence exceptional future ignored messages
234 });
235 }
236
237 SEASTAR_TEST_CASE(test_exception_thrown_from_then_wrapped_causes_future_to_fail) {
238 return make_ready_future().then_wrapped([] (auto&& f) {
239 throw std::runtime_error("");
240 }).then_wrapped([] (auto&& f) {
241 try {
242 f.get();
243 BOOST_REQUIRE(false);
244 } catch (...) {}
245 });
246 }
247
248 SEASTAR_TEST_CASE(test_exception_thrown_from_then_wrapped_causes_future_to_fail__async_case) {
249 promise<> p;
250
251 auto f = p.get_future().then_wrapped([] (auto&& f) {
252 throw std::runtime_error("");
253 }).then_wrapped([] (auto&& f) {
254 try {
255 f.get();
256 BOOST_REQUIRE(false);
257 } catch (...) {}
258 });
259
260 p.set_value();
261
262 return f;
263 }
264
265 SEASTAR_TEST_CASE(test_failing_intermediate_promise_should_fail_the_master_future) {
266 promise<> p1;
267 promise<> p2;
268
269 auto f = p1.get_future().then([f = p2.get_future()] () mutable {
270 return std::move(f);
271 }).then([] {
272 BOOST_REQUIRE(false);
273 });
274
275 p1.set_value();
276 p2.set_exception(std::runtime_error("boom"));
277
278 return std::move(f).then_wrapped([](auto&& f) {
279 try {
280 f.get();
281 BOOST_REQUIRE(false);
282 } catch (...) {}
283 });
284 }
285
286 SEASTAR_TEST_CASE(test_future_forwarding__not_ready_to_unarmed) {
287 promise<> p1;
288 promise<> p2;
289
290 auto f1 = p1.get_future();
291 auto f2 = p2.get_future();
292
293 f1.forward_to(std::move(p2));
294
295 BOOST_REQUIRE(!f2.available());
296
297 auto called = f2.then([] {});
298
299 p1.set_value();
300 return called;
301 }
302
303 SEASTAR_TEST_CASE(test_future_forwarding__not_ready_to_armed) {
304 promise<> p1;
305 promise<> p2;
306
307 auto f1 = p1.get_future();
308 auto f2 = p2.get_future();
309
310 auto called = f2.then([] {});
311
312 f1.forward_to(std::move(p2));
313
314 BOOST_REQUIRE(!f2.available());
315
316 p1.set_value();
317
318 return called;
319 }
320
321 SEASTAR_TEST_CASE(test_future_forwarding__ready_to_unarmed) {
322 promise<> p2;
323
324 auto f1 = make_ready_future<>();
325 auto f2 = p2.get_future();
326
327 std::move(f1).forward_to(std::move(p2));
328 BOOST_REQUIRE(f2.available());
329
330 return std::move(f2).then_wrapped([] (future<> f) {
331 BOOST_REQUIRE(!f.failed());
332 });
333 }
334
335 SEASTAR_TEST_CASE(test_future_forwarding__ready_to_armed) {
336 promise<> p2;
337
338 auto f1 = make_ready_future<>();
339 auto f2 = p2.get_future();
340
341 auto called = std::move(f2).then([] {});
342
343 BOOST_REQUIRE(f1.available());
344
345 f1.forward_to(std::move(p2));
346 return called;
347 }
348
349 static void forward_dead_unarmed_promise_with_dead_future_to(promise<>& p) {
350 promise<> p2;
351 p.get_future().forward_to(std::move(p2));
352 }
353
354 SEASTAR_TEST_CASE(test_future_forwarding__ready_to_unarmed_soon_to_be_dead) {
355 promise<> p1;
356 forward_dead_unarmed_promise_with_dead_future_to(p1);
357 make_ready_future<>().forward_to(std::move(p1));
358 return make_ready_future<>();
359 }
360
361 SEASTAR_TEST_CASE(test_exception_can_be_thrown_from_do_until_body) {
362 return do_until([] { return false; }, [] {
363 throw expected_exception();
364 return now();
365 }).then_wrapped([] (auto&& f) {
366 try {
367 f.get();
368 BOOST_FAIL("should have failed");
369 } catch (const expected_exception& e) {
370 // expected
371 }
372 });
373 }
374
375 SEASTAR_TEST_CASE(test_bare_value_can_be_returned_from_callback) {
376 return now().then([] {
377 return 3;
378 }).then([] (int x) {
379 BOOST_REQUIRE(x == 3);
380 });
381 }
382
383 SEASTAR_TEST_CASE(test_when_all_iterator_range) {
384 std::vector<future<size_t>> futures;
385 for (size_t i = 0; i != 1000000; ++i) {
386 // .then() usually returns a ready future, but sometimes it
387 // doesn't, so call it a million times. This exercises both
388 // available and unavailable paths in when_all().
389 futures.push_back(make_ready_future<>().then([i] { return i; }));
390 }
391 // Verify the above statement is correct
392 BOOST_REQUIRE(!std::all_of(futures.begin(), futures.end(),
393 [] (auto& f) { return f.available(); }));
394 auto p = make_shared(std::move(futures));
395 return when_all(p->begin(), p->end()).then([p] (std::vector<future<size_t>> ret) {
396 BOOST_REQUIRE(std::all_of(ret.begin(), ret.end(), [] (auto& f) { return f.available(); }));
397 BOOST_REQUIRE(std::all_of(ret.begin(), ret.end(), [&ret] (auto& f) { return std::get<0>(f.get()) == size_t(&f - ret.data()); }));
398 });
399 }
400
401 SEASTAR_TEST_CASE(test_map_reduce) {
402 auto square = [] (long x) { return make_ready_future<long>(x*x); };
403 long n = 1000;
404 return map_reduce(boost::make_counting_iterator<long>(0), boost::make_counting_iterator<long>(n),
405 square, long(0), std::plus<long>()).then([n] (auto result) {
406 auto m = n - 1; // counting does not include upper bound
407 BOOST_REQUIRE_EQUAL(result, (m * (m + 1) * (2*m + 1)) / 6);
408 });
409 }
410
411 // This test doesn't actually test anything - it just waits for the future
412 // returned by sleep to complete. However, a bug we had in sleep() caused
413 // this test to fail the sanitizer in the debug build, so this is a useful
414 // regression test.
415 SEASTAR_TEST_CASE(test_sleep) {
416 return sleep(std::chrono::milliseconds(100));
417 }
418
419 SEASTAR_TEST_CASE(test_do_with_1) {
420 return do_with(1, [] (int& one) {
421 BOOST_REQUIRE_EQUAL(one, 1);
422 return make_ready_future<>();
423 });
424 }
425
426 SEASTAR_TEST_CASE(test_do_with_2) {
427 return do_with(1, 2L, [] (int& one, long two) {
428 BOOST_REQUIRE_EQUAL(one, 1);
429 BOOST_REQUIRE_EQUAL(two, 2);
430 return make_ready_future<>();
431 });
432 }
433
434 SEASTAR_TEST_CASE(test_do_with_3) {
435 return do_with(1, 2L, 3, [] (int& one, long two, int three) {
436 BOOST_REQUIRE_EQUAL(one, 1);
437 BOOST_REQUIRE_EQUAL(two, 2);
438 BOOST_REQUIRE_EQUAL(three, 3);
439 return make_ready_future<>();
440 });
441 }
442
443 SEASTAR_TEST_CASE(test_do_with_4) {
444 return do_with(1, 2L, 3, 4, [] (int& one, long two, int three, int four) {
445 BOOST_REQUIRE_EQUAL(one, 1);
446 BOOST_REQUIRE_EQUAL(two, 2);
447 BOOST_REQUIRE_EQUAL(three, 3);
448 BOOST_REQUIRE_EQUAL(four, 4);
449 return make_ready_future<>();
450 });
451 }
452
453 SEASTAR_TEST_CASE(test_do_while_stopping_immediately) {
454 return do_with(int(0), [] (int& count) {
455 return repeat([&count] {
456 ++count;
457 return stop_iteration::yes;
458 }).then([&count] {
459 BOOST_REQUIRE(count == 1);
460 });
461 });
462 }
463
464 SEASTAR_TEST_CASE(test_do_while_stopping_after_two_iterations) {
465 return do_with(int(0), [] (int& count) {
466 return repeat([&count] {
467 ++count;
468 return count == 2 ? stop_iteration::yes : stop_iteration::no;
469 }).then([&count] {
470 BOOST_REQUIRE(count == 2);
471 });
472 });
473 }
474
475 SEASTAR_TEST_CASE(test_do_while_failing_in_the_first_step) {
476 return repeat([] {
477 throw expected_exception();
478 return stop_iteration::no;
479 }).then_wrapped([](auto&& f) {
480 try {
481 f.get();
482 BOOST_FAIL("should not happen");
483 } catch (const expected_exception&) {
484 // expected
485 }
486 });
487 }
488
489 SEASTAR_TEST_CASE(test_do_while_failing_in_the_second_step) {
490 return do_with(int(0), [] (int& count) {
491 return repeat([&count] {
492 ++count;
493 if (count > 1) {
494 throw expected_exception();
495 }
496 return later().then([] { return stop_iteration::no; });
497 }).then_wrapped([&count](auto&& f) {
498 try {
499 f.get();
500 BOOST_FAIL("should not happen");
501 } catch (const expected_exception&) {
502 BOOST_REQUIRE(count == 2);
503 }
504 });
505 });
506 }
507
508 SEASTAR_TEST_CASE(test_parallel_for_each) {
509 return async([] {
510 // empty
511 parallel_for_each(std::vector<int>(), [] (int) -> future<> {
512 BOOST_FAIL("should not reach");
513 abort();
514 }).get();
515
516 // immediate result
517 auto range = boost::copy_range<std::vector<int>>(boost::irange(1, 6));
518 auto sum = 0;
519 parallel_for_each(range, [&sum] (int v) {
520 sum += v;
521 return make_ready_future<>();
522 }).get();
523 BOOST_REQUIRE_EQUAL(sum, 15);
524
525 // all suspend
526 sum = 0;
527 parallel_for_each(range, [&sum] (int v) {
528 return later().then([&sum, v] {
529 sum += v;
530 });
531 }).get();
532 BOOST_REQUIRE_EQUAL(sum, 15);
533
534 // throws immediately
535 BOOST_CHECK_EXCEPTION(parallel_for_each(range, [] (int) -> future<> {
536 throw 5;
537 }).get(), int, [] (int v) { return v == 5; });
538
539 // throws after suspension
540 BOOST_CHECK_EXCEPTION(parallel_for_each(range, [] (int) {
541 return later().then([] {
542 throw 5;
543 });
544 }).get(), int, [] (int v) { return v == 5; });
545 });
546 }
547
548 SEASTAR_TEST_CASE(test_parallel_for_each_early_failure) {
549 return do_with(0, [] (int& counter) {
550 return parallel_for_each(boost::irange(0, 11000), [&counter] (int i) {
551 using namespace std::chrono_literals;
552 // force scheduling
553 return sleep((i % 31 + 1) * 1ms).then([&counter, i] {
554 ++counter;
555 if (i % 1777 == 1337) {
556 return make_exception_future<>(i);
557 }
558 return make_ready_future<>();
559 });
560 }).then_wrapped([&counter] (future<> f) {
561 BOOST_REQUIRE_EQUAL(counter, 11000);
562 BOOST_REQUIRE(f.failed());
563 try {
564 f.get();
565 BOOST_FAIL("wanted an exception");
566 } catch (int i) {
567 BOOST_REQUIRE(i % 1777 == 1337);
568 } catch (...) {
569 BOOST_FAIL("bad exception type");
570 }
571 });
572 });
573 }
574
575 SEASTAR_TEST_CASE(test_parallel_for_each_waits_for_all_fibers_even_if_one_of_them_failed) {
576 auto can_exit = make_lw_shared<bool>(false);
577 return parallel_for_each(boost::irange(0, 2), [can_exit] (int i) {
578 return later().then([i, can_exit] {
579 if (i == 1) {
580 throw expected_exception();
581 } else {
582 using namespace std::chrono_literals;
583 return sleep(300ms).then([can_exit] {
584 *can_exit = true;
585 });
586 }
587 });
588 }).then_wrapped([can_exit] (auto&& f) {
589 try {
590 f.get();
591 } catch (...) {
592 // expected
593 }
594 BOOST_REQUIRE(*can_exit);
595 });
596 }
597
598 #ifndef SEASTAR_SHUFFLE_TASK_QUEUE
599 SEASTAR_TEST_CASE(test_high_priority_task_runs_before_ready_continuations) {
600 return now().then([] {
601 auto flag = make_lw_shared<bool>(false);
602 engine().add_high_priority_task(make_task([flag] {
603 *flag = true;
604 }));
605 return make_ready_future().then([flag] {
606 BOOST_REQUIRE(*flag);
607 });
608 });
609 }
610
611 SEASTAR_TEST_CASE(test_high_priority_task_runs_in_the_middle_of_loops) {
612 auto counter = make_lw_shared<int>(0);
613 auto flag = make_lw_shared<bool>(false);
614 return repeat([counter, flag] {
615 if (*counter == 1) {
616 BOOST_REQUIRE(*flag);
617 return stop_iteration::yes;
618 }
619 engine().add_high_priority_task(make_task([flag] {
620 *flag = true;
621 }));
622 ++(*counter);
623 return stop_iteration::no;
624 });
625 }
626 #endif
627
628 SEASTAR_TEST_CASE(futurize_apply_val_exception) {
629 return futurize<int>::apply([] (int arg) { throw expected_exception(); return arg; }, 1).then_wrapped([] (future<int> f) {
630 try {
631 f.get();
632 BOOST_FAIL("should have thrown");
633 } catch (expected_exception& e) {}
634 });
635 }
636
637 SEASTAR_TEST_CASE(futurize_apply_val_ok) {
638 return futurize<int>::apply([] (int arg) { return arg * 2; }, 2).then_wrapped([] (future<int> f) {
639 try {
640 auto x = f.get0();
641 BOOST_REQUIRE_EQUAL(x, 4);
642 } catch (expected_exception& e) {
643 BOOST_FAIL("should not have thrown");
644 }
645 });
646 }
647
648 SEASTAR_TEST_CASE(futurize_apply_val_future_exception) {
649 return futurize<int>::apply([] (int a) {
650 return sleep(std::chrono::milliseconds(100)).then([] {
651 throw expected_exception();
652 return make_ready_future<int>(0);
653 });
654 }, 0).then_wrapped([] (future<int> f) {
655 try {
656 f.get();
657 BOOST_FAIL("should have thrown");
658 } catch (expected_exception& e) { }
659 });
660 }
661
662 SEASTAR_TEST_CASE(futurize_apply_val_future_ok) {
663 return futurize<int>::apply([] (int a) {
664 return sleep(std::chrono::milliseconds(100)).then([a] {
665 return make_ready_future<int>(a * 100);
666 });
667 }, 2).then_wrapped([] (future<int> f) {
668 try {
669 auto x = f.get0();
670 BOOST_REQUIRE_EQUAL(x, 200);
671 } catch (expected_exception& e) {
672 BOOST_FAIL("should not have thrown");
673 }
674 });
675 }
676 SEASTAR_TEST_CASE(futurize_apply_void_exception) {
677 return futurize<void>::apply([] (auto arg) { throw expected_exception(); }, 0).then_wrapped([] (future<> f) {
678 try {
679 f.get();
680 BOOST_FAIL("should have thrown");
681 } catch (expected_exception& e) {}
682 });
683 }
684
685 SEASTAR_TEST_CASE(futurize_apply_void_ok) {
686 return futurize<void>::apply([] (auto arg) { }, 0).then_wrapped([] (future<> f) {
687 try {
688 f.get();
689 } catch (expected_exception& e) {
690 BOOST_FAIL("should not have thrown");
691 }
692 });
693 }
694
695 SEASTAR_TEST_CASE(futurize_apply_void_future_exception) {
696 return futurize<void>::apply([] (auto a) {
697 return sleep(std::chrono::milliseconds(100)).then([] {
698 throw expected_exception();
699 });
700 }, 0).then_wrapped([] (future<> f) {
701 try {
702 f.get();
703 BOOST_FAIL("should have thrown");
704 } catch (expected_exception& e) { }
705 });
706 }
707
708 SEASTAR_TEST_CASE(futurize_apply_void_future_ok) {
709 auto a = make_lw_shared<int>(1);
710 return futurize<void>::apply([] (int& a) {
711 return sleep(std::chrono::milliseconds(100)).then([&a] {
712 a *= 100;
713 });
714 }, *a).then_wrapped([a] (future<> f) {
715 try {
716 f.get();
717 BOOST_REQUIRE_EQUAL(*a, 100);
718 } catch (expected_exception& e) {
719 BOOST_FAIL("should not have thrown");
720 }
721 });
722 }
723
724 SEASTAR_TEST_CASE(test_unused_shared_future_is_not_a_broken_future) {
725 promise<> p;
726 shared_future<> s(p.get_future());
727 return make_ready_future<>();
728 }
729
730 SEASTAR_TEST_CASE(test_shared_future_propagates_value_to_all) {
731 return seastar::async([] {
732 promise<shared_ptr<int>> p; // shared_ptr<> to check it deals with emptyable types
733 shared_future<shared_ptr<int>> f(p.get_future());
734
735 auto f1 = f.get_future();
736 auto f2 = f.get_future();
737
738 p.set_value(make_shared<int>(1));
739 BOOST_REQUIRE(*f1.get0() == 1);
740 BOOST_REQUIRE(*f2.get0() == 1);
741 });
742 }
743
744 template<typename... T>
745 void check_fails_with_expected(future<T...> f) {
746 try {
747 f.get();
748 BOOST_FAIL("Should have failed");
749 } catch (expected_exception&) {
750 // expected
751 }
752 }
753
754 SEASTAR_TEST_CASE(test_shared_future_propagates_value_to_copies) {
755 return seastar::async([] {
756 promise<int> p;
757 auto sf1 = shared_future<int>(p.get_future());
758 auto sf2 = sf1;
759
760 auto f1 = sf1.get_future();
761 auto f2 = sf2.get_future();
762
763 p.set_value(1);
764
765 BOOST_REQUIRE(f1.get0() == 1);
766 BOOST_REQUIRE(f2.get0() == 1);
767 });
768 }
769
770 SEASTAR_TEST_CASE(test_obtaining_future_from_shared_future_after_it_is_resolved) {
771 promise<int> p1;
772 promise<int> p2;
773 auto sf1 = shared_future<int>(p1.get_future());
774 auto sf2 = shared_future<int>(p2.get_future());
775 p1.set_value(1);
776 p2.set_exception(expected_exception());
777 return sf2.get_future().then_wrapped([f1 = sf1.get_future()] (auto&& f) mutable {
778 check_fails_with_expected(std::move(f));
779 return std::move(f1);
780 }).then_wrapped([] (auto&& f) {
781 BOOST_REQUIRE(f.get0() == 1);
782 });
783 }
784
785 SEASTAR_TEST_CASE(test_valueless_shared_future) {
786 return seastar::async([] {
787 promise<> p;
788 shared_future<> f(p.get_future());
789
790 auto f1 = f.get_future();
791 auto f2 = f.get_future();
792
793 p.set_value();
794
795 f1.get();
796 f2.get();
797 });
798 }
799
800 SEASTAR_TEST_CASE(test_shared_future_propagates_errors_to_all) {
801 promise<int> p;
802 shared_future<int> f(p.get_future());
803
804 auto f1 = f.get_future();
805 auto f2 = f.get_future();
806
807 p.set_exception(expected_exception());
808
809 return f1.then_wrapped([f2 = std::move(f2)] (auto&& f) mutable {
810 check_fails_with_expected(std::move(f));
811 return std::move(f2);
812 }).then_wrapped([] (auto&& f) mutable {
813 check_fails_with_expected(std::move(f));
814 });
815 }
816
817 SEASTAR_TEST_CASE(test_ignored_future_warning) {
818 // This doesn't warn:
819 promise<> p;
820 p.set_exception(expected_exception());
821 future<> f = p.get_future();
822 f.ignore_ready_future();
823
824 // And by analogy, neither should this
825 shared_promise<> p2;
826 p2.set_exception(expected_exception());
827 future<> f2 = p2.get_shared_future();
828 f2.ignore_ready_future();
829 return make_ready_future<>();
830 }
831
832 SEASTAR_TEST_CASE(test_futurize_from_tuple) {
833 std::tuple<int> v1 = std::make_tuple(3);
834 std::tuple<> v2 = {};
835 BOOST_REQUIRE(futurize<int>::from_tuple(v1).get() == v1);
836 BOOST_REQUIRE(futurize<void>::from_tuple(v2).get() == v2);
837 return make_ready_future<>();
838 }
839
840 SEASTAR_TEST_CASE(test_repeat_until_value) {
841 return do_with(int(), [] (int& counter) {
842 return repeat_until_value([&counter] () -> future<compat::optional<int>> {
843 if (counter == 10000) {
844 return make_ready_future<compat::optional<int>>(counter);
845 } else {
846 ++counter;
847 return make_ready_future<compat::optional<int>>(compat::nullopt);
848 }
849 }).then([&counter] (int result) {
850 BOOST_REQUIRE(counter == 10000);
851 BOOST_REQUIRE(result == counter);
852 });
853 });
854 }
855
856 SEASTAR_TEST_CASE(test_repeat_until_value_implicit_future) {
857 // Same as above, but returning compat::optional<int> instead of future<compat::optional<int>>
858 return do_with(int(), [] (int& counter) {
859 return repeat_until_value([&counter] {
860 if (counter == 10000) {
861 return compat::optional<int>(counter);
862 } else {
863 ++counter;
864 return compat::optional<int>(compat::nullopt);
865 }
866 }).then([&counter] (int result) {
867 BOOST_REQUIRE(counter == 10000);
868 BOOST_REQUIRE(result == counter);
869 });
870 });
871 }
872
873 SEASTAR_TEST_CASE(test_repeat_until_value_exception) {
874 return repeat_until_value([] {
875 throw expected_exception();
876 return compat::optional<int>(43);
877 }).then_wrapped([] (future<int> f) {
878 check_fails_with_expected(std::move(f));
879 });
880 }
881
882 SEASTAR_TEST_CASE(test_when_allx) {
883 return when_all(later(), later(), make_ready_future()).discard_result();
884 }
885
886 #if __cplusplus >= 201703L
887
888 // A noncopyable and nonmovable struct
889 struct non_copy_non_move {
890 non_copy_non_move(non_copy_non_move&&) = delete;
891 non_copy_non_move(const non_copy_non_move&) = delete;
892 };
893
894 SEASTAR_TEST_CASE(test_when_all_functions) {
895 auto f = [x = non_copy_non_move{}] {
896 (void)x;
897 return make_ready_future<int>(42);
898 };
899 return when_all(f, [] {
900 throw 42;
901 return make_ready_future<>();
902 }, later()).then([] (std::tuple<future<int>, future<>, future<>> res) {
903 BOOST_REQUIRE_EQUAL(std::get<0>(res).get0(), 42);
904
905 BOOST_REQUIRE(std::get<1>(res).available());
906 BOOST_REQUIRE(std::get<1>(res).failed());
907 std::get<1>(res).ignore_ready_future();
908
909 BOOST_REQUIRE(std::get<2>(res).available());
910 BOOST_REQUIRE(!std::get<2>(res).failed());
911 return make_ready_future<>();
912 });
913 }
914
915 SEASTAR_TEST_CASE(test_when_all_succeed_functions) {
916 auto f = [x = non_copy_non_move{}] {
917 (void)x;
918 return make_ready_future<int>(42);
919 };
920 return when_all_succeed(f, [] {
921 throw 42;
922 return make_ready_future<>();
923 }, later()).then_wrapped([] (future<int> res) {
924 BOOST_REQUIRE(res.available());
925 BOOST_REQUIRE(res.failed());
926 res.ignore_ready_future();
927 return make_ready_future<>();
928 });
929 }
930
931 #endif
932
933 template<typename E, typename... T>
934 static void check_failed_with(future<T...>&& f) {
935 BOOST_REQUIRE(f.failed());
936 try {
937 f.get();
938 BOOST_FAIL("exception expected");
939 } catch (const E& e) {
940 // expected
941 } catch (...) {
942 BOOST_FAIL(format("wrong exception: {}", std::current_exception()));
943 }
944 }
945
946 template<typename... T>
947 static void check_timed_out(future<T...>&& f) {
948 check_failed_with<timed_out_error>(std::move(f));
949 }
950
951 SEASTAR_TEST_CASE(test_with_timeout_when_it_times_out) {
952 return seastar::async([] {
953 promise<> pr;
954 auto f = with_timeout(manual_clock::now() + 2s, pr.get_future());
955
956 BOOST_REQUIRE(!f.available());
957
958 manual_clock::advance(1s);
959 later().get();
960
961 BOOST_REQUIRE(!f.available());
962
963 manual_clock::advance(1s);
964 later().get();
965
966 check_timed_out(std::move(f));
967
968 pr.set_value();
969 });
970 }
971
972 SEASTAR_THREAD_TEST_CASE(test_shared_future_get_future_after_timeout) {
973 // This used to crash because shared_future checked if the list of
974 // pending futures was empty to decide if it had already called
975 // then_wrapped. If all pending futures timed out, it would call
976 // it again.
977 promise<> pr;
978 shared_future<with_clock<manual_clock>> sfut(pr.get_future());
979 future<> fut1 = sfut.get_future(manual_clock::now() + 1s);
980
981 manual_clock::advance(1s);
982
983 check_timed_out(std::move(fut1));
984
985 future<> fut2 = sfut.get_future(manual_clock::now() + 1s);
986 manual_clock::advance(1s);
987 check_timed_out(std::move(fut2));
988
989 future<> fut3 = sfut.get_future(manual_clock::now() + 1s);
990 pr.set_value();
991 }
992
993 SEASTAR_TEST_CASE(test_custom_exception_factory_in_with_timeout) {
994 return seastar::async([] {
995 class custom_error : public std::exception {
996 public:
997 virtual const char* what() const noexcept {
998 return "timedout";
999 }
1000 };
1001 struct my_exception_factory {
1002 static auto timeout() {
1003 return custom_error();
1004 }
1005 };
1006 promise<> pr;
1007 auto f = with_timeout<my_exception_factory>(manual_clock::now() + 1s, pr.get_future());
1008
1009 manual_clock::advance(1s);
1010 later().get();
1011
1012 check_failed_with<custom_error>(std::move(f));
1013 });
1014 }
1015
1016 SEASTAR_TEST_CASE(test_with_timeout_when_it_does_not_time_out) {
1017 return seastar::async([] {
1018 {
1019 promise<int> pr;
1020 auto f = with_timeout(manual_clock::now() + 1s, pr.get_future());
1021
1022 pr.set_value(42);
1023
1024 BOOST_REQUIRE_EQUAL(f.get0(), 42);
1025 }
1026
1027 // Check that timer was indeed cancelled
1028 manual_clock::advance(1s);
1029 later().get();
1030 });
1031 }
1032
1033 SEASTAR_TEST_CASE(test_shared_future_with_timeout) {
1034 return seastar::async([] {
1035 shared_promise<with_clock<manual_clock>, int> pr;
1036 auto f1 = pr.get_shared_future(manual_clock::now() + 1s);
1037 auto f2 = pr.get_shared_future(manual_clock::now() + 2s);
1038 auto f3 = pr.get_shared_future();
1039
1040 BOOST_REQUIRE(!f1.available());
1041 BOOST_REQUIRE(!f2.available());
1042 BOOST_REQUIRE(!f3.available());
1043
1044 manual_clock::advance(1s);
1045 later().get();
1046
1047 check_timed_out(std::move(f1));
1048 BOOST_REQUIRE(!f2.available());
1049 BOOST_REQUIRE(!f3.available());
1050
1051 manual_clock::advance(1s);
1052 later().get();
1053
1054 check_timed_out(std::move(f2));
1055 BOOST_REQUIRE(!f3.available());
1056
1057 pr.set_value(42);
1058
1059 BOOST_REQUIRE_EQUAL(42, f3.get0());
1060 });
1061 }
1062
1063 SEASTAR_TEST_CASE(test_when_all_succeed_tuples) {
1064 return seastar::when_all_succeed(
1065 make_ready_future<>(),
1066 make_ready_future<sstring>("hello world"),
1067 make_ready_future<int>(42),
1068 make_ready_future<>(),
1069 make_ready_future<int, sstring>(84, "hi"),
1070 make_ready_future<bool>(true)
1071 ).then([] (sstring msg, int v, std::tuple<int, sstring> t, bool b) {
1072 BOOST_REQUIRE_EQUAL(msg, "hello world");
1073 BOOST_REQUIRE_EQUAL(v, 42);
1074 BOOST_REQUIRE_EQUAL(std::get<0>(t), 84);
1075 BOOST_REQUIRE_EQUAL(std::get<1>(t), "hi");
1076 BOOST_REQUIRE_EQUAL(b, true);
1077
1078 return seastar::when_all_succeed(
1079 make_exception_future<>(42),
1080 make_ready_future<sstring>("hello world"),
1081 make_exception_future<int>(43),
1082 make_ready_future<>()
1083 ).then([] (sstring, int) {
1084 BOOST_FAIL("shouldn't reach");
1085 return false;
1086 }).handle_exception([] (auto excp) {
1087 try {
1088 std::rethrow_exception(excp);
1089 } catch (int v) {
1090 BOOST_REQUIRE(v == 42 || v == 43);
1091 return true;
1092 } catch (...) { }
1093 return false;
1094 }).then([] (auto ret) {
1095 BOOST_REQUIRE(ret);
1096 });
1097 });
1098 }
1099
1100 SEASTAR_TEST_CASE(test_when_all_succeed_vector) {
1101 std::vector<future<>> vecs;
1102 vecs.emplace_back(make_ready_future<>());
1103 vecs.emplace_back(make_ready_future<>());
1104 vecs.emplace_back(make_ready_future<>());
1105 vecs.emplace_back(make_ready_future<>());
1106 return seastar::when_all_succeed(vecs.begin(), vecs.end()).then([] {
1107 std::vector<future<>> vecs;
1108 vecs.emplace_back(make_ready_future<>());
1109 vecs.emplace_back(make_ready_future<>());
1110 vecs.emplace_back(make_exception_future<>(42));
1111 vecs.emplace_back(make_exception_future<>(43));
1112 return seastar::when_all_succeed(vecs.begin(), vecs.end());
1113 }).then([] {
1114 BOOST_FAIL("shouldn't reach");
1115 return false;
1116 }).handle_exception([] (auto excp) {
1117 try {
1118 std::rethrow_exception(excp);
1119 } catch (int v) {
1120 BOOST_REQUIRE(v == 42 || v == 43);
1121 return true;
1122 } catch (...) { }
1123 return false;
1124 }).then([] (auto ret) {
1125 BOOST_REQUIRE(ret);
1126
1127 std::vector<future<int>> vecs;
1128 vecs.emplace_back(make_ready_future<int>(1));
1129 vecs.emplace_back(make_ready_future<int>(2));
1130 vecs.emplace_back(make_ready_future<int>(3));
1131 return seastar::when_all_succeed(vecs.begin(), vecs.end());
1132 }).then([] (std::vector<int> vals) {
1133 BOOST_REQUIRE_EQUAL(vals.size(), 3u);
1134 BOOST_REQUIRE_EQUAL(vals[0], 1);
1135 BOOST_REQUIRE_EQUAL(vals[1], 2);
1136 BOOST_REQUIRE_EQUAL(vals[2], 3);
1137
1138 std::vector<future<int>> vecs;
1139 vecs.emplace_back(make_ready_future<int>(1));
1140 vecs.emplace_back(make_ready_future<int>(2));
1141 vecs.emplace_back(make_exception_future<int>(42));
1142 vecs.emplace_back(make_exception_future<int>(43));
1143 return seastar::when_all_succeed(vecs.begin(), vecs.end());
1144 }).then([] (std::vector<int>) {
1145 BOOST_FAIL("shouldn't reach");
1146 return false;
1147 }).handle_exception([] (auto excp) {
1148 try {
1149 std::rethrow_exception(excp);
1150 } catch (int v) {
1151 BOOST_REQUIRE(v == 42 || v == 43);
1152 return true;
1153 } catch (...) { }
1154 return false;
1155 }).then([] (auto ret) {
1156 BOOST_REQUIRE(ret);
1157 });
1158 }
1159
1160 SEASTAR_TEST_CASE(test_futurize_mutable) {
1161 int count = 0;
1162 return seastar::repeat([count]() mutable {
1163 ++count;
1164 if (count == 3) {
1165 return seastar::stop_iteration::yes;
1166 }
1167 return seastar::stop_iteration::no;
1168 });
1169 }
1170
1171 SEASTAR_THREAD_TEST_CASE(test_broken_promises) {
1172 compat::optional<future<>> f;
1173 compat::optional<future<>> f2;
1174 { // Broken after attaching a continuation
1175 auto p = promise<>();
1176 f = p.get_future();
1177 f2 = f->then_wrapped([&] (future<> f3) {
1178 BOOST_CHECK(f3.failed());
1179 BOOST_CHECK_THROW(f3.get(), broken_promise);
1180 f = { };
1181 });
1182 }
1183 f2->get();
1184 BOOST_CHECK(!f);
1185
1186 { // Broken before attaching a continuation
1187 auto p = promise<>();
1188 f = p.get_future();
1189 }
1190 f->then_wrapped([&] (future<> f3) {
1191 BOOST_CHECK(f3.failed());
1192 BOOST_CHECK_THROW(f3.get(), broken_promise);
1193 f = { };
1194 }).get();
1195 BOOST_CHECK(!f);
1196
1197 { // Broken before suspending a thread
1198 auto p = promise<>();
1199 f = p.get_future();
1200 }
1201 BOOST_CHECK_THROW(f->get(), broken_promise);
1202 }
1203
1204 SEASTAR_TEST_CASE(test_warn_on_broken_promise_with_no_future) {
1205 // Example code where we expect a "Exceptional future ignored"
1206 // warning. We can't directly test that the warning is issued, but
1207 // this example functions as documentation.
1208 promise<> p;
1209 // Intentionally destroy the future
1210 (void)p.get_future();
1211 p.set_exception(std::runtime_error("foo"));
1212 return make_ready_future<>();
1213 }