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