/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2022 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include "common/async/OpaqueFuture.hh"
#include "unit_tests/common/async/FollyExecutorFixture.hh"
#include
#include
using eos::common::OpaqueFuture;
TEST(OpaqueFuture, BasicStdFuture)
{
std::promise p;
auto f = p.get_future();
eos::common::OpaqueFuture of(std::move(f));
ASSERT_TRUE(of.valid());
EXPECT_FALSE(of.ready());
p.set_value(42);
EXPECT_TRUE(of.ready());
EXPECT_EQ(of.getValue(), 42);
}
TEST(OpaqueFuture, VoidStdFuture)
{
std::promise p;
auto f = p.get_future();
eos::common::OpaqueFuture of(std::move(f));
ASSERT_TRUE(of.valid());
EXPECT_FALSE(of.ready());
p.set_value();
EXPECT_TRUE(of.ready());
of.getValue();
}
// We sneak in a folly::Unit as a void future!
TEST(OpaqueFuture, VoidFollyFuture)
{
folly::Promise p;
auto f = p.getFuture();
static_assert(std::is_same_v>);
eos::common::OpaqueFuture of(std::move(f));
ASSERT_TRUE(of.valid());
EXPECT_FALSE(of.ready());
p.setValue();
EXPECT_TRUE(of.ready());
of.getValue();
}
TEST(OpaqueFuture, BasicfollyFuture)
{
folly::Promise p;
auto f = p.getFuture();
static_assert(std::is_same_v>);
eos::common::OpaqueFuture of(std::move(f));
ASSERT_TRUE(of.valid());
EXPECT_FALSE(of.ready());
p.setValue(42);
EXPECT_TRUE(of.ready());
EXPECT_EQ(of.getValue(), 42);
}
TEST(OpaqueFuture, BasicfollySemiFuture)
{
folly::Promise p;
auto f = p.getSemiFuture();
static_assert(std::is_same_v>);
eos::common::OpaqueFuture of(std::move(f));
ASSERT_TRUE(of.valid());
EXPECT_FALSE(of.ready());
p.setValue(42);
EXPECT_TRUE(of.ready());
EXPECT_EQ(of.getValue(), 42);
}
// Shamelessly borrowed from FutureWrapperTests
TEST(OpaqueFuture, stdExceptions)
{
std::promise promise;
OpaqueFuture fut(promise.get_future());
ASSERT_FALSE(fut.ready());
promise.set_exception(std::make_exception_ptr(
std::runtime_error("something terrible happened")));
ASSERT_TRUE(fut.ready());
try {
fut.getValue();
FAIL(); // should never reach here
} catch (const std::runtime_error&
exc) { // yes, you can use strings as exceptions
ASSERT_STREQ(exc.what(), "something terrible happened");
}
}
TEST(OpaqueFuture, follyExceptions)
{
folly::Promise promise;
OpaqueFuture fut(promise.getFuture());
ASSERT_FALSE(fut.ready());
promise.setException(folly::exception_wrapper(
std::runtime_error("something terrible happened")));
ASSERT_TRUE(fut.ready());
try {
fut.getValue();
FAIL(); // should never reach here
} catch (const std::runtime_error&
exc) { // yes, you can use strings as exceptions
ASSERT_STREQ(exc.what(), "something terrible happened");
}
}
int fib(int n)
{
if (n < 3) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
}
TEST(OpaqueFuture, StdFutureWait)
{
// This executes a std:future asynchronously in a new thread and we wrap the
// resulting std::future in our OpaqueFuture. Since this takes a few 100ms
// the result shouldn't be immediately seen as ready.
OpaqueFuture f(std::async(std::launch::async, []() {
return fib(40);
}));
// This usually takes a few 100 msec.
EXPECT_FALSE(f.ready());
f.wait();
EXPECT_TRUE(f.ready());
// GetValue actually does a wait call so the f.ready() calls are redundant, however
// this is just to demonstrate wait() functionality that makes a future value "ready"
EXPECT_EQ(f.getValue(), 102334155);
}
TEST_F(FollyExecutor_F, follyOpaqueFutureWait)
{
auto f = folly::makeFuture().via(folly_io_executor.get()).then([](auto&&) {
return fib(40);
});
OpaqueFuture of(std::move(f));
EXPECT_FALSE(of.ready());
of.wait();
EXPECT_TRUE(of.ready());
EXPECT_EQ(of.getValue(), 102334155);
}