Skip to content

Commit e3151f5

Browse files
committed
add tests
1 parent 9a4c0d1 commit e3151f5

1 file changed

Lines changed: 95 additions & 0 deletions

File tree

libs/internal/tests/promise_test.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,3 +441,98 @@ TEST(WhenAll, ConcurrentResolution) {
441441
t4.join();
442442
t5.join();
443443
}
444+
445+
// Verifies that WaitForResult returns nullopt when the promise is never
446+
// resolved within the timeout.
447+
TEST(Promise, WaitForResultTimeout) {
448+
Promise<int> promise;
449+
Future<int> future = promise.GetFuture();
450+
451+
auto result = future.WaitForResult(std::chrono::milliseconds(50));
452+
EXPECT_FALSE(result.has_value());
453+
}
454+
455+
// Verifies that multiple threads can concurrently register continuations on
456+
// the same future before it resolves, and all continuations run after
457+
// resolution.
458+
TEST(Promise, ConcurrentThenRegistration) {
459+
Promise<int> promise;
460+
Future<int> future = promise.GetFuture();
461+
462+
std::atomic<int> count{0};
463+
std::vector<std::thread> threads;
464+
std::vector<Future<std::monostate>> results;
465+
466+
for (int i = 0; i < 10; i++) {
467+
results.push_back(future.Then(
468+
[&count](int const&) {
469+
count++;
470+
return std::monostate{};
471+
},
472+
[](Continuation<void()> f) { f(); }));
473+
}
474+
475+
promise.Resolve(42);
476+
477+
for (auto& r : results) {
478+
ASSERT_TRUE(r.WaitForResult(std::chrono::seconds(5)).has_value());
479+
}
480+
EXPECT_EQ(count, 10);
481+
}
482+
483+
// Verifies that when multiple threads race to resolve the same promise,
484+
// exactly one succeeds and the rest return false.
485+
TEST(Promise, ConcurrentResolveSingleWinner) {
486+
Promise<int> promise;
487+
Future<int> future = promise.GetFuture();
488+
489+
std::atomic<int> winners{0};
490+
std::vector<std::thread> threads;
491+
for (int i = 0; i < 10; i++) {
492+
threads.emplace_back([&promise, &winners, i] {
493+
if (promise.Resolve(i)) {
494+
winners++;
495+
}
496+
});
497+
}
498+
499+
for (auto& t : threads) {
500+
t.join();
501+
}
502+
503+
EXPECT_EQ(winners, 1);
504+
EXPECT_TRUE(future.GetResult().has_value());
505+
}
506+
507+
// Verifies that a chain of Then calls executes correctly when continuations
508+
// are dispatched via a multi-threaded ASIO executor.
509+
TEST(Promise, MultiThreadedASIOExecutor) {
510+
boost::asio::io_context ioc;
511+
auto work = boost::asio::make_work_guard(ioc);
512+
513+
std::vector<std::thread> ioc_threads;
514+
for (int i = 0; i < 4; i++) {
515+
ioc_threads.emplace_back([&ioc] { ioc.run(); });
516+
}
517+
518+
auto executor = [&ioc](Continuation<void()> f) {
519+
boost::asio::post(ioc, std::move(f));
520+
};
521+
522+
Promise<int> promise;
523+
Future<int> result =
524+
promise.GetFuture()
525+
.Then([](int const& v) { return v * 2; }, executor)
526+
.Then([](int const& v) { return v + 1; }, executor);
527+
528+
promise.Resolve(10);
529+
530+
auto r = result.WaitForResult(std::chrono::seconds(5));
531+
ASSERT_TRUE(r.has_value());
532+
EXPECT_EQ(*r, 21);
533+
534+
work.reset();
535+
for (auto& t : ioc_threads) {
536+
t.join();
537+
}
538+
}

0 commit comments

Comments
 (0)