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.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * Copyright (C) 2014 Cloudius Systems, Ltd.
22 #include <seastar/testing/test_case.hh>
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>
34 using namespace seastar
;
35 using namespace std::chrono_literals
;
37 class expected_exception
: std::runtime_error
{
39 expected_exception() : runtime_error("expected") {}
43 #pragma clang diagnostic push
44 #pragma clang diagnostic ignored "-Wself-move"
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.
51 future_state
<std::unique_ptr
<int>> s2
;
52 s2
.set(std::make_unique
<int>(42));
54 BOOST_REQUIRE_EQUAL(*std::get
<0>(std::move(s2
).get()), 42);
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.
60 promise
<std::unique_ptr
<int>> p2
;
61 p2
.set_value(std::make_unique
<int>(42));
63 BOOST_REQUIRE_EQUAL(*p2
.get_future().get0(), 42);
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.
68 auto f2
= make_ready_future
<std::unique_ptr
<int>>(std::make_unique
<int>(42));
70 BOOST_REQUIRE_EQUAL(*f2
.get0(), 42);
72 return make_ready_future
<>();
75 #pragma clang diagnostic pop
78 static subscription
<int> get_empty_subscription(std::function
<future
<> (int)> func
) {
80 auto ret
= s
.listen(func
);
85 SEASTAR_TEST_CASE(test_stream
) {
86 auto sub
= get_empty_subscription([](int x
) {
87 return make_ready_future
<>();
92 SEASTAR_TEST_CASE(test_stream_drop_sub
) {
93 auto s
= make_lw_shared
<stream
<int>>();
94 compat::optional
<future
<>> ret
;
96 auto sub
= s
->listen([](int x
) {
97 return make_ready_future
<>();
100 // It is ok to drop the subscription when we only want the competition future.
102 return s
->produce(42).then([ret
= std::move(*ret
), s
] () mutable {
104 return std::move(ret
);
108 SEASTAR_TEST_CASE(test_set_future_state_with_tuple
) {
109 future_state
<int> s1
;
111 const std::tuple
<int> v1(42);
115 future_state
<int, int> s2
;
116 promise
<int, int> p2
;
117 const std::tuple
<int, int> v2(41, 42);
121 return make_ready_future
<>();
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
{
129 throw_in_copy(const throw_in_copy
& x
) {
133 promise
<throw_in_copy
> p1
;
135 BOOST_REQUIRE_THROW(p1
.set_value(v
), int);
136 return make_ready_future
<>();
139 SEASTAR_TEST_CASE(test_finally_is_called_on_success_and_failure
) {
140 auto finally1
= make_shared
<bool>();
141 auto finally2
= make_shared
<bool>();
143 return make_ready_future().then([] {
147 throw std::runtime_error("");
150 }).then_wrapped([=] (auto&& f
) {
151 BOOST_REQUIRE(*finally1
);
152 BOOST_REQUIRE(*finally2
);
157 BOOST_REQUIRE(false);
162 SEASTAR_TEST_CASE(test_get_on_promise
) {
163 auto p
= promise
<uint32_t>();
165 BOOST_REQUIRE_EQUAL(10u, p
.get_future().get0());
166 return make_ready_future();
169 SEASTAR_TEST_CASE(test_finally_waits_for_inner
) {
170 auto finally
= make_shared
<bool>();
171 auto p
= make_shared
<promise
<>>();
173 auto f
= make_ready_future().then([] {
175 return p
->get_future().then([=] {
179 BOOST_REQUIRE(*finally
);
181 BOOST_REQUIRE(!*finally
);
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>();
191 auto f
= p
.get_future().finally([=] {
194 throw std::runtime_error("");
197 }).then_wrapped([=] (auto &&f
) {
198 BOOST_REQUIRE(*finally1
);
199 BOOST_REQUIRE(*finally2
);
202 } catch (...) {} // silence exceptional future ignored messages
209 SEASTAR_TEST_CASE(test_exception_from_finally_fails_the_target
) {
211 auto f
= pr
.get_future().finally([=] {
212 throw std::runtime_error("");
214 BOOST_REQUIRE(false);
215 }).then_wrapped([] (auto&& f
) {
218 } catch (...) {} // silence exceptional future ignored messages
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("");
229 BOOST_REQUIRE(false);
230 }).then_wrapped([] (auto&& f
) {
233 } catch (...) {} // silence exceptional future ignored messages
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
) {
243 BOOST_REQUIRE(false);
248 SEASTAR_TEST_CASE(test_exception_thrown_from_then_wrapped_causes_future_to_fail__async_case
) {
251 auto f
= p
.get_future().then_wrapped([] (auto&& f
) {
252 throw std::runtime_error("");
253 }).then_wrapped([] (auto&& f
) {
256 BOOST_REQUIRE(false);
265 SEASTAR_TEST_CASE(test_failing_intermediate_promise_should_fail_the_master_future
) {
269 auto f
= p1
.get_future().then([f
= p2
.get_future()] () mutable {
272 BOOST_REQUIRE(false);
276 p2
.set_exception(std::runtime_error("boom"));
278 return std::move(f
).then_wrapped([](auto&& f
) {
281 BOOST_REQUIRE(false);
286 SEASTAR_TEST_CASE(test_future_forwarding__not_ready_to_unarmed
) {
290 auto f1
= p1
.get_future();
291 auto f2
= p2
.get_future();
293 f1
.forward_to(std::move(p2
));
295 BOOST_REQUIRE(!f2
.available());
297 auto called
= f2
.then([] {});
303 SEASTAR_TEST_CASE(test_future_forwarding__not_ready_to_armed
) {
307 auto f1
= p1
.get_future();
308 auto f2
= p2
.get_future();
310 auto called
= f2
.then([] {});
312 f1
.forward_to(std::move(p2
));
314 BOOST_REQUIRE(!f2
.available());
321 SEASTAR_TEST_CASE(test_future_forwarding__ready_to_unarmed
) {
324 auto f1
= make_ready_future
<>();
325 auto f2
= p2
.get_future();
327 std::move(f1
).forward_to(std::move(p2
));
328 BOOST_REQUIRE(f2
.available());
330 return std::move(f2
).then_wrapped([] (future
<> f
) {
331 BOOST_REQUIRE(!f
.failed());
335 SEASTAR_TEST_CASE(test_future_forwarding__ready_to_armed
) {
338 auto f1
= make_ready_future
<>();
339 auto f2
= p2
.get_future();
341 auto called
= std::move(f2
).then([] {});
343 BOOST_REQUIRE(f1
.available());
345 f1
.forward_to(std::move(p2
));
349 static void forward_dead_unarmed_promise_with_dead_future_to(promise
<>& p
) {
351 p
.get_future().forward_to(std::move(p2
));
354 SEASTAR_TEST_CASE(test_future_forwarding__ready_to_unarmed_soon_to_be_dead
) {
356 forward_dead_unarmed_promise_with_dead_future_to(p1
);
357 make_ready_future
<>().forward_to(std::move(p1
));
358 return make_ready_future
<>();
361 SEASTAR_TEST_CASE(test_exception_can_be_thrown_from_do_until_body
) {
362 return do_until([] { return false; }, [] {
363 throw expected_exception();
365 }).then_wrapped([] (auto&& f
) {
368 BOOST_FAIL("should have failed");
369 } catch (const expected_exception
& e
) {
375 SEASTAR_TEST_CASE(test_bare_value_can_be_returned_from_callback
) {
376 return now().then([] {
379 BOOST_REQUIRE(x
== 3);
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
; }));
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()); }));
401 SEASTAR_TEST_CASE(test_map_reduce
) {
402 auto square
= [] (long x
) { return make_ready_future
<long>(x
*x
); };
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);
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
415 SEASTAR_TEST_CASE(test_sleep
) {
416 return sleep(std::chrono::milliseconds(100));
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
<>();
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
<>();
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
<>();
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
<>();
453 SEASTAR_TEST_CASE(test_do_while_stopping_immediately
) {
454 return do_with(int(0), [] (int& count
) {
455 return repeat([&count
] {
457 return stop_iteration::yes
;
459 BOOST_REQUIRE(count
== 1);
464 SEASTAR_TEST_CASE(test_do_while_stopping_after_two_iterations
) {
465 return do_with(int(0), [] (int& count
) {
466 return repeat([&count
] {
468 return count
== 2 ? stop_iteration::yes
: stop_iteration::no
;
470 BOOST_REQUIRE(count
== 2);
475 SEASTAR_TEST_CASE(test_do_while_failing_in_the_first_step
) {
477 throw expected_exception();
478 return stop_iteration::no
;
479 }).then_wrapped([](auto&& f
) {
482 BOOST_FAIL("should not happen");
483 } catch (const expected_exception
&) {
489 SEASTAR_TEST_CASE(test_do_while_failing_in_the_second_step
) {
490 return do_with(int(0), [] (int& count
) {
491 return repeat([&count
] {
494 throw expected_exception();
496 return later().then([] { return stop_iteration::no
; });
497 }).then_wrapped([&count
](auto&& f
) {
500 BOOST_FAIL("should not happen");
501 } catch (const expected_exception
&) {
502 BOOST_REQUIRE(count
== 2);
508 SEASTAR_TEST_CASE(test_parallel_for_each
) {
511 parallel_for_each(std::vector
<int>(), [] (int) -> future
<> {
512 BOOST_FAIL("should not reach");
517 auto range
= boost::copy_range
<std::vector
<int>>(boost::irange(1, 6));
519 parallel_for_each(range
, [&sum
] (int v
) {
521 return make_ready_future
<>();
523 BOOST_REQUIRE_EQUAL(sum
, 15);
527 parallel_for_each(range
, [&sum
] (int v
) {
528 return later().then([&sum
, v
] {
532 BOOST_REQUIRE_EQUAL(sum
, 15);
534 // throws immediately
535 BOOST_CHECK_EXCEPTION(parallel_for_each(range
, [] (int) -> future
<> {
537 }).get(), int, [] (int v
) { return v
== 5; });
539 // throws after suspension
540 BOOST_CHECK_EXCEPTION(parallel_for_each(range
, [] (int) {
541 return later().then([] {
544 }).get(), int, [] (int v
) { return v
== 5; });
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
;
553 return sleep((i
% 31 + 1) * 1ms
).then([&counter
, i
] {
555 if (i
% 1777 == 1337) {
556 return make_exception_future
<>(i
);
558 return make_ready_future
<>();
560 }).then_wrapped([&counter
] (future
<> f
) {
561 BOOST_REQUIRE_EQUAL(counter
, 11000);
562 BOOST_REQUIRE(f
.failed());
565 BOOST_FAIL("wanted an exception");
567 BOOST_REQUIRE(i
% 1777 == 1337);
569 BOOST_FAIL("bad exception type");
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
] {
580 throw expected_exception();
582 using namespace std::chrono_literals
;
583 return sleep(300ms
).then([can_exit
] {
588 }).then_wrapped([can_exit
] (auto&& f
) {
594 BOOST_REQUIRE(*can_exit
);
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
] {
605 return make_ready_future().then([flag
] {
606 BOOST_REQUIRE(*flag
);
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
] {
616 BOOST_REQUIRE(*flag
);
617 return stop_iteration::yes
;
619 engine().add_high_priority_task(make_task([flag
] {
623 return stop_iteration::no
;
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
) {
632 BOOST_FAIL("should have thrown");
633 } catch (expected_exception
& e
) {}
637 SEASTAR_TEST_CASE(futurize_apply_val_ok
) {
638 return futurize
<int>::apply([] (int arg
) { return arg
* 2; }, 2).then_wrapped([] (future
<int> f
) {
641 BOOST_REQUIRE_EQUAL(x
, 4);
642 } catch (expected_exception
& e
) {
643 BOOST_FAIL("should not have thrown");
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);
654 }, 0).then_wrapped([] (future
<int> f
) {
657 BOOST_FAIL("should have thrown");
658 } catch (expected_exception
& e
) { }
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);
667 }, 2).then_wrapped([] (future
<int> f
) {
670 BOOST_REQUIRE_EQUAL(x
, 200);
671 } catch (expected_exception
& e
) {
672 BOOST_FAIL("should not have thrown");
676 SEASTAR_TEST_CASE(futurize_apply_void_exception
) {
677 return futurize
<void>::apply([] (auto arg
) { throw expected_exception(); }, 0).then_wrapped([] (future
<> f
) {
680 BOOST_FAIL("should have thrown");
681 } catch (expected_exception
& e
) {}
685 SEASTAR_TEST_CASE(futurize_apply_void_ok
) {
686 return futurize
<void>::apply([] (auto arg
) { }, 0).then_wrapped([] (future
<> f
) {
689 } catch (expected_exception
& e
) {
690 BOOST_FAIL("should not have thrown");
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();
700 }, 0).then_wrapped([] (future
<> f
) {
703 BOOST_FAIL("should have thrown");
704 } catch (expected_exception
& e
) { }
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
] {
714 }, *a
).then_wrapped([a
] (future
<> f
) {
717 BOOST_REQUIRE_EQUAL(*a
, 100);
718 } catch (expected_exception
& e
) {
719 BOOST_FAIL("should not have thrown");
724 SEASTAR_TEST_CASE(test_unused_shared_future_is_not_a_broken_future
) {
726 shared_future
<> s(p
.get_future());
727 return make_ready_future
<>();
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());
735 auto f1
= f
.get_future();
736 auto f2
= f
.get_future();
738 p
.set_value(make_shared
<int>(1));
739 BOOST_REQUIRE(*f1
.get0() == 1);
740 BOOST_REQUIRE(*f2
.get0() == 1);
744 template<typename
... T
>
745 void check_fails_with_expected(future
<T
...> f
) {
748 BOOST_FAIL("Should have failed");
749 } catch (expected_exception
&) {
754 SEASTAR_TEST_CASE(test_shared_future_propagates_value_to_copies
) {
755 return seastar::async([] {
757 auto sf1
= shared_future
<int>(p
.get_future());
760 auto f1
= sf1
.get_future();
761 auto f2
= sf2
.get_future();
765 BOOST_REQUIRE(f1
.get0() == 1);
766 BOOST_REQUIRE(f2
.get0() == 1);
770 SEASTAR_TEST_CASE(test_obtaining_future_from_shared_future_after_it_is_resolved
) {
773 auto sf1
= shared_future
<int>(p1
.get_future());
774 auto sf2
= shared_future
<int>(p2
.get_future());
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);
785 SEASTAR_TEST_CASE(test_valueless_shared_future
) {
786 return seastar::async([] {
788 shared_future
<> f(p
.get_future());
790 auto f1
= f
.get_future();
791 auto f2
= f
.get_future();
800 SEASTAR_TEST_CASE(test_shared_future_propagates_errors_to_all
) {
802 shared_future
<int> f(p
.get_future());
804 auto f1
= f
.get_future();
805 auto f2
= f
.get_future();
807 p
.set_exception(expected_exception());
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
));
817 SEASTAR_TEST_CASE(test_ignored_future_warning
) {
818 // This doesn't warn:
820 p
.set_exception(expected_exception());
821 future
<> f
= p
.get_future();
822 f
.ignore_ready_future();
824 // And by analogy, neither should this
826 p2
.set_exception(expected_exception());
827 future
<> f2
= p2
.get_shared_future();
828 f2
.ignore_ready_future();
829 return make_ready_future
<>();
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
<>();
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
);
847 return make_ready_future
<compat::optional
<int>>(compat::nullopt
);
849 }).then([&counter
] (int result
) {
850 BOOST_REQUIRE(counter
== 10000);
851 BOOST_REQUIRE(result
== counter
);
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
);
864 return compat::optional
<int>(compat::nullopt
);
866 }).then([&counter
] (int result
) {
867 BOOST_REQUIRE(counter
== 10000);
868 BOOST_REQUIRE(result
== counter
);
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
));
882 SEASTAR_TEST_CASE(test_when_allx
) {
883 return when_all(later(), later(), make_ready_future()).discard_result();
886 #if __cplusplus >= 201703L
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;
894 SEASTAR_TEST_CASE(test_when_all_functions
) {
895 auto f
= [x
= non_copy_non_move
{}] {
897 return make_ready_future
<int>(42);
899 return when_all(f
, [] {
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);
905 BOOST_REQUIRE(std::get
<1>(res
).available());
906 BOOST_REQUIRE(std::get
<1>(res
).failed());
907 std::get
<1>(res
).ignore_ready_future();
909 BOOST_REQUIRE(std::get
<2>(res
).available());
910 BOOST_REQUIRE(!std::get
<2>(res
).failed());
911 return make_ready_future
<>();
915 SEASTAR_TEST_CASE(test_when_all_succeed_functions
) {
916 auto f
= [x
= non_copy_non_move
{}] {
918 return make_ready_future
<int>(42);
920 return when_all_succeed(f
, [] {
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
<>();
933 template<typename E
, typename
... T
>
934 static void check_failed_with(future
<T
...>&& f
) {
935 BOOST_REQUIRE(f
.failed());
938 BOOST_FAIL("exception expected");
939 } catch (const E
& e
) {
942 BOOST_FAIL(format("wrong exception: {}", std::current_exception()));
946 template<typename
... T
>
947 static void check_timed_out(future
<T
...>&& f
) {
948 check_failed_with
<timed_out_error
>(std::move(f
));
951 SEASTAR_TEST_CASE(test_with_timeout_when_it_times_out
) {
952 return seastar::async([] {
954 auto f
= with_timeout(manual_clock::now() + 2s
, pr
.get_future());
956 BOOST_REQUIRE(!f
.available());
958 manual_clock::advance(1s
);
961 BOOST_REQUIRE(!f
.available());
963 manual_clock::advance(1s
);
966 check_timed_out(std::move(f
));
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
978 shared_future
<with_clock
<manual_clock
>> sfut(pr
.get_future());
979 future
<> fut1
= sfut
.get_future(manual_clock::now() + 1s
);
981 manual_clock::advance(1s
);
983 check_timed_out(std::move(fut1
));
985 future
<> fut2
= sfut
.get_future(manual_clock::now() + 1s
);
986 manual_clock::advance(1s
);
987 check_timed_out(std::move(fut2
));
989 future
<> fut3
= sfut
.get_future(manual_clock::now() + 1s
);
993 SEASTAR_TEST_CASE(test_custom_exception_factory_in_with_timeout
) {
994 return seastar::async([] {
995 class custom_error
: public std::exception
{
997 virtual const char* what() const noexcept
{
1001 struct my_exception_factory
{
1002 static auto timeout() {
1003 return custom_error();
1007 auto f
= with_timeout
<my_exception_factory
>(manual_clock::now() + 1s
, pr
.get_future());
1009 manual_clock::advance(1s
);
1012 check_failed_with
<custom_error
>(std::move(f
));
1016 SEASTAR_TEST_CASE(test_with_timeout_when_it_does_not_time_out
) {
1017 return seastar::async([] {
1020 auto f
= with_timeout(manual_clock::now() + 1s
, pr
.get_future());
1024 BOOST_REQUIRE_EQUAL(f
.get0(), 42);
1027 // Check that timer was indeed cancelled
1028 manual_clock::advance(1s
);
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();
1040 BOOST_REQUIRE(!f1
.available());
1041 BOOST_REQUIRE(!f2
.available());
1042 BOOST_REQUIRE(!f3
.available());
1044 manual_clock::advance(1s
);
1047 check_timed_out(std::move(f1
));
1048 BOOST_REQUIRE(!f2
.available());
1049 BOOST_REQUIRE(!f3
.available());
1051 manual_clock::advance(1s
);
1054 check_timed_out(std::move(f2
));
1055 BOOST_REQUIRE(!f3
.available());
1059 BOOST_REQUIRE_EQUAL(42, f3
.get0());
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);
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");
1086 }).handle_exception([] (auto excp
) {
1088 std::rethrow_exception(excp
);
1090 BOOST_REQUIRE(v
== 42 || v
== 43);
1094 }).then([] (auto ret
) {
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());
1114 BOOST_FAIL("shouldn't reach");
1116 }).handle_exception([] (auto excp
) {
1118 std::rethrow_exception(excp
);
1120 BOOST_REQUIRE(v
== 42 || v
== 43);
1124 }).then([] (auto ret
) {
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);
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");
1147 }).handle_exception([] (auto excp
) {
1149 std::rethrow_exception(excp
);
1151 BOOST_REQUIRE(v
== 42 || v
== 43);
1155 }).then([] (auto ret
) {
1160 SEASTAR_TEST_CASE(test_futurize_mutable
) {
1162 return seastar::repeat([count
]() mutable {
1165 return seastar::stop_iteration::yes
;
1167 return seastar::stop_iteration::no
;
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
<>();
1177 f2
= f
->then_wrapped([&] (future
<> f3
) {
1178 BOOST_CHECK(f3
.failed());
1179 BOOST_CHECK_THROW(f3
.get(), broken_promise
);
1186 { // Broken before attaching a continuation
1187 auto p
= promise
<>();
1190 f
->then_wrapped([&] (future
<> f3
) {
1191 BOOST_CHECK(f3
.failed());
1192 BOOST_CHECK_THROW(f3
.get(), broken_promise
);
1197 { // Broken before suspending a thread
1198 auto p
= promise
<>();
1201 BOOST_CHECK_THROW(f
->get(), broken_promise
);
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.
1209 // Intentionally destroy the future
1210 (void)p
.get_future();
1211 p
.set_exception(std::runtime_error("foo"));
1212 return make_ready_future
<>();