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>
24 using namespace folly;
27 explicit ManualWaiter(std::shared_ptr<ManualExecutor> ex) : ex(ex) {}
34 std::shared_ptr<ManualExecutor> ex;
37 struct ViaFixture : public testing::Test {
39 westExecutor(new ManualExecutor),
40 eastExecutor(new ManualExecutor),
41 waiter(new ManualWaiter(westExecutor)),
45 ManualWaiter eastWaiter(eastExecutor);
47 eastWaiter.makeProgress();
53 eastExecutor->add([=]() { });
57 void addAsync(int a, int b, std::function<void(int&&)>&& cob) {
58 eastExecutor->add([=]() {
63 std::shared_ptr<ManualExecutor> westExecutor;
64 std::shared_ptr<ManualExecutor> eastExecutor;
65 std::shared_ptr<ManualWaiter> waiter;
66 InlineExecutor inlineExecutor;
71 TEST(Via, exception_on_launch) {
72 auto future = makeFuture<int>(std::runtime_error("E"));
73 EXPECT_THROW(future.value(), std::runtime_error);
76 TEST(Via, then_value) {
77 auto future = makeFuture(std::move(1))
78 .then([](Try<int>&& t) {
79 return t.value() == 1;
83 EXPECT_TRUE(future.value());
86 TEST(Via, then_future) {
87 auto future = makeFuture(1)
88 .then([](Try<int>&& t) {
89 return makeFuture(t.value() == 1);
92 EXPECT_TRUE(future.value());
95 static Future<std::string> doWorkStatic(Try<std::string>&& t) {
96 return makeFuture(t.value() + ";static");
99 TEST(Via, then_function) {
101 Future<std::string> doWork(Try<std::string>&& t) {
102 return makeFuture(t.value() + ";class");
104 static Future<std::string> doWorkStatic(Try<std::string>&& t) {
105 return makeFuture(t.value() + ";class-static");
109 auto f = makeFuture(std::string("start"))
111 .then(Worker::doWorkStatic)
112 .then(&w, &Worker::doWork)
115 EXPECT_EQ(f.value(), "start;static;class-static;class");
118 TEST_F(ViaFixture, deactivateChain) {
120 auto f = makeFuture().deactivate();
121 EXPECT_FALSE(f.isActive());
122 auto f2 = f.then([&](Try<void>){ flag = true; });
126 TEST_F(ViaFixture, deactivateActivateChain) {
128 // you can do this all day long with temporaries.
129 auto f1 = makeFuture().deactivate().activate().deactivate();
130 // Chaining on activate/deactivate requires an rvalue, so you have to move
131 // one of these two ways (if you're not using a temporary).
132 auto f2 = std::move(f1).activate();
134 auto f3 = std::move(f2.activate());
135 f3.then([&](Try<void>){ flag = true; });
139 TEST_F(ViaFixture, thread_hops) {
140 auto westThreadId = std::this_thread::get_id();
141 auto f = via(eastExecutor.get()).then([=](Try<void>&& t) {
142 EXPECT_NE(std::this_thread::get_id(), westThreadId);
143 return makeFuture<int>(1);
144 }).via(westExecutor.get()
145 ).then([=](Try<int>&& t) {
146 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
149 while (!f.isReady()) {
150 waiter->makeProgress();
152 EXPECT_EQ(f.value(), 1);
155 TEST_F(ViaFixture, chain_vias) {
156 auto westThreadId = std::this_thread::get_id();
157 auto f = via(eastExecutor.get()).then([=](Try<void>&& t) {
158 EXPECT_NE(std::this_thread::get_id(), westThreadId);
159 return makeFuture<int>(1);
160 }).then([=](Try<int>&& t) {
162 return makeFuture(std::move(val)).via(westExecutor.get())
163 .then([=](Try<int>&& t) mutable {
164 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
167 }).then([=](Try<int>&& t) {
168 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
172 while (!f.isReady()) {
173 waiter->makeProgress();
175 EXPECT_EQ(f.value(), 1);
178 TEST_F(ViaFixture, bareViaAssignment) {
179 auto f = via(eastExecutor.get());
181 TEST_F(ViaFixture, viaAssignment) {
183 auto f = makeFuture().via(eastExecutor.get());
185 auto f2 = f.via(eastExecutor.get());