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) {}
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);
97 EXPECT_TRUE(future.value());
100 static Future<std::string> doWorkStatic(Try<std::string>&& t) {
101 return makeFuture(t.value() + ";static");
104 TEST(Via, then_function) {
106 Future<std::string> doWork(Try<std::string>&& t) {
107 return makeFuture(t.value() + ";class");
109 static Future<std::string> doWorkStatic(Try<std::string>&& t) {
110 return makeFuture(t.value() + ";class-static");
114 auto f = makeFuture(std::string("start"))
116 .then(Worker::doWorkStatic)
117 .then(&Worker::doWork, &w)
120 EXPECT_EQ(f.value(), "start;static;class-static;class");
123 TEST_F(ViaFixture, deactivateChain) {
125 auto f = makeFuture().deactivate();
126 EXPECT_FALSE(f.isActive());
127 auto f2 = f.then([&](Try<void>){ flag = true; });
131 TEST_F(ViaFixture, deactivateActivateChain) {
133 // you can do this all day long with temporaries.
134 auto f1 = makeFuture().deactivate().activate().deactivate();
135 // Chaining on activate/deactivate requires an rvalue, so you have to move
136 // one of these two ways (if you're not using a temporary).
137 auto f2 = std::move(f1).activate();
139 auto f3 = std::move(f2.activate());
140 f3.then([&](Try<void>){ flag = true; });
144 TEST_F(ViaFixture, thread_hops) {
145 auto westThreadId = std::this_thread::get_id();
146 auto f = via(eastExecutor.get()).then([=](Try<void>&& t) {
147 EXPECT_NE(std::this_thread::get_id(), westThreadId);
148 return makeFuture<int>(1);
149 }).via(westExecutor.get()
150 ).then([=](Try<int>&& t) {
151 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
154 EXPECT_EQ(f.getVia(waiter.get()), 1);
157 TEST_F(ViaFixture, chain_vias) {
158 auto westThreadId = std::this_thread::get_id();
159 auto f = via(eastExecutor.get()).then([=](Try<void>&& t) {
160 EXPECT_NE(std::this_thread::get_id(), westThreadId);
161 return makeFuture<int>(1);
162 }).then([=](Try<int>&& t) {
164 return makeFuture(std::move(val)).via(westExecutor.get())
165 .then([=](Try<int>&& t) mutable {
166 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
169 }).then([=](Try<int>&& t) {
170 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
174 EXPECT_EQ(f.getVia(waiter.get()), 1);
177 TEST_F(ViaFixture, bareViaAssignment) {
178 auto f = via(eastExecutor.get());
180 TEST_F(ViaFixture, viaAssignment) {
182 auto f = makeFuture().via(eastExecutor.get());
184 auto f2 = f.via(eastExecutor.get());
190 .then(futures::chain<void, int>([] { return 42; }))
196 auto f = makeFuture().then(futures::chain<void, int>(
197 [&]{ count++; return 3.14159; },
198 [&](double) { count++; return std::string("hello"); },
199 [&]{ count++; return makeFuture(42); }));
200 EXPECT_EQ(42, f.get());