]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/tests/unit/futures_test.cc
update ceph source to reef 18.1.2
[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
20effc67
TL
22#include <cstddef>
23#include <exception>
11fdf7f2
TL
24#include <seastar/testing/test_case.hh>
25
f67539c2 26#include <seastar/core/reactor.hh>
11fdf7f2
TL
27#include <seastar/core/shared_ptr.hh>
28#include <seastar/core/future-util.hh>
29#include <seastar/core/sleep.hh>
f67539c2
TL
30#include <seastar/core/stream.hh>
31#include <seastar/util/backtrace.hh>
11fdf7f2
TL
32#include <seastar/core/do_with.hh>
33#include <seastar/core/shared_future.hh>
f67539c2 34#include <seastar/core/manual_clock.hh>
11fdf7f2 35#include <seastar/core/thread.hh>
9f95a23c 36#include <seastar/core/print.hh>
20effc67 37#include <seastar/core/when_any.hh>
1e59de90 38#include <seastar/core/when_all.hh>
f67539c2
TL
39#include <seastar/core/gate.hh>
40#include <seastar/util/log.hh>
1e59de90 41#include <seastar/util/later.hh>
11fdf7f2 42#include <boost/iterator/counting_iterator.hpp>
9f95a23c 43#include <seastar/testing/thread_test_case.hh>
11fdf7f2 44
f67539c2
TL
45#include <boost/range/iterator_range.hpp>
46#include <boost/range/irange.hpp>
47
48#include <seastar/core/internal/api-level.hh>
20effc67
TL
49#include <stdexcept>
50#include <unistd.h>
f67539c2 51
11fdf7f2
TL
52using namespace seastar;
53using namespace std::chrono_literals;
54
f67539c2
TL
55static_assert(std::is_nothrow_default_constructible_v<gate>,
56 "seastar::gate constructor must not throw");
57static_assert(std::is_nothrow_move_constructible_v<gate>,
58 "seastar::gate move constructor must not throw");
59
60static_assert(std::is_nothrow_default_constructible_v<shared_future<>>);
61static_assert(std::is_nothrow_copy_constructible_v<shared_future<>>);
62static_assert(std::is_nothrow_move_constructible_v<shared_future<>>);
63
64static_assert(std::is_nothrow_move_constructible_v<shared_promise<>>);
65
66class expected_exception : public std::runtime_error {
11fdf7f2
TL
67public:
68 expected_exception() : runtime_error("expected") {}
69};
70
9f95a23c
TL
71#ifdef __clang__
72#pragma clang diagnostic push
73#pragma clang diagnostic ignored "-Wself-move"
74#endif
75SEASTAR_TEST_CASE(test_self_move) {
f67539c2 76 future_state<std::tuple<std::unique_ptr<int>>> s1;
9f95a23c
TL
77 s1.set(std::make_unique<int>(42));
78 s1 = std::move(s1); // no crash, but the value of s1 is not defined.
79
f67539c2
TL
80#if SEASTAR_API_LEVEL < 5
81 future_state<std::tuple<std::unique_ptr<int>>> s2;
82#else
9f95a23c 83 future_state<std::unique_ptr<int>> s2;
f67539c2 84#endif
9f95a23c
TL
85 s2.set(std::make_unique<int>(42));
86 std::swap(s2, s2);
f67539c2 87 BOOST_REQUIRE_EQUAL(*std::move(s2).get0(), 42);
9f95a23c
TL
88
89 promise<std::unique_ptr<int>> p1;
90 p1.set_value(std::make_unique<int>(42));
91 p1 = std::move(p1); // no crash, but the value of p1 is not defined.
92
93 promise<std::unique_ptr<int>> p2;
94 p2.set_value(std::make_unique<int>(42));
95 std::swap(p2, p2);
96 BOOST_REQUIRE_EQUAL(*p2.get_future().get0(), 42);
97
98 auto f1 = make_ready_future<std::unique_ptr<int>>(std::make_unique<int>(42));
99 f1 = std::move(f1); // no crash, but the value of f1 is not defined.
100
101 auto f2 = make_ready_future<std::unique_ptr<int>>(std::make_unique<int>(42));
102 std::swap(f2, f2);
103 BOOST_REQUIRE_EQUAL(*f2.get0(), 42);
104
105 return make_ready_future<>();
106}
107#ifdef __clang__
108#pragma clang diagnostic pop
109#endif
110
111static subscription<int> get_empty_subscription(std::function<future<> (int)> func) {
112 stream<int> s;
113 auto ret = s.listen(func);
114 s.close();
115 return ret;
116}
117
118SEASTAR_TEST_CASE(test_stream) {
119 auto sub = get_empty_subscription([](int x) {
120 return make_ready_future<>();
121 });
122 return sub.done();
123}
124
125SEASTAR_TEST_CASE(test_stream_drop_sub) {
126 auto s = make_lw_shared<stream<int>>();
f67539c2 127 std::optional<future<>> ret;
9f95a23c
TL
128 {
129 auto sub = s->listen([](int x) {
130 return make_ready_future<>();
131 });
f67539c2 132 ret = sub.done();
9f95a23c
TL
133 // It is ok to drop the subscription when we only want the competition future.
134 }
135 return s->produce(42).then([ret = std::move(*ret), s] () mutable {
136 s->close();
137 return std::move(ret);
138 });
139}
140
f67539c2
TL
141SEASTAR_TEST_CASE(test_reference) {
142 int a = 42;
143 future<int&> orig = make_ready_future<int&>(a);
144 future<int&> fut = std::move(orig);
145 int& r = fut.get0();
146 r = 43;
147 BOOST_REQUIRE_EQUAL(a, 43);
148 return make_ready_future<>();
149}
150
9f95a23c 151SEASTAR_TEST_CASE(test_set_future_state_with_tuple) {
f67539c2 152 future_state<std::tuple<int>> s1;
9f95a23c
TL
153 promise<int> p1;
154 const std::tuple<int> v1(42);
155 s1.set(v1);
156 p1.set_value(v1);
157
9f95a23c
TL
158 return make_ready_future<>();
159}
160
f67539c2 161SEASTAR_THREAD_TEST_CASE(test_set_value_make_exception_in_copy) {
9f95a23c
TL
162 struct throw_in_copy {
163 throw_in_copy() noexcept = default;
164 throw_in_copy(throw_in_copy&& x) noexcept {
165 }
166 throw_in_copy(const throw_in_copy& x) {
167 throw 42;
168 }
169 };
170 promise<throw_in_copy> p1;
171 throw_in_copy v;
f67539c2
TL
172 p1.set_value(v);
173 BOOST_REQUIRE_THROW(p1.get_future().get(), int);
174}
175
176SEASTAR_THREAD_TEST_CASE(test_set_exception_in_constructor) {
177 struct throw_in_constructor {
178 throw_in_constructor() {
179 throw 42;
180 }
181 };
182 future<throw_in_constructor> f = make_ready_future<throw_in_constructor>();
183 BOOST_REQUIRE(f.failed());
184 BOOST_REQUIRE_THROW(f.get(), int);
9f95a23c
TL
185}
186
11fdf7f2
TL
187SEASTAR_TEST_CASE(test_finally_is_called_on_success_and_failure) {
188 auto finally1 = make_shared<bool>();
189 auto finally2 = make_shared<bool>();
190
191 return make_ready_future().then([] {
192 }).finally([=] {
193 *finally1 = true;
194 }).then([] {
195 throw std::runtime_error("");
196 }).finally([=] {
197 *finally2 = true;
198 }).then_wrapped([=] (auto&& f) {
199 BOOST_REQUIRE(*finally1);
200 BOOST_REQUIRE(*finally2);
201
202 // Should be failed.
203 try {
204 f.get();
205 BOOST_REQUIRE(false);
206 } catch (...) {}
207 });
208}
209
210SEASTAR_TEST_CASE(test_get_on_promise) {
211 auto p = promise<uint32_t>();
212 p.set_value(10);
213 BOOST_REQUIRE_EQUAL(10u, p.get_future().get0());
214 return make_ready_future();
215}
216
f67539c2
TL
217// An exception class with a controlled what() overload
218class test_exception : public std::exception {
219 sstring _what;
220public:
221 explicit test_exception(sstring what) : _what(std::move(what)) {}
222 virtual const char* what() const noexcept override {
223 return _what.c_str();
224 }
225};
226
1e59de90
TL
227SEASTAR_TEST_CASE(test_get_on_exceptional_promise) {
228 auto p = promise<>();
229 p.set_exception(test_exception("test"));
230 BOOST_REQUIRE_THROW(p.get_future().get(), test_exception);
231 return make_ready_future();
232}
233
f67539c2
TL
234static void check_finally_exception(std::exception_ptr ex) {
235 BOOST_REQUIRE_EQUAL(fmt::format("{}", ex),
236 "seastar::nested_exception: test_exception (bar) (while cleaning up after test_exception (foo))");
237 try {
238 // convert to the concrete type nested_exception
239 std::rethrow_exception(ex);
240 } catch (seastar::nested_exception& ex) {
241 try {
242 std::rethrow_exception(ex.inner);
243 } catch (test_exception& inner) {
244 BOOST_REQUIRE_EQUAL(inner.what(), "bar");
245 }
246 try {
247 ex.rethrow_nested();
248 } catch (test_exception& outer) {
249 BOOST_REQUIRE_EQUAL(outer.what(), "foo");
250 }
251 }
252}
253
254SEASTAR_TEST_CASE(test_finally_exception) {
255 return make_ready_future<>().then([] {
256 throw test_exception("foo");
257 }).finally([] {
258 throw test_exception("bar");
259 }).handle_exception(check_finally_exception);
260}
261
262SEASTAR_TEST_CASE(test_finally_exceptional_future) {
263 return make_ready_future<>().then([] {
264 throw test_exception("foo");
265 }).finally([] {
266 return make_exception_future<>(test_exception("bar"));
267 }).handle_exception(check_finally_exception);
268}
269
11fdf7f2
TL
270SEASTAR_TEST_CASE(test_finally_waits_for_inner) {
271 auto finally = make_shared<bool>();
272 auto p = make_shared<promise<>>();
273
274 auto f = make_ready_future().then([] {
275 }).finally([=] {
276 return p->get_future().then([=] {
277 *finally = true;
278 });
279 }).then([=] {
280 BOOST_REQUIRE(*finally);
281 });
282 BOOST_REQUIRE(!*finally);
283 p->set_value();
284 return f;
285}
286
287SEASTAR_TEST_CASE(test_finally_is_called_on_success_and_failure__not_ready_to_armed) {
288 auto finally1 = make_shared<bool>();
289 auto finally2 = make_shared<bool>();
290
291 promise<> p;
292 auto f = p.get_future().finally([=] {
293 *finally1 = true;
294 }).then([] {
295 throw std::runtime_error("");
296 }).finally([=] {
297 *finally2 = true;
298 }).then_wrapped([=] (auto &&f) {
299 BOOST_REQUIRE(*finally1);
300 BOOST_REQUIRE(*finally2);
301 try {
302 f.get();
303 } catch (...) {} // silence exceptional future ignored messages
304 });
305
306 p.set_value();
307 return f;
308}
309
310SEASTAR_TEST_CASE(test_exception_from_finally_fails_the_target) {
311 promise<> pr;
312 auto f = pr.get_future().finally([=] {
313 throw std::runtime_error("");
314 }).then([] {
315 BOOST_REQUIRE(false);
316 }).then_wrapped([] (auto&& f) {
317 try {
318 f.get();
319 } catch (...) {} // silence exceptional future ignored messages
320 });
321
322 pr.set_value();
323 return f;
324}
325
326SEASTAR_TEST_CASE(test_exception_from_finally_fails_the_target_on_already_resolved) {
327 return make_ready_future().finally([=] {
328 throw std::runtime_error("");
329 }).then([] {
330 BOOST_REQUIRE(false);
331 }).then_wrapped([] (auto&& f) {
332 try {
333 f.get();
334 } catch (...) {} // silence exceptional future ignored messages
335 });
336}
337
338SEASTAR_TEST_CASE(test_exception_thrown_from_then_wrapped_causes_future_to_fail) {
339 return make_ready_future().then_wrapped([] (auto&& f) {
340 throw std::runtime_error("");
341 }).then_wrapped([] (auto&& f) {
342 try {
343 f.get();
344 BOOST_REQUIRE(false);
345 } catch (...) {}
346 });
347}
348
349SEASTAR_TEST_CASE(test_exception_thrown_from_then_wrapped_causes_future_to_fail__async_case) {
350 promise<> p;
351
352 auto f = p.get_future().then_wrapped([] (auto&& f) {
353 throw std::runtime_error("");
354 }).then_wrapped([] (auto&& f) {
355 try {
356 f.get();
357 BOOST_REQUIRE(false);
358 } catch (...) {}
359 });
360
361 p.set_value();
362
363 return f;
364}
365
366SEASTAR_TEST_CASE(test_failing_intermediate_promise_should_fail_the_master_future) {
367 promise<> p1;
368 promise<> p2;
369
9f95a23c 370 auto f = p1.get_future().then([f = p2.get_future()] () mutable {
11fdf7f2
TL
371 return std::move(f);
372 }).then([] {
373 BOOST_REQUIRE(false);
374 });
375
376 p1.set_value();
377 p2.set_exception(std::runtime_error("boom"));
378
379 return std::move(f).then_wrapped([](auto&& f) {
380 try {
381 f.get();
382 BOOST_REQUIRE(false);
383 } catch (...) {}
384 });
385}
386
387SEASTAR_TEST_CASE(test_future_forwarding__not_ready_to_unarmed) {
388 promise<> p1;
389 promise<> p2;
390
391 auto f1 = p1.get_future();
392 auto f2 = p2.get_future();
393
394 f1.forward_to(std::move(p2));
395
396 BOOST_REQUIRE(!f2.available());
397
398 auto called = f2.then([] {});
399
400 p1.set_value();
401 return called;
402}
403
404SEASTAR_TEST_CASE(test_future_forwarding__not_ready_to_armed) {
405 promise<> p1;
406 promise<> p2;
407
408 auto f1 = p1.get_future();
409 auto f2 = p2.get_future();
410
411 auto called = f2.then([] {});
412
413 f1.forward_to(std::move(p2));
414
415 BOOST_REQUIRE(!f2.available());
416
417 p1.set_value();
418
419 return called;
420}
421
422SEASTAR_TEST_CASE(test_future_forwarding__ready_to_unarmed) {
423 promise<> p2;
424
425 auto f1 = make_ready_future<>();
426 auto f2 = p2.get_future();
427
428 std::move(f1).forward_to(std::move(p2));
429 BOOST_REQUIRE(f2.available());
430
431 return std::move(f2).then_wrapped([] (future<> f) {
432 BOOST_REQUIRE(!f.failed());
433 });
434}
435
436SEASTAR_TEST_CASE(test_future_forwarding__ready_to_armed) {
437 promise<> p2;
438
439 auto f1 = make_ready_future<>();
440 auto f2 = p2.get_future();
441
442 auto called = std::move(f2).then([] {});
443
444 BOOST_REQUIRE(f1.available());
445
446 f1.forward_to(std::move(p2));
447 return called;
448}
449
450static void forward_dead_unarmed_promise_with_dead_future_to(promise<>& p) {
451 promise<> p2;
452 p.get_future().forward_to(std::move(p2));
453}
454
455SEASTAR_TEST_CASE(test_future_forwarding__ready_to_unarmed_soon_to_be_dead) {
456 promise<> p1;
457 forward_dead_unarmed_promise_with_dead_future_to(p1);
458 make_ready_future<>().forward_to(std::move(p1));
459 return make_ready_future<>();
460}
461
462SEASTAR_TEST_CASE(test_exception_can_be_thrown_from_do_until_body) {
463 return do_until([] { return false; }, [] {
464 throw expected_exception();
465 return now();
466 }).then_wrapped([] (auto&& f) {
467 try {
468 f.get();
469 BOOST_FAIL("should have failed");
470 } catch (const expected_exception& e) {
471 // expected
472 }
473 });
474}
475
20effc67
TL
476SEASTAR_TEST_CASE(test_exception_can_be_thrown_from_do_until_condition) {
477 return do_until([] { throw expected_exception(); return false; }, [] {
478 return now();
479 }).then_wrapped([] (auto&& f) {
480 try {
481 f.get();
482 BOOST_FAIL("should have failed");
483 } catch (const expected_exception& e) {
484 // expected
485 }
486 });
487}
488
11fdf7f2
TL
489SEASTAR_TEST_CASE(test_bare_value_can_be_returned_from_callback) {
490 return now().then([] {
491 return 3;
492 }).then([] (int x) {
493 BOOST_REQUIRE(x == 3);
494 });
495}
496
497SEASTAR_TEST_CASE(test_when_all_iterator_range) {
498 std::vector<future<size_t>> futures;
499 for (size_t i = 0; i != 1000000; ++i) {
f67539c2
TL
500 // Use a mix of available and unavailable futures to exercise
501 // both paths in when_all().
1e59de90 502 auto fut = (i % 2) == 0 ? make_ready_future<>() : yield();
f67539c2 503 futures.push_back(fut.then([i] { return i; }));
11fdf7f2
TL
504 }
505 // Verify the above statement is correct
506 BOOST_REQUIRE(!std::all_of(futures.begin(), futures.end(),
507 [] (auto& f) { return f.available(); }));
508 auto p = make_shared(std::move(futures));
509 return when_all(p->begin(), p->end()).then([p] (std::vector<future<size_t>> ret) {
510 BOOST_REQUIRE(std::all_of(ret.begin(), ret.end(), [] (auto& f) { return f.available(); }));
f67539c2 511 BOOST_REQUIRE(std::all_of(ret.begin(), ret.end(), [&ret] (auto& f) { return f.get0() == size_t(&f - ret.data()); }));
11fdf7f2
TL
512 });
513}
514
20effc67
TL
515// helper function for when_any tests
516template<typename Container>
517future<> when_all_but_one_succeed(Container& futures, size_t leave_out)
518{
519 auto sz = futures.size();
520 assert(sz >= 1);
521 assert(leave_out < sz);
522 std::vector<future<size_t>> all_but_one_tmp;
523 all_but_one_tmp.reserve(sz - 1);
524 for (size_t i = 0 ; i < sz; i++){
525 if (i == leave_out) { continue; }
526 all_but_one_tmp.push_back(std::move(futures[i]));
527 }
528 auto all_but_one = make_shared(std::move(all_but_one_tmp));
529 return when_all_succeed(all_but_one->begin(), all_but_one->end()).then([all_but_one] (auto&& _) {
530 return make_ready_future<>();
531 });
532}
533
534SEASTAR_TEST_CASE(test_when_any_iterator_range_i) {
535 std::vector<future<size_t>> futures;
536 for (size_t i = 0; i != 100; ++i) {
1e59de90 537 auto fut = yield();
20effc67
TL
538 futures.push_back(fut.then([i] { return i; }));
539 }
540
541 // Verify the above statement is correct
542 BOOST_REQUIRE(std::all_of(futures.begin(), futures.end(), [](auto &f) { return !f.available(); }));
543
544 auto p = make_shared(std::move(futures));
545 return seastar::when_any(p->begin(), p->end()).then([p](auto &&ret_obj) {
546 BOOST_REQUIRE(ret_obj.futures[ret_obj.index].available());
547 BOOST_REQUIRE(ret_obj.futures[ret_obj.index].get0() == ret_obj.index);
548 return when_all_but_one_succeed(ret_obj.futures, ret_obj.index);
549 });
550}
551
552SEASTAR_TEST_CASE(test_when_any_iterator_range_ii) {
553 std::vector<future<size_t>> futures;
554 for (size_t i = 0; i != 100; ++i) {
555 if (i == 42) {
556 auto fut = seastar::make_ready_future<>();
557 futures.push_back(fut.then([i] { return i; }));
558 } else {
559 auto fut = seastar::sleep(100ms);
560 futures.push_back(fut.then([i] { return i; }));
561 }
562 }
563 auto p = make_shared(std::move(futures));
564 return seastar::when_any(p->begin(), p->end()).then([p](auto &&ret_obj) {
565 BOOST_REQUIRE(ret_obj.futures[ret_obj.index].available());
566 BOOST_REQUIRE(ret_obj.futures[ret_obj.index].get0() == ret_obj.index);
567 BOOST_REQUIRE(ret_obj.index == 42);
568 return when_all_but_one_succeed(ret_obj.futures, ret_obj.index);
569 });
570}
571
572SEASTAR_TEST_CASE(test_when_any_iterator_range_iii) {
573 std::vector<future<size_t>> futures;
574 for (size_t i = 0; i != 100; ++i) {
575 if (i == 42) {
576 auto fut = seastar::sleep(5ms);
577 futures.push_back(fut.then([i] { return i; }));
578 } else {
579 auto fut = seastar::sleep(100ms);
580 futures.push_back(fut.then([i] { return i; }));
581 }
582 }
583 auto p = make_shared(std::move(futures));
584 return seastar::when_any(p->begin(), p->end()).then([p](auto &&ret_obj) {
585 BOOST_REQUIRE(ret_obj.futures[ret_obj.index].available());
586 BOOST_REQUIRE(ret_obj.futures[ret_obj.index].get0() == ret_obj.index);
587 BOOST_REQUIRE(ret_obj.index == 42);
588 return when_all_but_one_succeed(ret_obj.futures, ret_obj.index);
589 });
590}
591
592SEASTAR_TEST_CASE(test_when_any_iterator_range_iv) {
593 std::vector<future<size_t>> futures;
594 for (size_t i = 0; i != 100; ++i) {
595 if (i == 42) {
1e59de90 596 auto fut = yield().then([] { return seastar::make_exception_future(std::runtime_error("test")); } );
20effc67
TL
597 futures.push_back(fut.then([i] { return i; }));
598 } else {
599 auto fut = seastar::sleep(100ms);
600 futures.push_back(fut.then([i] { return i; }));
601 }
602 }
603 auto p = make_shared(std::move(futures));
604 return seastar::when_any(p->begin(), p->end()).then([p](auto &&ret_obj) {
605 BOOST_REQUIRE(ret_obj.futures[ret_obj.index].available());
606 BOOST_REQUIRE_THROW(ret_obj.futures[ret_obj.index].get(), std::runtime_error);
607 return when_all_but_one_succeed(ret_obj.futures, ret_obj.index);
608 });
609}
610
1e59de90
TL
611SEASTAR_TEST_CASE(test_when_any_variadic_i)
612{
613 auto f_int = yield().then([] { return make_ready_future<int>(42); });
614 auto f_string = sleep(100ms).then([] { return make_ready_future<sstring>("hello"); });
615 auto f_l33tspeak = sleep(100ms).then([] {
616 return make_ready_future<std::tuple<char, int, int, char, char, int, char>>(
617 std::make_tuple('s', 3, 4, 's', 't', 4, 'r'));
618 });
619 return when_any(std::move(f_int), std::move(f_string), std::move(f_l33tspeak)).then([](auto&& wa_result) {
620 BOOST_REQUIRE(wa_result.index == 0);
621 auto [one, two, three] = std::move(wa_result.futures);
622 BOOST_REQUIRE(one.get0() == 42);
623 return when_all_succeed(std::move(two), std::move(three)).then([](auto _) { return seastar::make_ready_future<>(); });
624 });
625}
626
627SEASTAR_TEST_CASE(test_when_any_variadic_ii)
628{
629 struct foo {
630 int bar = 86;
631 };
632
633 auto f_int = sleep(100ms).then([] { return make_ready_future<int>(42); });
634 auto f_foo = sleep(75ms).then([] { return make_ready_future<foo>(); });
635 auto f_string = sleep(1ms).then([] { return make_ready_future<sstring>("hello"); });
636 auto f_l33tspeak = sleep(50ms).then([] {
637 return make_ready_future<std::tuple<char, int, int, char, char, int, char>>(
638 std::make_tuple('s', 3, 4, 's', 't', 4, 'r'));
639 });
640 return when_any(std::move(f_int), std::move(f_foo), std::move(f_string), std::move(f_l33tspeak))
641 .then([](auto&& wa_result) {
642 BOOST_REQUIRE(wa_result.index == 2);
643 auto [one, two, three, four] = std::move(wa_result.futures);
644 BOOST_REQUIRE(three.get0() == "hello");
645 return when_any(std::move(one), std::move(two), std::move(four)).then([](auto wa_nextresult) {
646 auto [one, two, four] = std::move(wa_nextresult.futures);
647 BOOST_REQUIRE(wa_nextresult.index == 2);
648 BOOST_REQUIRE(four.get0() == std::make_tuple('s', 3, 4, 's', 't', 4, 'r'));
649 return when_any(std::move(one), std::move(two)).then([](auto wa_result) {
650 auto [one, two] = std::move(wa_result.futures);
651 BOOST_REQUIRE(wa_result.index == 1);
652 BOOST_REQUIRE(two.get0().bar == foo{}.bar);
653 return one.then([](int x) { BOOST_REQUIRE(x == 42); });
654 });
655 });
656 });
657}
658
11fdf7f2
TL
659SEASTAR_TEST_CASE(test_map_reduce) {
660 auto square = [] (long x) { return make_ready_future<long>(x*x); };
661 long n = 1000;
662 return map_reduce(boost::make_counting_iterator<long>(0), boost::make_counting_iterator<long>(n),
663 square, long(0), std::plus<long>()).then([n] (auto result) {
664 auto m = n - 1; // counting does not include upper bound
665 BOOST_REQUIRE_EQUAL(result, (m * (m + 1) * (2*m + 1)) / 6);
666 });
667}
668
f67539c2
TL
669SEASTAR_TEST_CASE(test_map_reduce_simple) {
670 return do_with(0L, [] (auto& res) {
671 long n = 10;
672 return map_reduce(boost::make_counting_iterator<long>(0), boost::make_counting_iterator<long>(n),
673 [] (long x) { return x; },
674 [&res] (long x) { res += x; }).then([n, &res] {
675 long expected = (n * (n - 1)) / 2;
676 BOOST_REQUIRE_EQUAL(res, expected);
677 });
678 });
679}
680
681SEASTAR_TEST_CASE(test_map_reduce_tuple) {
682 return do_with(0L, 0L, [] (auto& res0, auto& res1) {
683 long n = 10;
684 return map_reduce(boost::make_counting_iterator<long>(0), boost::make_counting_iterator<long>(n),
685 [] (long x) { return std::tuple<long, long>(x, -x); },
686 [&res0, &res1] (std::tuple<long, long> t) { res0 += std::get<0>(t); res1 += std::get<1>(t); }).then([n, &res0, &res1] {
687 long expected = (n * (n - 1)) / 2;
688 BOOST_REQUIRE_EQUAL(res0, expected);
689 BOOST_REQUIRE_EQUAL(res1, -expected);
690 });
691 });
692}
693
1e59de90
TL
694SEASTAR_TEST_CASE(test_map_reduce_lifetime) {
695 struct map {
696 bool destroyed = false;
697 ~map() {
698 destroyed = true;
699 }
700 auto operator()(long x) {
701 return yield().then([this, x] {
702 BOOST_REQUIRE(!destroyed);
703 return x;
704 });
705 }
706 };
707 struct reduce {
708 long& res;
709 bool destroyed = false;
710 ~reduce() {
711 destroyed = true;
712 }
713 auto operator()(long x) {
714 return yield().then([this, x] {
715 BOOST_REQUIRE(!destroyed);
716 res += x;
717 });
718 }
719 };
720 return do_with(0L, [] (auto& res) {
721 long n = 10;
722 return map_reduce(boost::make_counting_iterator<long>(0), boost::make_counting_iterator<long>(n),
723 map{}, reduce{res}).then([n, &res] {
724 long expected = (n * (n - 1)) / 2;
725 BOOST_REQUIRE_EQUAL(res, expected);
726 });
727 });
728}
729
730SEASTAR_TEST_CASE(test_map_reduce0_lifetime) {
731 struct map {
732 bool destroyed = false;
733 ~map() {
734 destroyed = true;
735 }
736 auto operator()(long x) {
737 return yield().then([this, x] {
738 BOOST_REQUIRE(!destroyed);
739 return x;
740 });
741 }
742 };
743 struct reduce {
744 bool destroyed = false;
745 ~reduce() {
746 destroyed = true;
747 }
748 auto operator()(long res, long x) {
749 BOOST_REQUIRE(!destroyed);
750 return res + x;
751 }
752 };
753 long n = 10;
754 return map_reduce(boost::make_counting_iterator<long>(0), boost::make_counting_iterator<long>(n),
755 map{}, 0L, reduce{}).then([n] (long res) {
756 long expected = (n * (n - 1)) / 2;
757 BOOST_REQUIRE_EQUAL(res, expected);
758 });
759}
760
11fdf7f2
TL
761// This test doesn't actually test anything - it just waits for the future
762// returned by sleep to complete. However, a bug we had in sleep() caused
763// this test to fail the sanitizer in the debug build, so this is a useful
764// regression test.
765SEASTAR_TEST_CASE(test_sleep) {
766 return sleep(std::chrono::milliseconds(100));
767}
768
769SEASTAR_TEST_CASE(test_do_with_1) {
770 return do_with(1, [] (int& one) {
771 BOOST_REQUIRE_EQUAL(one, 1);
772 return make_ready_future<>();
773 });
774}
775
776SEASTAR_TEST_CASE(test_do_with_2) {
777 return do_with(1, 2L, [] (int& one, long two) {
778 BOOST_REQUIRE_EQUAL(one, 1);
779 BOOST_REQUIRE_EQUAL(two, 2);
780 return make_ready_future<>();
781 });
782}
783
784SEASTAR_TEST_CASE(test_do_with_3) {
785 return do_with(1, 2L, 3, [] (int& one, long two, int three) {
786 BOOST_REQUIRE_EQUAL(one, 1);
787 BOOST_REQUIRE_EQUAL(two, 2);
788 BOOST_REQUIRE_EQUAL(three, 3);
789 return make_ready_future<>();
790 });
791}
792
793SEASTAR_TEST_CASE(test_do_with_4) {
794 return do_with(1, 2L, 3, 4, [] (int& one, long two, int three, int four) {
795 BOOST_REQUIRE_EQUAL(one, 1);
796 BOOST_REQUIRE_EQUAL(two, 2);
797 BOOST_REQUIRE_EQUAL(three, 3);
798 BOOST_REQUIRE_EQUAL(four, 4);
799 return make_ready_future<>();
800 });
801}
802
f67539c2
TL
803SEASTAR_TEST_CASE(test_do_with_5) {
804 using func = noncopyable_function<void()>;
805 return do_with(func([] {}), [] (func&) {
806 return make_ready_future<>();
807 });
808}
809
810SEASTAR_TEST_CASE(test_do_with_6) {
811 const int x = 42;
812 return do_with(int(42), x, [](int&, int&) {
813 return make_ready_future<>();
814 });
815}
816
817SEASTAR_TEST_CASE(test_do_with_7) {
818 const int x = 42;
819 return do_with(x, [](int&) {
820 return make_ready_future<>();
821 });
822}
823
11fdf7f2
TL
824SEASTAR_TEST_CASE(test_do_while_stopping_immediately) {
825 return do_with(int(0), [] (int& count) {
826 return repeat([&count] {
827 ++count;
828 return stop_iteration::yes;
829 }).then([&count] {
830 BOOST_REQUIRE(count == 1);
831 });
832 });
833}
834
835SEASTAR_TEST_CASE(test_do_while_stopping_after_two_iterations) {
836 return do_with(int(0), [] (int& count) {
837 return repeat([&count] {
838 ++count;
839 return count == 2 ? stop_iteration::yes : stop_iteration::no;
840 }).then([&count] {
841 BOOST_REQUIRE(count == 2);
842 });
843 });
844}
845
846SEASTAR_TEST_CASE(test_do_while_failing_in_the_first_step) {
847 return repeat([] {
848 throw expected_exception();
849 return stop_iteration::no;
850 }).then_wrapped([](auto&& f) {
851 try {
852 f.get();
853 BOOST_FAIL("should not happen");
854 } catch (const expected_exception&) {
855 // expected
856 }
857 });
858}
859
860SEASTAR_TEST_CASE(test_do_while_failing_in_the_second_step) {
861 return do_with(int(0), [] (int& count) {
862 return repeat([&count] {
863 ++count;
864 if (count > 1) {
865 throw expected_exception();
866 }
1e59de90 867 return yield().then([] { return stop_iteration::no; });
11fdf7f2
TL
868 }).then_wrapped([&count](auto&& f) {
869 try {
870 f.get();
871 BOOST_FAIL("should not happen");
872 } catch (const expected_exception&) {
873 BOOST_REQUIRE(count == 2);
874 }
875 });
876 });
877}
878
879SEASTAR_TEST_CASE(test_parallel_for_each) {
880 return async([] {
881 // empty
882 parallel_for_each(std::vector<int>(), [] (int) -> future<> {
883 BOOST_FAIL("should not reach");
884 abort();
885 }).get();
886
887 // immediate result
888 auto range = boost::copy_range<std::vector<int>>(boost::irange(1, 6));
889 auto sum = 0;
890 parallel_for_each(range, [&sum] (int v) {
891 sum += v;
892 return make_ready_future<>();
893 }).get();
894 BOOST_REQUIRE_EQUAL(sum, 15);
895
896 // all suspend
897 sum = 0;
898 parallel_for_each(range, [&sum] (int v) {
1e59de90 899 return yield().then([&sum, v] {
11fdf7f2
TL
900 sum += v;
901 });
902 }).get();
903 BOOST_REQUIRE_EQUAL(sum, 15);
904
905 // throws immediately
9f95a23c 906 BOOST_CHECK_EXCEPTION(parallel_for_each(range, [] (int) -> future<> {
11fdf7f2
TL
907 throw 5;
908 }).get(), int, [] (int v) { return v == 5; });
909
910 // throws after suspension
9f95a23c 911 BOOST_CHECK_EXCEPTION(parallel_for_each(range, [] (int) {
1e59de90 912 return yield().then([] {
11fdf7f2
TL
913 throw 5;
914 });
915 }).get(), int, [] (int v) { return v == 5; });
916 });
917}
918
919SEASTAR_TEST_CASE(test_parallel_for_each_early_failure) {
920 return do_with(0, [] (int& counter) {
921 return parallel_for_each(boost::irange(0, 11000), [&counter] (int i) {
922 using namespace std::chrono_literals;
923 // force scheduling
924 return sleep((i % 31 + 1) * 1ms).then([&counter, i] {
925 ++counter;
926 if (i % 1777 == 1337) {
927 return make_exception_future<>(i);
928 }
929 return make_ready_future<>();
930 });
931 }).then_wrapped([&counter] (future<> f) {
932 BOOST_REQUIRE_EQUAL(counter, 11000);
933 BOOST_REQUIRE(f.failed());
934 try {
935 f.get();
936 BOOST_FAIL("wanted an exception");
937 } catch (int i) {
938 BOOST_REQUIRE(i % 1777 == 1337);
939 } catch (...) {
940 BOOST_FAIL("bad exception type");
941 }
942 });
943 });
944}
945
946SEASTAR_TEST_CASE(test_parallel_for_each_waits_for_all_fibers_even_if_one_of_them_failed) {
947 auto can_exit = make_lw_shared<bool>(false);
948 return parallel_for_each(boost::irange(0, 2), [can_exit] (int i) {
1e59de90 949 return yield().then([i, can_exit] {
11fdf7f2
TL
950 if (i == 1) {
951 throw expected_exception();
952 } else {
953 using namespace std::chrono_literals;
954 return sleep(300ms).then([can_exit] {
955 *can_exit = true;
956 });
957 }
958 });
959 }).then_wrapped([can_exit] (auto&& f) {
960 try {
961 f.get();
962 } catch (...) {
963 // expected
964 }
965 BOOST_REQUIRE(*can_exit);
966 });
967}
968
f67539c2
TL
969SEASTAR_THREAD_TEST_CASE(test_parallel_for_each_broken_promise) {
970 auto fut = [] {
971 std::vector<promise<>> v(2);
972 return parallel_for_each(v, [] (promise<>& p) {
973 return p.get_future();
11fdf7f2 974 });
f67539c2
TL
975 }();
976 BOOST_CHECK_THROW(fut.get(), broken_promise);
977}
978
979SEASTAR_THREAD_TEST_CASE(test_repeat_broken_promise) {
980 auto get_fut = [] {
981 promise<stop_iteration> pr;
982 return pr.get_future();
983 };
984
985 future<> r = repeat([fut = get_fut()] () mutable {
986 return std::move(fut);
11fdf7f2 987 });
f67539c2
TL
988
989 BOOST_CHECK_THROW(r.get(), broken_promise);
11fdf7f2
TL
990}
991
f67539c2 992#ifndef SEASTAR_SHUFFLE_TASK_QUEUE
11fdf7f2
TL
993SEASTAR_TEST_CASE(test_high_priority_task_runs_in_the_middle_of_loops) {
994 auto counter = make_lw_shared<int>(0);
995 auto flag = make_lw_shared<bool>(false);
996 return repeat([counter, flag] {
997 if (*counter == 1) {
998 BOOST_REQUIRE(*flag);
999 return stop_iteration::yes;
1000 }
1001 engine().add_high_priority_task(make_task([flag] {
1002 *flag = true;
1003 }));
1004 ++(*counter);
1005 return stop_iteration::no;
1006 });
1007}
1008#endif
1009
f67539c2
TL
1010SEASTAR_TEST_CASE(futurize_invoke_val_exception) {
1011 return futurize_invoke([] (int arg) { throw expected_exception(); return arg; }, 1).then_wrapped([] (future<int> f) {
11fdf7f2
TL
1012 try {
1013 f.get();
1014 BOOST_FAIL("should have thrown");
1015 } catch (expected_exception& e) {}
1016 });
1017}
1018
f67539c2
TL
1019SEASTAR_TEST_CASE(futurize_invoke_val_ok) {
1020 return futurize_invoke([] (int arg) { return arg * 2; }, 2).then_wrapped([] (future<int> f) {
11fdf7f2
TL
1021 try {
1022 auto x = f.get0();
1023 BOOST_REQUIRE_EQUAL(x, 4);
1024 } catch (expected_exception& e) {
1025 BOOST_FAIL("should not have thrown");
1026 }
1027 });
1028}
1029
f67539c2
TL
1030SEASTAR_TEST_CASE(futurize_invoke_val_future_exception) {
1031 return futurize_invoke([] (int a) {
11fdf7f2
TL
1032 return sleep(std::chrono::milliseconds(100)).then([] {
1033 throw expected_exception();
1034 return make_ready_future<int>(0);
1035 });
1036 }, 0).then_wrapped([] (future<int> f) {
1037 try {
1038 f.get();
1039 BOOST_FAIL("should have thrown");
1040 } catch (expected_exception& e) { }
1041 });
1042}
1043
f67539c2
TL
1044SEASTAR_TEST_CASE(futurize_invoke_val_future_ok) {
1045 return futurize_invoke([] (int a) {
11fdf7f2
TL
1046 return sleep(std::chrono::milliseconds(100)).then([a] {
1047 return make_ready_future<int>(a * 100);
1048 });
1049 }, 2).then_wrapped([] (future<int> f) {
1050 try {
1051 auto x = f.get0();
1052 BOOST_REQUIRE_EQUAL(x, 200);
1053 } catch (expected_exception& e) {
1054 BOOST_FAIL("should not have thrown");
1055 }
1056 });
1057}
f67539c2
TL
1058SEASTAR_TEST_CASE(futurize_invoke_void_exception) {
1059 return futurize_invoke([] (auto arg) { throw expected_exception(); }, 0).then_wrapped([] (future<> f) {
11fdf7f2
TL
1060 try {
1061 f.get();
1062 BOOST_FAIL("should have thrown");
1063 } catch (expected_exception& e) {}
1064 });
1065}
1066
f67539c2
TL
1067SEASTAR_TEST_CASE(futurize_invoke_void_ok) {
1068 return futurize_invoke([] (auto arg) { }, 0).then_wrapped([] (future<> f) {
11fdf7f2
TL
1069 try {
1070 f.get();
1071 } catch (expected_exception& e) {
1072 BOOST_FAIL("should not have thrown");
1073 }
1074 });
1075}
1076
f67539c2
TL
1077SEASTAR_TEST_CASE(futurize_invoke_void_future_exception) {
1078 return futurize_invoke([] (auto a) {
11fdf7f2
TL
1079 return sleep(std::chrono::milliseconds(100)).then([] {
1080 throw expected_exception();
1081 });
1082 }, 0).then_wrapped([] (future<> f) {
1083 try {
1084 f.get();
1085 BOOST_FAIL("should have thrown");
1086 } catch (expected_exception& e) { }
1087 });
1088}
1089
f67539c2 1090SEASTAR_TEST_CASE(futurize_invoke_void_future_ok) {
11fdf7f2 1091 auto a = make_lw_shared<int>(1);
f67539c2 1092 return futurize_invoke([] (int& a) {
11fdf7f2
TL
1093 return sleep(std::chrono::milliseconds(100)).then([&a] {
1094 a *= 100;
1095 });
1096 }, *a).then_wrapped([a] (future<> f) {
1097 try {
1098 f.get();
1099 BOOST_REQUIRE_EQUAL(*a, 100);
1100 } catch (expected_exception& e) {
1101 BOOST_FAIL("should not have thrown");
1102 }
1103 });
1104}
1105
9f95a23c
TL
1106SEASTAR_TEST_CASE(test_unused_shared_future_is_not_a_broken_future) {
1107 promise<> p;
1108 shared_future<> s(p.get_future());
1109 return make_ready_future<>();
1110}
1111
11fdf7f2
TL
1112SEASTAR_TEST_CASE(test_shared_future_propagates_value_to_all) {
1113 return seastar::async([] {
1114 promise<shared_ptr<int>> p; // shared_ptr<> to check it deals with emptyable types
1115 shared_future<shared_ptr<int>> f(p.get_future());
1116
1117 auto f1 = f.get_future();
1118 auto f2 = f.get_future();
1119
1120 p.set_value(make_shared<int>(1));
1121 BOOST_REQUIRE(*f1.get0() == 1);
1122 BOOST_REQUIRE(*f2.get0() == 1);
1123 });
1124}
1125
1126template<typename... T>
1127void check_fails_with_expected(future<T...> f) {
1128 try {
1129 f.get();
1130 BOOST_FAIL("Should have failed");
1131 } catch (expected_exception&) {
1132 // expected
1133 }
1134}
1135
1136SEASTAR_TEST_CASE(test_shared_future_propagates_value_to_copies) {
1137 return seastar::async([] {
1138 promise<int> p;
1139 auto sf1 = shared_future<int>(p.get_future());
1140 auto sf2 = sf1;
1141
1142 auto f1 = sf1.get_future();
1143 auto f2 = sf2.get_future();
1144
1145 p.set_value(1);
1146
1147 BOOST_REQUIRE(f1.get0() == 1);
1148 BOOST_REQUIRE(f2.get0() == 1);
1149 });
1150}
1151
1152SEASTAR_TEST_CASE(test_obtaining_future_from_shared_future_after_it_is_resolved) {
1153 promise<int> p1;
1154 promise<int> p2;
1155 auto sf1 = shared_future<int>(p1.get_future());
1156 auto sf2 = shared_future<int>(p2.get_future());
1157 p1.set_value(1);
1158 p2.set_exception(expected_exception());
1159 return sf2.get_future().then_wrapped([f1 = sf1.get_future()] (auto&& f) mutable {
1160 check_fails_with_expected(std::move(f));
1161 return std::move(f1);
1162 }).then_wrapped([] (auto&& f) {
1163 BOOST_REQUIRE(f.get0() == 1);
1164 });
1165}
1166
1167SEASTAR_TEST_CASE(test_valueless_shared_future) {
1168 return seastar::async([] {
1169 promise<> p;
1170 shared_future<> f(p.get_future());
1171
1172 auto f1 = f.get_future();
1173 auto f2 = f.get_future();
1174
1175 p.set_value();
1176
1177 f1.get();
1178 f2.get();
1179 });
1180}
1181
1182SEASTAR_TEST_CASE(test_shared_future_propagates_errors_to_all) {
1183 promise<int> p;
1184 shared_future<int> f(p.get_future());
1185
1186 auto f1 = f.get_future();
1187 auto f2 = f.get_future();
1188
1189 p.set_exception(expected_exception());
1190
1191 return f1.then_wrapped([f2 = std::move(f2)] (auto&& f) mutable {
1192 check_fails_with_expected(std::move(f));
1193 return std::move(f2);
1194 }).then_wrapped([] (auto&& f) mutable {
1195 check_fails_with_expected(std::move(f));
1196 });
1197}
1198
9f95a23c
TL
1199SEASTAR_TEST_CASE(test_ignored_future_warning) {
1200 // This doesn't warn:
1201 promise<> p;
1202 p.set_exception(expected_exception());
1203 future<> f = p.get_future();
1204 f.ignore_ready_future();
1205
1206 // And by analogy, neither should this
1207 shared_promise<> p2;
1208 p2.set_exception(expected_exception());
1209 future<> f2 = p2.get_shared_future();
1210 f2.ignore_ready_future();
1211 return make_ready_future<>();
1212}
1213
11fdf7f2
TL
1214SEASTAR_TEST_CASE(test_futurize_from_tuple) {
1215 std::tuple<int> v1 = std::make_tuple(3);
1216 std::tuple<> v2 = {};
f67539c2
TL
1217 future<int> fut1 = futurize<int>::from_tuple(v1);
1218 future<> fut2 = futurize<void>::from_tuple(v2);
1219 BOOST_REQUIRE(fut1.get0() == std::get<0>(v1));
1220#if SEASTAR_API_LEVEL < 5
1221 BOOST_REQUIRE(fut2.get() == v2);
1222#endif
11fdf7f2
TL
1223 return make_ready_future<>();
1224}
1225
1226SEASTAR_TEST_CASE(test_repeat_until_value) {
1227 return do_with(int(), [] (int& counter) {
f67539c2 1228 return repeat_until_value([&counter] () -> future<std::optional<int>> {
11fdf7f2 1229 if (counter == 10000) {
f67539c2 1230 return make_ready_future<std::optional<int>>(counter);
11fdf7f2
TL
1231 } else {
1232 ++counter;
f67539c2 1233 return make_ready_future<std::optional<int>>(std::nullopt);
11fdf7f2
TL
1234 }
1235 }).then([&counter] (int result) {
1236 BOOST_REQUIRE(counter == 10000);
1237 BOOST_REQUIRE(result == counter);
1238 });
1239 });
1240}
1241
9f95a23c 1242SEASTAR_TEST_CASE(test_repeat_until_value_implicit_future) {
f67539c2 1243 // Same as above, but returning std::optional<int> instead of future<std::optional<int>>
9f95a23c
TL
1244 return do_with(int(), [] (int& counter) {
1245 return repeat_until_value([&counter] {
1246 if (counter == 10000) {
f67539c2 1247 return std::optional<int>(counter);
9f95a23c
TL
1248 } else {
1249 ++counter;
f67539c2 1250 return std::optional<int>(std::nullopt);
9f95a23c
TL
1251 }
1252 }).then([&counter] (int result) {
1253 BOOST_REQUIRE(counter == 10000);
1254 BOOST_REQUIRE(result == counter);
1255 });
1256 });
1257}
1258
1259SEASTAR_TEST_CASE(test_repeat_until_value_exception) {
1260 return repeat_until_value([] {
1261 throw expected_exception();
f67539c2 1262 return std::optional<int>(43);
9f95a23c
TL
1263 }).then_wrapped([] (future<int> f) {
1264 check_fails_with_expected(std::move(f));
1265 });
1266}
1267
11fdf7f2 1268SEASTAR_TEST_CASE(test_when_allx) {
1e59de90 1269 return when_all(yield(), yield(), make_ready_future()).discard_result();
11fdf7f2
TL
1270}
1271
9f95a23c
TL
1272// A noncopyable and nonmovable struct
1273struct non_copy_non_move {
f67539c2 1274 non_copy_non_move() = default;
9f95a23c
TL
1275 non_copy_non_move(non_copy_non_move&&) = delete;
1276 non_copy_non_move(const non_copy_non_move&) = delete;
1277};
1278
1279SEASTAR_TEST_CASE(test_when_all_functions) {
f67539c2 1280 auto f = [x = non_copy_non_move()] {
9f95a23c
TL
1281 (void)x;
1282 return make_ready_future<int>(42);
1283 };
1284 return when_all(f, [] {
1285 throw 42;
1286 return make_ready_future<>();
1e59de90 1287 }, yield()).then([] (std::tuple<future<int>, future<>, future<>> res) {
9f95a23c
TL
1288 BOOST_REQUIRE_EQUAL(std::get<0>(res).get0(), 42);
1289
1290 BOOST_REQUIRE(std::get<1>(res).available());
1291 BOOST_REQUIRE(std::get<1>(res).failed());
1292 std::get<1>(res).ignore_ready_future();
1293
1294 BOOST_REQUIRE(std::get<2>(res).available());
1295 BOOST_REQUIRE(!std::get<2>(res).failed());
1296 return make_ready_future<>();
1297 });
1298}
1299
1300SEASTAR_TEST_CASE(test_when_all_succeed_functions) {
f67539c2 1301 auto f = [x = non_copy_non_move()] {
9f95a23c
TL
1302 (void)x;
1303 return make_ready_future<int>(42);
1304 };
1305 return when_all_succeed(f, [] {
1306 throw 42;
1307 return make_ready_future<>();
1e59de90 1308 }, yield()).then_wrapped([] (auto res) { // type of `res` changes when SESTAR_API_LEVEL < 3
9f95a23c
TL
1309 BOOST_REQUIRE(res.available());
1310 BOOST_REQUIRE(res.failed());
1311 res.ignore_ready_future();
1312 return make_ready_future<>();
1313 });
1314}
1315
11fdf7f2
TL
1316template<typename E, typename... T>
1317static void check_failed_with(future<T...>&& f) {
1318 BOOST_REQUIRE(f.failed());
1319 try {
1320 f.get();
1321 BOOST_FAIL("exception expected");
1322 } catch (const E& e) {
1323 // expected
1324 } catch (...) {
1325 BOOST_FAIL(format("wrong exception: {}", std::current_exception()));
1326 }
1327}
1328
1329template<typename... T>
1330static void check_timed_out(future<T...>&& f) {
1331 check_failed_with<timed_out_error>(std::move(f));
1332}
1333
1334SEASTAR_TEST_CASE(test_with_timeout_when_it_times_out) {
1335 return seastar::async([] {
1336 promise<> pr;
1337 auto f = with_timeout(manual_clock::now() + 2s, pr.get_future());
1338
1339 BOOST_REQUIRE(!f.available());
1340
1341 manual_clock::advance(1s);
1e59de90 1342 yield().get();
11fdf7f2
TL
1343
1344 BOOST_REQUIRE(!f.available());
1345
1346 manual_clock::advance(1s);
1e59de90 1347 yield().get();
11fdf7f2
TL
1348
1349 check_timed_out(std::move(f));
1350
1351 pr.set_value();
1352 });
1353}
1354
9f95a23c
TL
1355SEASTAR_THREAD_TEST_CASE(test_shared_future_get_future_after_timeout) {
1356 // This used to crash because shared_future checked if the list of
1357 // pending futures was empty to decide if it had already called
1358 // then_wrapped. If all pending futures timed out, it would call
1359 // it again.
1360 promise<> pr;
1361 shared_future<with_clock<manual_clock>> sfut(pr.get_future());
1362 future<> fut1 = sfut.get_future(manual_clock::now() + 1s);
1363
1364 manual_clock::advance(1s);
1365
1366 check_timed_out(std::move(fut1));
1367
1368 future<> fut2 = sfut.get_future(manual_clock::now() + 1s);
1369 manual_clock::advance(1s);
1370 check_timed_out(std::move(fut2));
1371
1372 future<> fut3 = sfut.get_future(manual_clock::now() + 1s);
1373 pr.set_value();
f67539c2 1374 fut3.get();
9f95a23c
TL
1375}
1376
11fdf7f2
TL
1377SEASTAR_TEST_CASE(test_custom_exception_factory_in_with_timeout) {
1378 return seastar::async([] {
1379 class custom_error : public std::exception {
1380 public:
1381 virtual const char* what() const noexcept {
1382 return "timedout";
1383 }
1384 };
1385 struct my_exception_factory {
1386 static auto timeout() {
1387 return custom_error();
1388 }
1389 };
1390 promise<> pr;
1391 auto f = with_timeout<my_exception_factory>(manual_clock::now() + 1s, pr.get_future());
1392
1393 manual_clock::advance(1s);
1e59de90 1394 yield().get();
11fdf7f2
TL
1395
1396 check_failed_with<custom_error>(std::move(f));
1397 });
1398}
1399
1400SEASTAR_TEST_CASE(test_with_timeout_when_it_does_not_time_out) {
1401 return seastar::async([] {
1402 {
1403 promise<int> pr;
1404 auto f = with_timeout(manual_clock::now() + 1s, pr.get_future());
1405
1406 pr.set_value(42);
1407
1408 BOOST_REQUIRE_EQUAL(f.get0(), 42);
1409 }
1410
1411 // Check that timer was indeed cancelled
1412 manual_clock::advance(1s);
1e59de90 1413 yield().get();
11fdf7f2
TL
1414 });
1415}
1416
1e59de90
TL
1417template<typename... T>
1418static void check_aborted(future<T...>&& f) {
1419 check_failed_with<abort_requested_exception>(std::move(f));
1420}
1421
11fdf7f2
TL
1422SEASTAR_TEST_CASE(test_shared_future_with_timeout) {
1423 return seastar::async([] {
1424 shared_promise<with_clock<manual_clock>, int> pr;
1425 auto f1 = pr.get_shared_future(manual_clock::now() + 1s);
1426 auto f2 = pr.get_shared_future(manual_clock::now() + 2s);
1427 auto f3 = pr.get_shared_future();
1428
1429 BOOST_REQUIRE(!f1.available());
1430 BOOST_REQUIRE(!f2.available());
1431 BOOST_REQUIRE(!f3.available());
1432
1433 manual_clock::advance(1s);
1e59de90 1434 yield().get();
11fdf7f2
TL
1435
1436 check_timed_out(std::move(f1));
1437 BOOST_REQUIRE(!f2.available());
1438 BOOST_REQUIRE(!f3.available());
1439
1440 manual_clock::advance(1s);
1e59de90 1441 yield().get();
11fdf7f2
TL
1442
1443 check_timed_out(std::move(f2));
1444 BOOST_REQUIRE(!f3.available());
1445
1446 pr.set_value(42);
1447
1448 BOOST_REQUIRE_EQUAL(42, f3.get0());
1449 });
1450}
1451
1e59de90
TL
1452SEASTAR_THREAD_TEST_CASE(test_shared_future_with_abort) {
1453 abort_source as;
1454 abort_source as2;
1455 shared_promise<with_clock<manual_clock>, int> pr;
1456 auto f1 = pr.get_shared_future(as);
1457 auto f2 = pr.get_shared_future(as2);
1458 auto f3 = pr.get_shared_future();
1459
1460 BOOST_REQUIRE(!f1.available());
1461 BOOST_REQUIRE(!f2.available());
1462 BOOST_REQUIRE(!f3.available());
1463
1464 as.request_abort();
1465
1466 check_aborted(std::move(f1));
1467 BOOST_REQUIRE(!f2.available());
1468 BOOST_REQUIRE(!f3.available());
1469
1470 as2.request_abort();
1471
1472 check_aborted(std::move(f2));
1473 BOOST_REQUIRE(!f3.available());
1474
1475 pr.set_value(42);
1476
1477 BOOST_REQUIRE_EQUAL(42, f3.get0());
1478
1479 auto f4 = pr.get_shared_future(as);
1480 BOOST_REQUIRE(f4.available());
1481}
1482
f67539c2
TL
1483#if SEASTAR_API_LEVEL < 4
1484#define THEN_UNPACK then
1485#else
1486#define THEN_UNPACK then_unpack
1487#endif
1488
11fdf7f2
TL
1489SEASTAR_TEST_CASE(test_when_all_succeed_tuples) {
1490 return seastar::when_all_succeed(
1491 make_ready_future<>(),
1492 make_ready_future<sstring>("hello world"),
1493 make_ready_future<int>(42),
1494 make_ready_future<>(),
f67539c2 1495 make_ready_future<std::tuple<int, sstring>>(std::tuple(84, "hi")),
11fdf7f2 1496 make_ready_future<bool>(true)
f67539c2 1497 ).THEN_UNPACK([] (sstring msg, int v, std::tuple<int, sstring> t, bool b) {
11fdf7f2
TL
1498 BOOST_REQUIRE_EQUAL(msg, "hello world");
1499 BOOST_REQUIRE_EQUAL(v, 42);
1500 BOOST_REQUIRE_EQUAL(std::get<0>(t), 84);
1501 BOOST_REQUIRE_EQUAL(std::get<1>(t), "hi");
1502 BOOST_REQUIRE_EQUAL(b, true);
1503
1504 return seastar::when_all_succeed(
1505 make_exception_future<>(42),
1506 make_ready_future<sstring>("hello world"),
1507 make_exception_future<int>(43),
1508 make_ready_future<>()
f67539c2 1509 ).THEN_UNPACK([] (sstring, int) {
11fdf7f2
TL
1510 BOOST_FAIL("shouldn't reach");
1511 return false;
1512 }).handle_exception([] (auto excp) {
1513 try {
1514 std::rethrow_exception(excp);
1515 } catch (int v) {
1516 BOOST_REQUIRE(v == 42 || v == 43);
1517 return true;
1518 } catch (...) { }
1519 return false;
1520 }).then([] (auto ret) {
1521 BOOST_REQUIRE(ret);
1522 });
1523 });
1524}
1525
1526SEASTAR_TEST_CASE(test_when_all_succeed_vector) {
1527 std::vector<future<>> vecs;
1528 vecs.emplace_back(make_ready_future<>());
1529 vecs.emplace_back(make_ready_future<>());
1530 vecs.emplace_back(make_ready_future<>());
1531 vecs.emplace_back(make_ready_future<>());
1532 return seastar::when_all_succeed(vecs.begin(), vecs.end()).then([] {
1533 std::vector<future<>> vecs;
1534 vecs.emplace_back(make_ready_future<>());
1535 vecs.emplace_back(make_ready_future<>());
1536 vecs.emplace_back(make_exception_future<>(42));
1537 vecs.emplace_back(make_exception_future<>(43));
1538 return seastar::when_all_succeed(vecs.begin(), vecs.end());
1539 }).then([] {
1540 BOOST_FAIL("shouldn't reach");
1541 return false;
1542 }).handle_exception([] (auto excp) {
1543 try {
1544 std::rethrow_exception(excp);
1545 } catch (int v) {
1546 BOOST_REQUIRE(v == 42 || v == 43);
1547 return true;
1548 } catch (...) { }
1549 return false;
1550 }).then([] (auto ret) {
1551 BOOST_REQUIRE(ret);
1552
1553 std::vector<future<int>> vecs;
1554 vecs.emplace_back(make_ready_future<int>(1));
1555 vecs.emplace_back(make_ready_future<int>(2));
1556 vecs.emplace_back(make_ready_future<int>(3));
1557 return seastar::when_all_succeed(vecs.begin(), vecs.end());
1558 }).then([] (std::vector<int> vals) {
1559 BOOST_REQUIRE_EQUAL(vals.size(), 3u);
1560 BOOST_REQUIRE_EQUAL(vals[0], 1);
1561 BOOST_REQUIRE_EQUAL(vals[1], 2);
1562 BOOST_REQUIRE_EQUAL(vals[2], 3);
1563
1564 std::vector<future<int>> vecs;
1565 vecs.emplace_back(make_ready_future<int>(1));
1566 vecs.emplace_back(make_ready_future<int>(2));
1567 vecs.emplace_back(make_exception_future<int>(42));
1568 vecs.emplace_back(make_exception_future<int>(43));
1569 return seastar::when_all_succeed(vecs.begin(), vecs.end());
1570 }).then([] (std::vector<int>) {
1571 BOOST_FAIL("shouldn't reach");
1572 return false;
1573 }).handle_exception([] (auto excp) {
1574 try {
1575 std::rethrow_exception(excp);
1576 } catch (int v) {
1577 BOOST_REQUIRE(v == 42 || v == 43);
1578 return true;
1579 } catch (...) { }
1580 return false;
1581 }).then([] (auto ret) {
1582 BOOST_REQUIRE(ret);
1583 });
1584}
1585
1586SEASTAR_TEST_CASE(test_futurize_mutable) {
1587 int count = 0;
1588 return seastar::repeat([count]() mutable {
1589 ++count;
1590 if (count == 3) {
1591 return seastar::stop_iteration::yes;
1592 }
1593 return seastar::stop_iteration::no;
1594 });
1595}
9f95a23c
TL
1596
1597SEASTAR_THREAD_TEST_CASE(test_broken_promises) {
f67539c2
TL
1598 std::optional<future<>> f;
1599 std::optional<future<>> f2;
9f95a23c
TL
1600 { // Broken after attaching a continuation
1601 auto p = promise<>();
1602 f = p.get_future();
1603 f2 = f->then_wrapped([&] (future<> f3) {
1604 BOOST_CHECK(f3.failed());
1605 BOOST_CHECK_THROW(f3.get(), broken_promise);
1606 f = { };
1607 });
1608 }
1609 f2->get();
1610 BOOST_CHECK(!f);
1611
1612 { // Broken before attaching a continuation
1613 auto p = promise<>();
1614 f = p.get_future();
1615 }
1616 f->then_wrapped([&] (future<> f3) {
1617 BOOST_CHECK(f3.failed());
1618 BOOST_CHECK_THROW(f3.get(), broken_promise);
1619 f = { };
1620 }).get();
1621 BOOST_CHECK(!f);
1622
1623 { // Broken before suspending a thread
1624 auto p = promise<>();
1625 f = p.get_future();
1626 }
1627 BOOST_CHECK_THROW(f->get(), broken_promise);
1628}
1629
1630SEASTAR_TEST_CASE(test_warn_on_broken_promise_with_no_future) {
1631 // Example code where we expect a "Exceptional future ignored"
f67539c2 1632 // warning.
9f95a23c
TL
1633 promise<> p;
1634 // Intentionally destroy the future
1635 (void)p.get_future();
f67539c2
TL
1636
1637 with_allow_abandoned_failed_futures(1, [&] {
1638 p.set_exception(std::runtime_error("foo"));
1639 });
1640
1641 return make_ready_future<>();
1642}
1643
1e59de90
TL
1644SEASTAR_TEST_CASE(test_destroy_promise_after_state_take_value) {
1645 future<> f = make_ready_future<>();
1646 auto p = std::make_unique<seastar::promise<>>();
1647 f = p->get_future();
1648 p->set_value();
1649 auto g = f.then([] {});
1650 p.reset();
1651 return g;
1652}
1653
f67539c2
TL
1654SEASTAR_THREAD_TEST_CASE(test_exception_future_with_backtrace) {
1655 int counter = 0;
1656 auto inner = [&] (bool return_exception) mutable {
1657 if (!return_exception) {
1658 return make_ready_future<int>(++counter);
1659 } else {
1660 return make_exception_future_with_backtrace<int>(expected_exception());
1661 }
1662 };
1663 auto outer = [&] (bool return_exception) {
1664 return inner(return_exception).then([] (int i) {
1665 return make_ready_future<int>(-i);
1666 });
1667 };
1668
1669 BOOST_REQUIRE_EQUAL(outer(false).get0(), -1);
1670 BOOST_REQUIRE_EQUAL(counter, 1);
1671
1672 BOOST_CHECK_THROW(outer(true).get0(), expected_exception);
1673 BOOST_REQUIRE_EQUAL(counter, 1);
1674
1675 // Example code where we expect a "Exceptional future ignored"
1676 // warning.
1677 (void)outer(true).then_wrapped([](future<int> fut) {
1678 with_allow_abandoned_failed_futures(1, [fut = std::move(fut)]() mutable {
1679 auto foo = std::move(fut);
1680 });
1681 });
1682}
1683
1684class throw_on_move {
1685 int _i;
1686public:
1687 throw_on_move(int i = 0) noexcept {
1688 _i = i;
1689 }
1690 throw_on_move(const throw_on_move&) = delete;
1691 throw_on_move(throw_on_move&&) {
1692 _i = -1;
1693 throw expected_exception();
1694 }
1695
1696 int value() const {
1697 return _i;
1698 }
1699};
1700
1701SEASTAR_TEST_CASE(test_async_throw_on_move) {
1702 return async([] (throw_on_move t) {
1703 BOOST_CHECK(false);
1704 }, throw_on_move()).handle_exception_type([] (const expected_exception&) {
1705 return make_ready_future<>();
1706 });
1707}
1708
1709future<> func4() {
1e59de90 1710 return yield().then([] {
f67539c2
TL
1711 seastar_logger.info("backtrace: {}", current_backtrace());
1712 });
1713}
1714
1715void func3() {
1716 seastar::async([] {
1717 func4().get();
1718 }).get();
1719}
1720
1721future<> func2() {
1722 return seastar::async([] {
1723 func3();
1724 });
1725}
1726
1727future<> func1() {
1e59de90 1728 return yield().then([] {
f67539c2
TL
1729 return func2();
1730 });
1731}
1732
1733SEASTAR_THREAD_TEST_CASE(test_backtracing) {
1734 func1().get();
1735}
1736
1737SEASTAR_THREAD_TEST_CASE(test_then_unpack) {
1738 make_ready_future<std::tuple<>>().then_unpack([] () {
1739 BOOST_REQUIRE(true);
1740 }).get();
1741 make_ready_future<std::tuple<int>>(std::tuple<int>(1)).then_unpack([] (int x) {
1742 BOOST_REQUIRE(x == 1);
1743 }).get();
1744 make_ready_future<std::tuple<int, long>>(std::tuple<int, long>(1, 2)).then_unpack([] (int x, long y) {
1745 BOOST_REQUIRE(x == 1 && y == 2);
1746 }).get();
1747 make_ready_future<std::tuple<std::unique_ptr<int>>>(std::tuple(std::make_unique<int>(42))).then_unpack([] (std::unique_ptr<int> p1) {
1748 BOOST_REQUIRE(*p1 == 42);
1749 }).get();
1750}
1751
1752future<> test_then_function_f() {
9f95a23c
TL
1753 return make_ready_future<>();
1754}
f67539c2
TL
1755
1756SEASTAR_TEST_CASE(test_then_function) {
1757 return make_ready_future<>().then(test_then_function_f);
1758}
1759
1760SEASTAR_THREAD_TEST_CASE(test_with_gate) {
1761 gate g;
1762 int counter = 0;
1763 int gate_closed_errors = 0;
1764 int other_errors = 0;
1765
1766 // test normal operation when gate is opened
1767 BOOST_CHECK_NO_THROW(with_gate(g, [&] { counter++; }).get());
1768 BOOST_REQUIRE_EQUAL(counter, 1);
1769
1770 // test that an exception returned by the calling func
1771 // is propagated to with_gate future
1772 counter = gate_closed_errors = other_errors = 0;
1773 BOOST_CHECK_NO_THROW(with_gate(g, [&] {
1774 counter++;
1775 return make_exception_future<>(expected_exception());
1776 }).handle_exception_type([&] (gate_closed_exception& e) {
1777 gate_closed_errors++;
1778 }).handle_exception([&] (std::exception_ptr) {
1779 other_errors++;
1780 }).get());
1781 BOOST_REQUIRE(counter);
1782 BOOST_REQUIRE(!gate_closed_errors);
1783 BOOST_REQUIRE(other_errors);
1784
1785 g.close().get();
1786
1787 // test that with_gate.get() throws when the gate is closed
1788 counter = gate_closed_errors = other_errors = 0;
1789 BOOST_CHECK_THROW(with_gate(g, [&] { counter++; }).get(), gate_closed_exception);
1790 BOOST_REQUIRE(!counter);
1791
1792 // test that with_gate throws when the gate is closed
1793 counter = gate_closed_errors = other_errors = 0;
1794 BOOST_CHECK_THROW(with_gate(g, [&] {
1795 counter++;
1796 }).then_wrapped([&] (future<> f) {
1797 auto eptr = f.get_exception();
1798 try {
1799 std::rethrow_exception(eptr);
1800 } catch (gate_closed_exception& e) {
1801 gate_closed_errors++;
1802 } catch (...) {
1803 other_errors++;
1804 }
1805 }).get(), gate_closed_exception);
1806 BOOST_REQUIRE(!counter);
1807 BOOST_REQUIRE(!gate_closed_errors);
1808 BOOST_REQUIRE(!other_errors);
1809
1810 // test that try_with_gate returns gate_closed_exception when the gate is closed
1811 counter = gate_closed_errors = other_errors = 0;
1812 try_with_gate(g, [&] { counter++; }).handle_exception_type([&] (gate_closed_exception& e) {
1813 gate_closed_errors++;
1814 }).handle_exception([&] (std::exception_ptr) {
1815 other_errors++;
1816 }).get();
1817 BOOST_REQUIRE(!counter);
1818 BOOST_REQUIRE(gate_closed_errors);
1819 BOOST_REQUIRE(!other_errors);
1820}
1821
1822SEASTAR_THREAD_TEST_CASE(test_max_concurrent_for_each) {
1823 BOOST_TEST_MESSAGE("empty range");
1824 max_concurrent_for_each(std::vector<int>(), 3, [] (int) {
1825 BOOST_FAIL("should not reach");
1826 return make_exception_future<>(std::bad_function_call());
1827 }).get();
1828
1829 auto range = boost::copy_range<std::vector<int>>(boost::irange(1, 8));
1830
1831 BOOST_TEST_MESSAGE("iterator");
1832 auto sum = 0;
1833 max_concurrent_for_each(range.begin(), range.end(), 3, [&sum] (int v) {
1834 sum += v;
1835 return make_ready_future<>();
1836 }).get();
1837 BOOST_REQUIRE_EQUAL(sum, 28);
1838
1839 BOOST_TEST_MESSAGE("const iterator");
1840 sum = 0;
1841 max_concurrent_for_each(range.cbegin(), range.cend(), 3, [&sum] (int v) {
1842 sum += v;
1843 return make_ready_future<>();
1844 }).get();
1845 BOOST_REQUIRE_EQUAL(sum, 28);
1846
1847 BOOST_TEST_MESSAGE("reverse iterator");
1848 sum = 0;
1849 max_concurrent_for_each(range.rbegin(), range.rend(), 3, [&sum] (int v) {
1850 sum += v;
1851 return make_ready_future<>();
1852 }).get();
1853 BOOST_REQUIRE_EQUAL(sum, 28);
1854
1855 BOOST_TEST_MESSAGE("immediate result");
1856 sum = 0;
1857 max_concurrent_for_each(range, 3, [&sum] (int v) {
1858 sum += v;
1859 return make_ready_future<>();
1860 }).get();
1861 BOOST_REQUIRE_EQUAL(sum, 28);
1862
1863 BOOST_TEST_MESSAGE("suspend");
1864 sum = 0;
1865 max_concurrent_for_each(range, 3, [&sum] (int v) {
1e59de90 1866 return yield().then([&sum, v] {
f67539c2
TL
1867 sum += v;
1868 });
1869 }).get();
1870 BOOST_REQUIRE_EQUAL(sum, 28);
1871
1872 BOOST_TEST_MESSAGE("throw immediately");
1873 sum = 0;
1874 BOOST_CHECK_EXCEPTION(max_concurrent_for_each(range, 3, [&sum] (int v) {
1875 sum += v;
1876 if (v == 1) {
1877 throw 5;
1878 }
1879 return make_ready_future<>();
1880 }).get(), int, [] (int v) { return v == 5; });
1881 BOOST_REQUIRE_EQUAL(sum, 28);
1882
1883 BOOST_TEST_MESSAGE("throw after suspension");
1884 sum = 0;
1885 BOOST_CHECK_EXCEPTION(max_concurrent_for_each(range, 3, [&sum] (int v) {
1e59de90 1886 return yield().then([&sum, v] {
f67539c2
TL
1887 sum += v;
1888 if (v == 2) {
1889 throw 5;
1890 }
1891 });
1892 }).get(), int, [] (int v) { return v == 5; });
1893
1894 BOOST_TEST_MESSAGE("concurrency higher than vector length");
1895 sum = 0;
1896 max_concurrent_for_each(range, range.size() + 3, [&sum] (int v) {
1897 sum += v;
1898 return make_ready_future<>();
1899 }).get();
1900 BOOST_REQUIRE_EQUAL(sum, 28);
1901}
20effc67
TL
1902
1903SEASTAR_THREAD_TEST_CASE(test_for_each_set) {
1904 std::bitset<32> s;
1905 s.set(4);
1906 s.set(0);
1907
1908 auto range = bitsets::for_each_set(s);
1909 unsigned res = 0;
1910 do_for_each(range, [&res] (auto i) {
1911 res |= 1 << i;
1912 }).get();
1913 BOOST_REQUIRE_EQUAL(res, 17);
1914}
1e59de90
TL
1915
1916SEASTAR_THREAD_TEST_CASE(test_yield) {
1917 bool flag = false;
1918 auto one = yield().then([&] {
1919 flag = true;
1920 });
1921 BOOST_REQUIRE_EQUAL(flag, false);
1922 one.get();
1923 BOOST_REQUIRE_EQUAL(flag, true);
1924
1925#ifndef SEASTAR_DEBUG
1926 // same thing, with now(), but for non-DEBUG only, otherwise .then() doesn't
1927 // use the ready-future fast-path and always schedules a task
1928 flag = false;
1929 auto two = now().then([&] {
1930 flag = true;
1931 });
1932 // now() does not yield
1933 BOOST_REQUIRE_EQUAL(flag, true);
1934#endif
1935}
1936
1937// The seastar::make_exception_future() function has two distinct cases - it
1938// can create an exceptional future from an existing std::exception_ptr, or
1939// from an any object which will be wrapped in an std::exception_ptr using
1940// std::make_exception_ptr. We want to test here these two cases, as well
1941// what happens when the given parameter is almost a std::exception_ptr,
1942// just with different qualifiers, like && or const (see issue #1010).
1943SEASTAR_TEST_CASE(test_make_exception_future) {
1944 // When make_exception_future() is given most types - like int and
1945 // std::runtime_error - a copy of the given value get stored in the
1946 // future (internally, it is wrapped using std::make_exception_ptr):
1947 future<> f1 = make_exception_future<>(3);
1948 BOOST_REQUIRE(f1.failed());
1949 BOOST_REQUIRE_THROW(f1.get(), int);
1950 future<> f2 = make_exception_future<>(std::runtime_error("hello"));
1951 BOOST_REQUIRE(f2.failed());
1952 BOOST_REQUIRE_THROW(f2.get(), std::runtime_error);
1953 // However, if make_exception_future() is given an std::exception_ptr
1954 // it behaves differently - the exception stored in the future will be
1955 // the one held in the given exception_ptr - not the exception_ptr object
1956 // itself.
1957 std::exception_ptr e3 = std::make_exception_ptr(3);
1958 future<> f3 = make_exception_future<>(e3);
1959 BOOST_REQUIRE(f3.failed());
1960 BOOST_REQUIRE_THROW(f3.get(), int); // expecting int, not std::exception_ptr
1961 // If make_exception_future() is given an std::exception_ptr by rvalue,
1962 // it should also work correctly:
1963 // An unnamed rvalue:
1964 future<> f4 = make_exception_future<>(std::make_exception_ptr(3));
1965 BOOST_REQUIRE(f4.failed());
1966 BOOST_REQUIRE_THROW(f4.get(), int); // expecting int, not std::exception_ptr
1967 // A rvalue reference (a move):
1968 std::exception_ptr e5 = std::make_exception_ptr(3);
1969 future<> f5 = make_exception_future<>(std::move(e5)); // note std::move()
1970 BOOST_REQUIRE(f5.failed());
1971 BOOST_REQUIRE_THROW(f5.get(), int); // expecting int, not std::exception_ptr
1972 // A rvalue reference to a *const* exception_ptr:
1973 // Reproduces issue #1010 - a const exception_ptr sounds odd, but can
1974 // happen accidentally when capturing an exception_ptr in a non-mutable
1975 // lambda.
1976 // Note that C++ is fine with std::move() being used on a const object,
1977 // it will simply fall back to a copy instead of a move. And a copy does
1978 // work (without std::move(), it works).
1979 const std::exception_ptr e6 = std::make_exception_ptr(3); // note const!
1980 future<> f6 = make_exception_future<>(std::move(e6)); // note std::move()
1981 BOOST_REQUIRE(f6.failed());
1982 BOOST_REQUIRE_THROW(f6.get(), int); // expecting int, not std::exception_ptr
1983
1984 return make_ready_future<>();
1985}