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