]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/tests/unit/futures_test.cc
update download target update for octopus release
[ceph.git] / ceph / src / seastar / tests / unit / futures_test.cc
CommitLineData
11fdf7f2
TL
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 <boost/iterator/counting_iterator.hpp>
31
32using namespace seastar;
33using namespace std::chrono_literals;
34
35class expected_exception : std::runtime_error {
36public:
37 expected_exception() : runtime_error("expected") {}
38};
39
40SEASTAR_TEST_CASE(test_finally_is_called_on_success_and_failure) {
41 auto finally1 = make_shared<bool>();
42 auto finally2 = make_shared<bool>();
43
44 return make_ready_future().then([] {
45 }).finally([=] {
46 *finally1 = true;
47 }).then([] {
48 throw std::runtime_error("");
49 }).finally([=] {
50 *finally2 = true;
51 }).then_wrapped([=] (auto&& f) {
52 BOOST_REQUIRE(*finally1);
53 BOOST_REQUIRE(*finally2);
54
55 // Should be failed.
56 try {
57 f.get();
58 BOOST_REQUIRE(false);
59 } catch (...) {}
60 });
61}
62
63SEASTAR_TEST_CASE(test_get_on_promise) {
64 auto p = promise<uint32_t>();
65 p.set_value(10);
66 BOOST_REQUIRE_EQUAL(10u, p.get_future().get0());
67 return make_ready_future();
68}
69
70SEASTAR_TEST_CASE(test_finally_waits_for_inner) {
71 auto finally = make_shared<bool>();
72 auto p = make_shared<promise<>>();
73
74 auto f = make_ready_future().then([] {
75 }).finally([=] {
76 return p->get_future().then([=] {
77 *finally = true;
78 });
79 }).then([=] {
80 BOOST_REQUIRE(*finally);
81 });
82 BOOST_REQUIRE(!*finally);
83 p->set_value();
84 return f;
85}
86
87SEASTAR_TEST_CASE(test_finally_is_called_on_success_and_failure__not_ready_to_armed) {
88 auto finally1 = make_shared<bool>();
89 auto finally2 = make_shared<bool>();
90
91 promise<> p;
92 auto f = p.get_future().finally([=] {
93 *finally1 = true;
94 }).then([] {
95 throw std::runtime_error("");
96 }).finally([=] {
97 *finally2 = true;
98 }).then_wrapped([=] (auto &&f) {
99 BOOST_REQUIRE(*finally1);
100 BOOST_REQUIRE(*finally2);
101 try {
102 f.get();
103 } catch (...) {} // silence exceptional future ignored messages
104 });
105
106 p.set_value();
107 return f;
108}
109
110SEASTAR_TEST_CASE(test_exception_from_finally_fails_the_target) {
111 promise<> pr;
112 auto f = pr.get_future().finally([=] {
113 throw std::runtime_error("");
114 }).then([] {
115 BOOST_REQUIRE(false);
116 }).then_wrapped([] (auto&& f) {
117 try {
118 f.get();
119 } catch (...) {} // silence exceptional future ignored messages
120 });
121
122 pr.set_value();
123 return f;
124}
125
126SEASTAR_TEST_CASE(test_exception_from_finally_fails_the_target_on_already_resolved) {
127 return make_ready_future().finally([=] {
128 throw std::runtime_error("");
129 }).then([] {
130 BOOST_REQUIRE(false);
131 }).then_wrapped([] (auto&& f) {
132 try {
133 f.get();
134 } catch (...) {} // silence exceptional future ignored messages
135 });
136}
137
138SEASTAR_TEST_CASE(test_exception_thrown_from_then_wrapped_causes_future_to_fail) {
139 return make_ready_future().then_wrapped([] (auto&& f) {
140 throw std::runtime_error("");
141 }).then_wrapped([] (auto&& f) {
142 try {
143 f.get();
144 BOOST_REQUIRE(false);
145 } catch (...) {}
146 });
147}
148
149SEASTAR_TEST_CASE(test_exception_thrown_from_then_wrapped_causes_future_to_fail__async_case) {
150 promise<> p;
151
152 auto f = p.get_future().then_wrapped([] (auto&& f) {
153 throw std::runtime_error("");
154 }).then_wrapped([] (auto&& f) {
155 try {
156 f.get();
157 BOOST_REQUIRE(false);
158 } catch (...) {}
159 });
160
161 p.set_value();
162
163 return f;
164}
165
166SEASTAR_TEST_CASE(test_failing_intermediate_promise_should_fail_the_master_future) {
167 promise<> p1;
168 promise<> p2;
169
170 auto f = p1.get_future().then([f = std::move(p2.get_future())] () mutable {
171 return std::move(f);
172 }).then([] {
173 BOOST_REQUIRE(false);
174 });
175
176 p1.set_value();
177 p2.set_exception(std::runtime_error("boom"));
178
179 return std::move(f).then_wrapped([](auto&& f) {
180 try {
181 f.get();
182 BOOST_REQUIRE(false);
183 } catch (...) {}
184 });
185}
186
187SEASTAR_TEST_CASE(test_future_forwarding__not_ready_to_unarmed) {
188 promise<> p1;
189 promise<> p2;
190
191 auto f1 = p1.get_future();
192 auto f2 = p2.get_future();
193
194 f1.forward_to(std::move(p2));
195
196 BOOST_REQUIRE(!f2.available());
197
198 auto called = f2.then([] {});
199
200 p1.set_value();
201 return called;
202}
203
204SEASTAR_TEST_CASE(test_future_forwarding__not_ready_to_armed) {
205 promise<> p1;
206 promise<> p2;
207
208 auto f1 = p1.get_future();
209 auto f2 = p2.get_future();
210
211 auto called = f2.then([] {});
212
213 f1.forward_to(std::move(p2));
214
215 BOOST_REQUIRE(!f2.available());
216
217 p1.set_value();
218
219 return called;
220}
221
222SEASTAR_TEST_CASE(test_future_forwarding__ready_to_unarmed) {
223 promise<> p2;
224
225 auto f1 = make_ready_future<>();
226 auto f2 = p2.get_future();
227
228 std::move(f1).forward_to(std::move(p2));
229 BOOST_REQUIRE(f2.available());
230
231 return std::move(f2).then_wrapped([] (future<> f) {
232 BOOST_REQUIRE(!f.failed());
233 });
234}
235
236SEASTAR_TEST_CASE(test_future_forwarding__ready_to_armed) {
237 promise<> p2;
238
239 auto f1 = make_ready_future<>();
240 auto f2 = p2.get_future();
241
242 auto called = std::move(f2).then([] {});
243
244 BOOST_REQUIRE(f1.available());
245
246 f1.forward_to(std::move(p2));
247 return called;
248}
249
250static void forward_dead_unarmed_promise_with_dead_future_to(promise<>& p) {
251 promise<> p2;
252 p.get_future().forward_to(std::move(p2));
253}
254
255SEASTAR_TEST_CASE(test_future_forwarding__ready_to_unarmed_soon_to_be_dead) {
256 promise<> p1;
257 forward_dead_unarmed_promise_with_dead_future_to(p1);
258 make_ready_future<>().forward_to(std::move(p1));
259 return make_ready_future<>();
260}
261
262SEASTAR_TEST_CASE(test_exception_can_be_thrown_from_do_until_body) {
263 return do_until([] { return false; }, [] {
264 throw expected_exception();
265 return now();
266 }).then_wrapped([] (auto&& f) {
267 try {
268 f.get();
269 BOOST_FAIL("should have failed");
270 } catch (const expected_exception& e) {
271 // expected
272 }
273 });
274}
275
276SEASTAR_TEST_CASE(test_bare_value_can_be_returned_from_callback) {
277 return now().then([] {
278 return 3;
279 }).then([] (int x) {
280 BOOST_REQUIRE(x == 3);
281 });
282}
283
284SEASTAR_TEST_CASE(test_when_all_iterator_range) {
285 std::vector<future<size_t>> futures;
286 for (size_t i = 0; i != 1000000; ++i) {
287 // .then() usually returns a ready future, but sometimes it
288 // doesn't, so call it a million times. This exercises both
289 // available and unavailable paths in when_all().
290 futures.push_back(make_ready_future<>().then([i] { return i; }));
291 }
292 // Verify the above statement is correct
293 BOOST_REQUIRE(!std::all_of(futures.begin(), futures.end(),
294 [] (auto& f) { return f.available(); }));
295 auto p = make_shared(std::move(futures));
296 return when_all(p->begin(), p->end()).then([p] (std::vector<future<size_t>> ret) {
297 BOOST_REQUIRE(std::all_of(ret.begin(), ret.end(), [] (auto& f) { return f.available(); }));
298 BOOST_REQUIRE(std::all_of(ret.begin(), ret.end(), [&ret] (auto& f) { return std::get<0>(f.get()) == size_t(&f - ret.data()); }));
299 });
300}
301
302SEASTAR_TEST_CASE(test_map_reduce) {
303 auto square = [] (long x) { return make_ready_future<long>(x*x); };
304 long n = 1000;
305 return map_reduce(boost::make_counting_iterator<long>(0), boost::make_counting_iterator<long>(n),
306 square, long(0), std::plus<long>()).then([n] (auto result) {
307 auto m = n - 1; // counting does not include upper bound
308 BOOST_REQUIRE_EQUAL(result, (m * (m + 1) * (2*m + 1)) / 6);
309 });
310}
311
312// This test doesn't actually test anything - it just waits for the future
313// returned by sleep to complete. However, a bug we had in sleep() caused
314// this test to fail the sanitizer in the debug build, so this is a useful
315// regression test.
316SEASTAR_TEST_CASE(test_sleep) {
317 return sleep(std::chrono::milliseconds(100));
318}
319
320SEASTAR_TEST_CASE(test_do_with_1) {
321 return do_with(1, [] (int& one) {
322 BOOST_REQUIRE_EQUAL(one, 1);
323 return make_ready_future<>();
324 });
325}
326
327SEASTAR_TEST_CASE(test_do_with_2) {
328 return do_with(1, 2L, [] (int& one, long two) {
329 BOOST_REQUIRE_EQUAL(one, 1);
330 BOOST_REQUIRE_EQUAL(two, 2);
331 return make_ready_future<>();
332 });
333}
334
335SEASTAR_TEST_CASE(test_do_with_3) {
336 return do_with(1, 2L, 3, [] (int& one, long two, int three) {
337 BOOST_REQUIRE_EQUAL(one, 1);
338 BOOST_REQUIRE_EQUAL(two, 2);
339 BOOST_REQUIRE_EQUAL(three, 3);
340 return make_ready_future<>();
341 });
342}
343
344SEASTAR_TEST_CASE(test_do_with_4) {
345 return do_with(1, 2L, 3, 4, [] (int& one, long two, int three, int four) {
346 BOOST_REQUIRE_EQUAL(one, 1);
347 BOOST_REQUIRE_EQUAL(two, 2);
348 BOOST_REQUIRE_EQUAL(three, 3);
349 BOOST_REQUIRE_EQUAL(four, 4);
350 return make_ready_future<>();
351 });
352}
353
354SEASTAR_TEST_CASE(test_do_while_stopping_immediately) {
355 return do_with(int(0), [] (int& count) {
356 return repeat([&count] {
357 ++count;
358 return stop_iteration::yes;
359 }).then([&count] {
360 BOOST_REQUIRE(count == 1);
361 });
362 });
363}
364
365SEASTAR_TEST_CASE(test_do_while_stopping_after_two_iterations) {
366 return do_with(int(0), [] (int& count) {
367 return repeat([&count] {
368 ++count;
369 return count == 2 ? stop_iteration::yes : stop_iteration::no;
370 }).then([&count] {
371 BOOST_REQUIRE(count == 2);
372 });
373 });
374}
375
376SEASTAR_TEST_CASE(test_do_while_failing_in_the_first_step) {
377 return repeat([] {
378 throw expected_exception();
379 return stop_iteration::no;
380 }).then_wrapped([](auto&& f) {
381 try {
382 f.get();
383 BOOST_FAIL("should not happen");
384 } catch (const expected_exception&) {
385 // expected
386 }
387 });
388}
389
390SEASTAR_TEST_CASE(test_do_while_failing_in_the_second_step) {
391 return do_with(int(0), [] (int& count) {
392 return repeat([&count] {
393 ++count;
394 if (count > 1) {
395 throw expected_exception();
396 }
397 return later().then([] { return stop_iteration::no; });
398 }).then_wrapped([&count](auto&& f) {
399 try {
400 f.get();
401 BOOST_FAIL("should not happen");
402 } catch (const expected_exception&) {
403 BOOST_REQUIRE(count == 2);
404 }
405 });
406 });
407}
408
409SEASTAR_TEST_CASE(test_parallel_for_each) {
410 return async([] {
411 // empty
412 parallel_for_each(std::vector<int>(), [] (int) -> future<> {
413 BOOST_FAIL("should not reach");
414 abort();
415 }).get();
416
417 // immediate result
418 auto range = boost::copy_range<std::vector<int>>(boost::irange(1, 6));
419 auto sum = 0;
420 parallel_for_each(range, [&sum] (int v) {
421 sum += v;
422 return make_ready_future<>();
423 }).get();
424 BOOST_REQUIRE_EQUAL(sum, 15);
425
426 // all suspend
427 sum = 0;
428 parallel_for_each(range, [&sum] (int v) {
429 return later().then([&sum, v] {
430 sum += v;
431 });
432 }).get();
433 BOOST_REQUIRE_EQUAL(sum, 15);
434
435 // throws immediately
436 BOOST_CHECK_EXCEPTION(parallel_for_each(range, [&sum] (int) -> future<> {
437 throw 5;
438 }).get(), int, [] (int v) { return v == 5; });
439
440 // throws after suspension
441 BOOST_CHECK_EXCEPTION(parallel_for_each(range, [&sum] (int) {
442 return later().then([] {
443 throw 5;
444 });
445 }).get(), int, [] (int v) { return v == 5; });
446 });
447}
448
449SEASTAR_TEST_CASE(test_parallel_for_each_early_failure) {
450 return do_with(0, [] (int& counter) {
451 return parallel_for_each(boost::irange(0, 11000), [&counter] (int i) {
452 using namespace std::chrono_literals;
453 // force scheduling
454 return sleep((i % 31 + 1) * 1ms).then([&counter, i] {
455 ++counter;
456 if (i % 1777 == 1337) {
457 return make_exception_future<>(i);
458 }
459 return make_ready_future<>();
460 });
461 }).then_wrapped([&counter] (future<> f) {
462 BOOST_REQUIRE_EQUAL(counter, 11000);
463 BOOST_REQUIRE(f.failed());
464 try {
465 f.get();
466 BOOST_FAIL("wanted an exception");
467 } catch (int i) {
468 BOOST_REQUIRE(i % 1777 == 1337);
469 } catch (...) {
470 BOOST_FAIL("bad exception type");
471 }
472 });
473 });
474}
475
476SEASTAR_TEST_CASE(test_parallel_for_each_waits_for_all_fibers_even_if_one_of_them_failed) {
477 auto can_exit = make_lw_shared<bool>(false);
478 return parallel_for_each(boost::irange(0, 2), [can_exit] (int i) {
479 return later().then([i, can_exit] {
480 if (i == 1) {
481 throw expected_exception();
482 } else {
483 using namespace std::chrono_literals;
484 return sleep(300ms).then([can_exit] {
485 *can_exit = true;
486 });
487 }
488 });
489 }).then_wrapped([can_exit] (auto&& f) {
490 try {
491 f.get();
492 } catch (...) {
493 // expected
494 }
495 BOOST_REQUIRE(*can_exit);
496 });
497}
498
499#ifndef SEASTAR_SHUFFLE_TASK_QUEUE
500SEASTAR_TEST_CASE(test_high_priority_task_runs_before_ready_continuations) {
501 return now().then([] {
502 auto flag = make_lw_shared<bool>(false);
503 engine().add_high_priority_task(make_task([flag] {
504 *flag = true;
505 }));
506 make_ready_future().then([flag] {
507 BOOST_REQUIRE(*flag);
508 });
509 });
510}
511
512SEASTAR_TEST_CASE(test_high_priority_task_runs_in_the_middle_of_loops) {
513 auto counter = make_lw_shared<int>(0);
514 auto flag = make_lw_shared<bool>(false);
515 return repeat([counter, flag] {
516 if (*counter == 1) {
517 BOOST_REQUIRE(*flag);
518 return stop_iteration::yes;
519 }
520 engine().add_high_priority_task(make_task([flag] {
521 *flag = true;
522 }));
523 ++(*counter);
524 return stop_iteration::no;
525 });
526}
527#endif
528
529SEASTAR_TEST_CASE(futurize_apply_val_exception) {
530 return futurize<int>::apply([] (int arg) { throw expected_exception(); return arg; }, 1).then_wrapped([] (future<int> f) {
531 try {
532 f.get();
533 BOOST_FAIL("should have thrown");
534 } catch (expected_exception& e) {}
535 });
536}
537
538SEASTAR_TEST_CASE(futurize_apply_val_ok) {
539 return futurize<int>::apply([] (int arg) { return arg * 2; }, 2).then_wrapped([] (future<int> f) {
540 try {
541 auto x = f.get0();
542 BOOST_REQUIRE_EQUAL(x, 4);
543 } catch (expected_exception& e) {
544 BOOST_FAIL("should not have thrown");
545 }
546 });
547}
548
549SEASTAR_TEST_CASE(futurize_apply_val_future_exception) {
550 return futurize<int>::apply([] (int a) {
551 return sleep(std::chrono::milliseconds(100)).then([] {
552 throw expected_exception();
553 return make_ready_future<int>(0);
554 });
555 }, 0).then_wrapped([] (future<int> f) {
556 try {
557 f.get();
558 BOOST_FAIL("should have thrown");
559 } catch (expected_exception& e) { }
560 });
561}
562
563SEASTAR_TEST_CASE(futurize_apply_val_future_ok) {
564 return futurize<int>::apply([] (int a) {
565 return sleep(std::chrono::milliseconds(100)).then([a] {
566 return make_ready_future<int>(a * 100);
567 });
568 }, 2).then_wrapped([] (future<int> f) {
569 try {
570 auto x = f.get0();
571 BOOST_REQUIRE_EQUAL(x, 200);
572 } catch (expected_exception& e) {
573 BOOST_FAIL("should not have thrown");
574 }
575 });
576}
577SEASTAR_TEST_CASE(futurize_apply_void_exception) {
578 return futurize<void>::apply([] (auto arg) { throw expected_exception(); }, 0).then_wrapped([] (future<> f) {
579 try {
580 f.get();
581 BOOST_FAIL("should have thrown");
582 } catch (expected_exception& e) {}
583 });
584}
585
586SEASTAR_TEST_CASE(futurize_apply_void_ok) {
587 return futurize<void>::apply([] (auto arg) { }, 0).then_wrapped([] (future<> f) {
588 try {
589 f.get();
590 } catch (expected_exception& e) {
591 BOOST_FAIL("should not have thrown");
592 }
593 });
594}
595
596SEASTAR_TEST_CASE(futurize_apply_void_future_exception) {
597 return futurize<void>::apply([] (auto a) {
598 return sleep(std::chrono::milliseconds(100)).then([] {
599 throw expected_exception();
600 });
601 }, 0).then_wrapped([] (future<> f) {
602 try {
603 f.get();
604 BOOST_FAIL("should have thrown");
605 } catch (expected_exception& e) { }
606 });
607}
608
609SEASTAR_TEST_CASE(futurize_apply_void_future_ok) {
610 auto a = make_lw_shared<int>(1);
611 return futurize<void>::apply([] (int& a) {
612 return sleep(std::chrono::milliseconds(100)).then([&a] {
613 a *= 100;
614 });
615 }, *a).then_wrapped([a] (future<> f) {
616 try {
617 f.get();
618 BOOST_REQUIRE_EQUAL(*a, 100);
619 } catch (expected_exception& e) {
620 BOOST_FAIL("should not have thrown");
621 }
622 });
623}
624
625SEASTAR_TEST_CASE(test_shared_future_propagates_value_to_all) {
626 return seastar::async([] {
627 promise<shared_ptr<int>> p; // shared_ptr<> to check it deals with emptyable types
628 shared_future<shared_ptr<int>> f(p.get_future());
629
630 auto f1 = f.get_future();
631 auto f2 = f.get_future();
632
633 p.set_value(make_shared<int>(1));
634 BOOST_REQUIRE(*f1.get0() == 1);
635 BOOST_REQUIRE(*f2.get0() == 1);
636 });
637}
638
639template<typename... T>
640void check_fails_with_expected(future<T...> f) {
641 try {
642 f.get();
643 BOOST_FAIL("Should have failed");
644 } catch (expected_exception&) {
645 // expected
646 }
647}
648
649SEASTAR_TEST_CASE(test_shared_future_propagates_value_to_copies) {
650 return seastar::async([] {
651 promise<int> p;
652 auto sf1 = shared_future<int>(p.get_future());
653 auto sf2 = sf1;
654
655 auto f1 = sf1.get_future();
656 auto f2 = sf2.get_future();
657
658 p.set_value(1);
659
660 BOOST_REQUIRE(f1.get0() == 1);
661 BOOST_REQUIRE(f2.get0() == 1);
662 });
663}
664
665SEASTAR_TEST_CASE(test_obtaining_future_from_shared_future_after_it_is_resolved) {
666 promise<int> p1;
667 promise<int> p2;
668 auto sf1 = shared_future<int>(p1.get_future());
669 auto sf2 = shared_future<int>(p2.get_future());
670 p1.set_value(1);
671 p2.set_exception(expected_exception());
672 return sf2.get_future().then_wrapped([f1 = sf1.get_future()] (auto&& f) mutable {
673 check_fails_with_expected(std::move(f));
674 return std::move(f1);
675 }).then_wrapped([] (auto&& f) {
676 BOOST_REQUIRE(f.get0() == 1);
677 });
678}
679
680SEASTAR_TEST_CASE(test_valueless_shared_future) {
681 return seastar::async([] {
682 promise<> p;
683 shared_future<> f(p.get_future());
684
685 auto f1 = f.get_future();
686 auto f2 = f.get_future();
687
688 p.set_value();
689
690 f1.get();
691 f2.get();
692 });
693}
694
695SEASTAR_TEST_CASE(test_shared_future_propagates_errors_to_all) {
696 promise<int> p;
697 shared_future<int> f(p.get_future());
698
699 auto f1 = f.get_future();
700 auto f2 = f.get_future();
701
702 p.set_exception(expected_exception());
703
704 return f1.then_wrapped([f2 = std::move(f2)] (auto&& f) mutable {
705 check_fails_with_expected(std::move(f));
706 return std::move(f2);
707 }).then_wrapped([] (auto&& f) mutable {
708 check_fails_with_expected(std::move(f));
709 });
710}
711
712SEASTAR_TEST_CASE(test_futurize_from_tuple) {
713 std::tuple<int> v1 = std::make_tuple(3);
714 std::tuple<> v2 = {};
715 BOOST_REQUIRE(futurize<int>::from_tuple(v1).get() == v1);
716 BOOST_REQUIRE(futurize<void>::from_tuple(v2).get() == v2);
717 return make_ready_future<>();
718}
719
720SEASTAR_TEST_CASE(test_repeat_until_value) {
721 return do_with(int(), [] (int& counter) {
722 return repeat_until_value([&counter] () -> future<compat::optional<int>> {
723 if (counter == 10000) {
724 return make_ready_future<compat::optional<int>>(counter);
725 } else {
726 ++counter;
727 return make_ready_future<compat::optional<int>>(compat::nullopt);
728 }
729 }).then([&counter] (int result) {
730 BOOST_REQUIRE(counter == 10000);
731 BOOST_REQUIRE(result == counter);
732 });
733 });
734}
735
736SEASTAR_TEST_CASE(test_when_allx) {
737 return when_all(later(), later(), make_ready_future()).discard_result();
738}
739
740template<typename E, typename... T>
741static void check_failed_with(future<T...>&& f) {
742 BOOST_REQUIRE(f.failed());
743 try {
744 f.get();
745 BOOST_FAIL("exception expected");
746 } catch (const E& e) {
747 // expected
748 } catch (...) {
749 BOOST_FAIL(format("wrong exception: {}", std::current_exception()));
750 }
751}
752
753template<typename... T>
754static void check_timed_out(future<T...>&& f) {
755 check_failed_with<timed_out_error>(std::move(f));
756}
757
758SEASTAR_TEST_CASE(test_with_timeout_when_it_times_out) {
759 return seastar::async([] {
760 promise<> pr;
761 auto f = with_timeout(manual_clock::now() + 2s, pr.get_future());
762
763 BOOST_REQUIRE(!f.available());
764
765 manual_clock::advance(1s);
766 later().get();
767
768 BOOST_REQUIRE(!f.available());
769
770 manual_clock::advance(1s);
771 later().get();
772
773 check_timed_out(std::move(f));
774
775 pr.set_value();
776 });
777}
778
779SEASTAR_TEST_CASE(test_custom_exception_factory_in_with_timeout) {
780 return seastar::async([] {
781 class custom_error : public std::exception {
782 public:
783 virtual const char* what() const noexcept {
784 return "timedout";
785 }
786 };
787 struct my_exception_factory {
788 static auto timeout() {
789 return custom_error();
790 }
791 };
792 promise<> pr;
793 auto f = with_timeout<my_exception_factory>(manual_clock::now() + 1s, pr.get_future());
794
795 manual_clock::advance(1s);
796 later().get();
797
798 check_failed_with<custom_error>(std::move(f));
799 });
800}
801
802SEASTAR_TEST_CASE(test_with_timeout_when_it_does_not_time_out) {
803 return seastar::async([] {
804 {
805 promise<int> pr;
806 auto f = with_timeout(manual_clock::now() + 1s, pr.get_future());
807
808 pr.set_value(42);
809
810 BOOST_REQUIRE_EQUAL(f.get0(), 42);
811 }
812
813 // Check that timer was indeed cancelled
814 manual_clock::advance(1s);
815 later().get();
816 });
817}
818
819SEASTAR_TEST_CASE(test_shared_future_with_timeout) {
820 return seastar::async([] {
821 shared_promise<with_clock<manual_clock>, int> pr;
822 auto f1 = pr.get_shared_future(manual_clock::now() + 1s);
823 auto f2 = pr.get_shared_future(manual_clock::now() + 2s);
824 auto f3 = pr.get_shared_future();
825
826 BOOST_REQUIRE(!f1.available());
827 BOOST_REQUIRE(!f2.available());
828 BOOST_REQUIRE(!f3.available());
829
830 manual_clock::advance(1s);
831 later().get();
832
833 check_timed_out(std::move(f1));
834 BOOST_REQUIRE(!f2.available());
835 BOOST_REQUIRE(!f3.available());
836
837 manual_clock::advance(1s);
838 later().get();
839
840 check_timed_out(std::move(f2));
841 BOOST_REQUIRE(!f3.available());
842
843 pr.set_value(42);
844
845 BOOST_REQUIRE_EQUAL(42, f3.get0());
846 });
847}
848
849SEASTAR_TEST_CASE(test_when_all_succeed_tuples) {
850 return seastar::when_all_succeed(
851 make_ready_future<>(),
852 make_ready_future<sstring>("hello world"),
853 make_ready_future<int>(42),
854 make_ready_future<>(),
855 make_ready_future<int, sstring>(84, "hi"),
856 make_ready_future<bool>(true)
857 ).then([] (sstring msg, int v, std::tuple<int, sstring> t, bool b) {
858 BOOST_REQUIRE_EQUAL(msg, "hello world");
859 BOOST_REQUIRE_EQUAL(v, 42);
860 BOOST_REQUIRE_EQUAL(std::get<0>(t), 84);
861 BOOST_REQUIRE_EQUAL(std::get<1>(t), "hi");
862 BOOST_REQUIRE_EQUAL(b, true);
863
864 return seastar::when_all_succeed(
865 make_exception_future<>(42),
866 make_ready_future<sstring>("hello world"),
867 make_exception_future<int>(43),
868 make_ready_future<>()
869 ).then([] (sstring, int) {
870 BOOST_FAIL("shouldn't reach");
871 return false;
872 }).handle_exception([] (auto excp) {
873 try {
874 std::rethrow_exception(excp);
875 } catch (int v) {
876 BOOST_REQUIRE(v == 42 || v == 43);
877 return true;
878 } catch (...) { }
879 return false;
880 }).then([] (auto ret) {
881 BOOST_REQUIRE(ret);
882 });
883 });
884}
885
886SEASTAR_TEST_CASE(test_when_all_succeed_vector) {
887 std::vector<future<>> vecs;
888 vecs.emplace_back(make_ready_future<>());
889 vecs.emplace_back(make_ready_future<>());
890 vecs.emplace_back(make_ready_future<>());
891 vecs.emplace_back(make_ready_future<>());
892 return seastar::when_all_succeed(vecs.begin(), vecs.end()).then([] {
893 std::vector<future<>> vecs;
894 vecs.emplace_back(make_ready_future<>());
895 vecs.emplace_back(make_ready_future<>());
896 vecs.emplace_back(make_exception_future<>(42));
897 vecs.emplace_back(make_exception_future<>(43));
898 return seastar::when_all_succeed(vecs.begin(), vecs.end());
899 }).then([] {
900 BOOST_FAIL("shouldn't reach");
901 return false;
902 }).handle_exception([] (auto excp) {
903 try {
904 std::rethrow_exception(excp);
905 } catch (int v) {
906 BOOST_REQUIRE(v == 42 || v == 43);
907 return true;
908 } catch (...) { }
909 return false;
910 }).then([] (auto ret) {
911 BOOST_REQUIRE(ret);
912
913 std::vector<future<int>> vecs;
914 vecs.emplace_back(make_ready_future<int>(1));
915 vecs.emplace_back(make_ready_future<int>(2));
916 vecs.emplace_back(make_ready_future<int>(3));
917 return seastar::when_all_succeed(vecs.begin(), vecs.end());
918 }).then([] (std::vector<int> vals) {
919 BOOST_REQUIRE_EQUAL(vals.size(), 3u);
920 BOOST_REQUIRE_EQUAL(vals[0], 1);
921 BOOST_REQUIRE_EQUAL(vals[1], 2);
922 BOOST_REQUIRE_EQUAL(vals[2], 3);
923
924 std::vector<future<int>> vecs;
925 vecs.emplace_back(make_ready_future<int>(1));
926 vecs.emplace_back(make_ready_future<int>(2));
927 vecs.emplace_back(make_exception_future<int>(42));
928 vecs.emplace_back(make_exception_future<int>(43));
929 return seastar::when_all_succeed(vecs.begin(), vecs.end());
930 }).then([] (std::vector<int>) {
931 BOOST_FAIL("shouldn't reach");
932 return false;
933 }).handle_exception([] (auto excp) {
934 try {
935 std::rethrow_exception(excp);
936 } catch (int v) {
937 BOOST_REQUIRE(v == 42 || v == 43);
938 return true;
939 } catch (...) { }
940 return false;
941 }).then([] (auto ret) {
942 BOOST_REQUIRE(ret);
943 });
944}
945
946SEASTAR_TEST_CASE(test_futurize_mutable) {
947 int count = 0;
948 return seastar::repeat([count]() mutable {
949 ++count;
950 if (count == 3) {
951 return seastar::stop_iteration::yes;
952 }
953 return seastar::stop_iteration::no;
954 });
955}