2 * Copyright 2014 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <gtest/gtest.h>
20 #include <folly/futures/Future.h>
21 #include <folly/futures/InlineExecutor.h>
22 #include <folly/futures/ManualExecutor.h>
23 #include <folly/futures/DrivableExecutor.h>
25 using namespace folly;
27 struct ManualWaiter : public DrivableExecutor {
28 explicit ManualWaiter(std::shared_ptr<ManualExecutor> ex) : ex(ex) {}
30 void add(Func f) override {
34 void drive() override {
39 std::shared_ptr<ManualExecutor> ex;
42 struct ViaFixture : public testing::Test {
44 westExecutor(new ManualExecutor),
45 eastExecutor(new ManualExecutor),
46 waiter(new ManualWaiter(westExecutor)),
50 ManualWaiter eastWaiter(eastExecutor);
58 eastExecutor->add([=]() { });
62 void addAsync(int a, int b, std::function<void(int&&)>&& cob) {
63 eastExecutor->add([=]() {
68 std::shared_ptr<ManualExecutor> westExecutor;
69 std::shared_ptr<ManualExecutor> eastExecutor;
70 std::shared_ptr<ManualWaiter> waiter;
71 InlineExecutor inlineExecutor;
76 TEST(Via, exception_on_launch) {
77 auto future = makeFuture<int>(std::runtime_error("E"));
78 EXPECT_THROW(future.value(), std::runtime_error);
81 TEST(Via, then_value) {
82 auto future = makeFuture(std::move(1))
83 .then([](Try<int>&& t) {
84 return t.value() == 1;
88 EXPECT_TRUE(future.value());
91 TEST(Via, then_future) {
92 auto future = makeFuture(1)
93 .then([](Try<int>&& t) {
94 return makeFuture(t.value() == 1);
96 EXPECT_TRUE(future.value());
99 static Future<std::string> doWorkStatic(Try<std::string>&& t) {
100 return makeFuture(t.value() + ";static");
103 TEST(Via, then_function) {
105 Future<std::string> doWork(Try<std::string>&& t) {
106 return makeFuture(t.value() + ";class");
108 static Future<std::string> doWorkStatic(Try<std::string>&& t) {
109 return makeFuture(t.value() + ";class-static");
113 auto f = makeFuture(std::string("start"))
115 .then(Worker::doWorkStatic)
116 .then(&Worker::doWork, &w)
119 EXPECT_EQ(f.value(), "start;static;class-static;class");
122 TEST_F(ViaFixture, thread_hops) {
123 auto westThreadId = std::this_thread::get_id();
124 auto f = via(eastExecutor.get()).then([=](Try<void>&& t) {
125 EXPECT_NE(std::this_thread::get_id(), westThreadId);
126 return makeFuture<int>(1);
127 }).via(westExecutor.get()
128 ).then([=](Try<int>&& t) {
129 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
132 EXPECT_EQ(f.getVia(waiter.get()), 1);
135 TEST_F(ViaFixture, chain_vias) {
136 auto westThreadId = std::this_thread::get_id();
137 auto f = via(eastExecutor.get()).then([=]() {
138 EXPECT_NE(std::this_thread::get_id(), westThreadId);
140 }).then([=](int val) {
141 return makeFuture(val).via(westExecutor.get())
142 .then([=](int val) mutable {
143 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
146 }).then([=](int val) {
147 // even though ultimately the future that triggers this one executed in
148 // the west thread, this then() inherited the executor from its
149 // predecessor, ie the eastExecutor.
150 EXPECT_NE(std::this_thread::get_id(), westThreadId);
152 }).via(westExecutor.get()).then([=](int val) {
153 // go back to west, so we can wait on it
154 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
158 EXPECT_EQ(f.getVia(waiter.get()), 4);
161 TEST_F(ViaFixture, bareViaAssignment) {
162 auto f = via(eastExecutor.get());
164 TEST_F(ViaFixture, viaAssignment) {
166 auto f = makeFuture().via(eastExecutor.get());
168 auto f2 = f.via(eastExecutor.get());
174 .then(futures::chain<void, int>([] { return 42; }))
180 auto f = makeFuture().then(futures::chain<void, int>(
181 [&]{ count++; return 3.14159; },
182 [&](double) { count++; return std::string("hello"); },
183 [&]{ count++; return makeFuture(42); }));
184 EXPECT_EQ(42, f.get());