#include <gtest/gtest.h>
+#include <boost/thread/barrier.hpp>
+
#include <folly/futures/Future.h>
#include <folly/Random.h>
#include <folly/small_vector.h>
// check that futures are ready in then()
{
- std::vector<Promise<void>> promises(10);
- std::vector<Future<void>> futures;
+ std::vector<Promise<Unit>> promises(10);
+ std::vector<Future<Unit>> futures;
for (auto& p : promises)
futures.push_back(p.getFuture());
auto allf = collectAll(futures)
- .then([](Try<std::vector<Try<void>>>&& ts) {
+ .then([](Try<std::vector<Try<Unit>>>&& ts) {
for (auto& f : ts.value())
f.value();
});
// void futures success case
{
- std::vector<Promise<void>> promises(10);
- std::vector<Future<void>> futures;
+ std::vector<Promise<Unit>> promises(10);
+ std::vector<Future<Unit>> futures;
for (auto& p : promises)
futures.push_back(p.getFuture());
// void futures failure case
{
- std::vector<Promise<void>> promises(10);
- std::vector<Future<void>> futures;
+ std::vector<Promise<Unit>> promises(10);
+ std::vector<Future<Unit>> futures;
for (auto& p : promises)
futures.push_back(p.getFuture());
// error
{
- std::vector<Promise<void>> promises(10);
- std::vector<Future<void>> futures;
+ std::vector<Promise<Unit>> promises(10);
+ std::vector<Future<Unit>> futures;
for (auto& p : promises)
futures.push_back(p.getFuture());
TEST(Collect, alreadyCompleted) {
{
- std::vector<Future<void>> fs;
+ std::vector<Future<Unit>> fs;
for (int i = 0; i < 10; i++)
fs.push_back(makeFuture());
collectAll(fs)
- .then([&](std::vector<Try<void>> ts) {
+ .then([&](std::vector<Try<Unit>> ts) {
EXPECT_EQ(fs.size(), ts.size());
});
}
}
}
+TEST(Collect, parallel) {
+ std::vector<Promise<int>> ps(10);
+ std::vector<Future<int>> fs;
+ for (size_t i = 0; i < ps.size(); i++) {
+ fs.emplace_back(ps[i].getFuture());
+ }
+ auto f = collect(fs);
+
+ std::vector<std::thread> ts;
+ boost::barrier barrier(ps.size() + 1);
+ for (size_t i = 0; i < ps.size(); i++) {
+ ts.emplace_back([&ps, &barrier, i]() {
+ barrier.wait();
+ ps[i].setValue(i);
+ });
+ }
+
+ barrier.wait();
+
+ for (size_t i = 0; i < ps.size(); i++) {
+ ts[i].join();
+ }
+
+ EXPECT_TRUE(f.isReady());
+ for (size_t i = 0; i < ps.size(); i++) {
+ EXPECT_EQ(i, f.value()[i]);
+ }
+}
+
+TEST(Collect, parallelWithError) {
+ std::vector<Promise<int>> ps(10);
+ std::vector<Future<int>> fs;
+ for (size_t i = 0; i < ps.size(); i++) {
+ fs.emplace_back(ps[i].getFuture());
+ }
+ auto f = collect(fs);
+
+ std::vector<std::thread> ts;
+ boost::barrier barrier(ps.size() + 1);
+ for (size_t i = 0; i < ps.size(); i++) {
+ ts.emplace_back([&ps, &barrier, i]() {
+ barrier.wait();
+ if (i == (ps.size()/2)) {
+ ps[i].setException(eggs);
+ } else {
+ ps[i].setValue(i);
+ }
+ });
+ }
+
+ barrier.wait();
+
+ for (size_t i = 0; i < ps.size(); i++) {
+ ts[i].join();
+ }
+
+ EXPECT_TRUE(f.isReady());
+ EXPECT_THROW(f.value(), eggs_t);
+}
+
+TEST(Collect, allParallel) {
+ std::vector<Promise<int>> ps(10);
+ std::vector<Future<int>> fs;
+ for (size_t i = 0; i < ps.size(); i++) {
+ fs.emplace_back(ps[i].getFuture());
+ }
+ auto f = collectAll(fs);
+
+ std::vector<std::thread> ts;
+ boost::barrier barrier(ps.size() + 1);
+ for (size_t i = 0; i < ps.size(); i++) {
+ ts.emplace_back([&ps, &barrier, i]() {
+ barrier.wait();
+ ps[i].setValue(i);
+ });
+ }
+
+ barrier.wait();
+
+ for (size_t i = 0; i < ps.size(); i++) {
+ ts[i].join();
+ }
+
+ EXPECT_TRUE(f.isReady());
+ for (size_t i = 0; i < ps.size(); i++) {
+ EXPECT_TRUE(f.value()[i].hasValue());
+ EXPECT_EQ(i, f.value()[i].value());
+ }
+}
+
+TEST(Collect, allParallelWithError) {
+ std::vector<Promise<int>> ps(10);
+ std::vector<Future<int>> fs;
+ for (size_t i = 0; i < ps.size(); i++) {
+ fs.emplace_back(ps[i].getFuture());
+ }
+ auto f = collectAll(fs);
+
+ std::vector<std::thread> ts;
+ boost::barrier barrier(ps.size() + 1);
+ for (size_t i = 0; i < ps.size(); i++) {
+ ts.emplace_back([&ps, &barrier, i]() {
+ barrier.wait();
+ if (i == (ps.size()/2)) {
+ ps[i].setException(eggs);
+ } else {
+ ps[i].setValue(i);
+ }
+ });
+ }
+
+ barrier.wait();
+
+ for (size_t i = 0; i < ps.size(); i++) {
+ ts[i].join();
+ }
+
+ EXPECT_TRUE(f.isReady());
+ for (size_t i = 0; i < ps.size(); i++) {
+ if (i == (ps.size()/2)) {
+ EXPECT_THROW(f.value()[i].value(), eggs_t);
+ } else {
+ EXPECT_TRUE(f.value()[i].hasValue());
+ EXPECT_EQ(i, f.value()[i].value());
+ }
+ }
+}
+
TEST(Collect, collectN) {
- std::vector<Promise<void>> promises(10);
- std::vector<Future<void>> futures;
+ std::vector<Promise<Unit>> promises(10);
+ std::vector<Future<Unit>> futures;
for (auto& p : promises)
futures.push_back(p.getFuture());
bool flag = false;
size_t n = 3;
collectN(futures, n)
- .then([&](std::vector<std::pair<size_t, Try<void>>> v) {
+ .then([&](std::vector<std::pair<size_t, Try<Unit>>> v) {
flag = true;
EXPECT_EQ(n, v.size());
for (auto& tt : v)
/// Ensure that we can compile collectAll/Any with folly::small_vector
TEST(Collect, smallVector) {
- static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<void>),
+ static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<Unit>),
"Futures should not be trivially copyable");
static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<int>),
"Futures should not be trivially copyable");
{
- folly::small_vector<Future<void>> futures;
+ folly::small_vector<Future<Unit>> futures;
for (int i = 0; i < 10; i++)
futures.push_back(makeFuture());
auto anyf = collectAny(futures);
}
{
- folly::small_vector<Future<void>> futures;
+ folly::small_vector<Future<Unit>> futures;
for (int i = 0; i < 10; i++)
futures.push_back(makeFuture());
EXPECT_TRUE(flag);
}
+TEST(Collect, collectAllVariadicWithException) {
+ Promise<bool> pb;
+ Promise<int> pi;
+ Future<bool> fb = pb.getFuture();
+ Future<int> fi = pi.getFuture();
+ bool flag = false;
+ collectAll(std::move(fb), std::move(fi))
+ .then([&](std::tuple<Try<bool>, Try<int>> tup) {
+ flag = true;
+ EXPECT_TRUE(std::get<0>(tup).hasValue());
+ EXPECT_EQ(std::get<0>(tup).value(), true);
+ EXPECT_TRUE(std::get<1>(tup).hasException());
+ EXPECT_THROW(std::get<1>(tup).value(), eggs_t);
+ });
+ pb.setValue(true);
+ EXPECT_FALSE(flag);
+ pi.setException(eggs);
+ EXPECT_TRUE(flag);
+}
+
+TEST(Collect, collectVariadic) {
+ Promise<bool> pb;
+ Promise<int> pi;
+ Future<bool> fb = pb.getFuture();
+ Future<int> fi = pi.getFuture();
+ bool flag = false;
+ collect(std::move(fb), std::move(fi))
+ .then([&](std::tuple<bool, int> tup) {
+ flag = true;
+ EXPECT_EQ(std::get<0>(tup), true);
+ EXPECT_EQ(std::get<1>(tup), 42);
+ });
+ pb.setValue(true);
+ EXPECT_FALSE(flag);
+ pi.setValue(42);
+ EXPECT_TRUE(flag);
+}
+
+TEST(Collect, collectVariadicWithException) {
+ Promise<bool> pb;
+ Promise<int> pi;
+ Future<bool> fb = pb.getFuture();
+ Future<int> fi = pi.getFuture();
+ auto f = collect(std::move(fb), std::move(fi));
+ pb.setValue(true);
+ EXPECT_FALSE(f.isReady());
+ pi.setException(eggs);
+ EXPECT_TRUE(f.isReady());
+ EXPECT_TRUE(f.getTry().hasException());
+ EXPECT_THROW(f.get(), eggs_t);
+}
+
TEST(Collect, collectAllNone) {
std::vector<Future<int>> fs;
auto f = collectAll(fs);
EXPECT_TRUE(f.isReady());
}
+
+TEST(Collect, noDefaultConstructor) {
+ struct A {
+ explicit A(size_t /* x */) {}
+ };
+
+ auto f1 = makeFuture(A(1));
+ auto f2 = makeFuture(A(2));
+
+ auto f = collect(std::move(f1), std::move(f2));
+}