2 * Copyright 2015 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>
19 #include <folly/futures/Future.h>
20 #include <folly/futures/InlineExecutor.h>
21 #include <folly/futures/ManualExecutor.h>
22 #include <folly/futures/DrivableExecutor.h>
23 #include <folly/Baton.h>
24 #include <folly/MPMCQueue.h>
28 using namespace folly;
30 struct ManualWaiter : public DrivableExecutor {
31 explicit ManualWaiter(std::shared_ptr<ManualExecutor> ex) : ex(ex) {}
33 void add(Func f) override {
37 void drive() override {
42 std::shared_ptr<ManualExecutor> ex;
45 struct ViaFixture : public testing::Test {
47 westExecutor(new ManualExecutor),
48 eastExecutor(new ManualExecutor),
49 waiter(new ManualWaiter(westExecutor)),
53 ManualWaiter eastWaiter(eastExecutor);
61 eastExecutor->add([=]() { });
65 void addAsync(int a, int b, std::function<void(int&&)>&& cob) {
66 eastExecutor->add([=]() {
71 std::shared_ptr<ManualExecutor> westExecutor;
72 std::shared_ptr<ManualExecutor> eastExecutor;
73 std::shared_ptr<ManualWaiter> waiter;
74 InlineExecutor inlineExecutor;
79 TEST(Via, exceptionOnLaunch) {
80 auto future = makeFuture<int>(std::runtime_error("E"));
81 EXPECT_THROW(future.value(), std::runtime_error);
84 TEST(Via, thenValue) {
85 auto future = makeFuture(std::move(1))
86 .then([](Try<int>&& t) {
87 return t.value() == 1;
91 EXPECT_TRUE(future.value());
94 TEST(Via, thenFuture) {
95 auto future = makeFuture(1)
96 .then([](Try<int>&& t) {
97 return makeFuture(t.value() == 1);
99 EXPECT_TRUE(future.value());
102 static Future<std::string> doWorkStatic(Try<std::string>&& t) {
103 return makeFuture(t.value() + ";static");
106 TEST(Via, thenFunction) {
108 Future<std::string> doWork(Try<std::string>&& t) {
109 return makeFuture(t.value() + ";class");
111 static Future<std::string> doWorkStatic(Try<std::string>&& t) {
112 return makeFuture(t.value() + ";class-static");
116 auto f = makeFuture(std::string("start"))
118 .then(Worker::doWorkStatic)
119 .then(&Worker::doWork, &w)
122 EXPECT_EQ(f.value(), "start;static;class-static;class");
125 TEST_F(ViaFixture, threadHops) {
126 auto westThreadId = std::this_thread::get_id();
127 auto f = via(eastExecutor.get()).then([=](Try<void>&& t) {
128 EXPECT_NE(std::this_thread::get_id(), westThreadId);
129 return makeFuture<int>(1);
130 }).via(westExecutor.get()
131 ).then([=](Try<int>&& t) {
132 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
135 EXPECT_EQ(f.getVia(waiter.get()), 1);
138 TEST_F(ViaFixture, chainVias) {
139 auto westThreadId = std::this_thread::get_id();
140 auto f = via(eastExecutor.get()).then([=]() {
141 EXPECT_NE(std::this_thread::get_id(), westThreadId);
143 }).then([=](int val) {
144 return makeFuture(val).via(westExecutor.get())
145 .then([=](int val) mutable {
146 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
149 }).then([=](int val) {
150 // even though ultimately the future that triggers this one executed in
151 // the west thread, this then() inherited the executor from its
152 // predecessor, ie the eastExecutor.
153 EXPECT_NE(std::this_thread::get_id(), westThreadId);
155 }).via(westExecutor.get()).then([=](int val) {
156 // go back to west, so we can wait on it
157 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
161 EXPECT_EQ(f.getVia(waiter.get()), 4);
164 TEST_F(ViaFixture, bareViaAssignment) {
165 auto f = via(eastExecutor.get());
167 TEST_F(ViaFixture, viaAssignment) {
169 auto f = makeFuture().via(eastExecutor.get());
171 auto f2 = f.via(eastExecutor.get());
177 .thenMulti([] { return 42; })
183 auto f = makeFuture().thenMulti(
184 [&]{ count++; return 3.14159; },
185 [&](double) { count++; return std::string("hello"); },
186 [&]{ count++; return makeFuture(42); });
187 EXPECT_EQ(42, f.get());
191 struct PriorityExecutor : public Executor {
192 void add(Func f) override {}
194 void addWithPriority(Func, int8_t priority) override {
195 int mid = getNumPriorities() / 2;
196 int p = priority < 0 ?
197 std::max(0, mid + priority) :
198 std::min(getNumPriorities() - 1, mid + priority);
210 uint8_t getNumPriorities() const override {
219 TEST(Via, priority) {
220 PriorityExecutor exe;
221 via(&exe, -1).then([]{});
222 via(&exe, 0).then([]{});
223 via(&exe, 1).then([]{});
224 via(&exe, 42).then([]{}); // overflow should go to max priority
225 via(&exe, -42).then([]{}); // underflow should go to min priority
226 via(&exe).then([]{}); // default to mid priority
227 via(&exe, Executor::LO_PRI).then([]{});
228 via(&exe, Executor::HI_PRI).then([]{});
229 EXPECT_EQ(3, exe.count0);
230 EXPECT_EQ(2, exe.count1);
231 EXPECT_EQ(3, exe.count2);
234 TEST_F(ViaFixture, chainX1) {
237 .thenMultiWithExecutor(eastExecutor.get(),[] { return 42; })
241 TEST_F(ViaFixture, chainX3) {
242 auto westThreadId = std::this_thread::get_id();
244 auto f = via(westExecutor.get()).thenMultiWithExecutor(
247 EXPECT_NE(std::this_thread::get_id(), westThreadId);
248 count++; return 3.14159;
250 [&](double) { count++; return std::string("hello"); },
253 EXPECT_EQ(std::this_thread::get_id(), westThreadId);
254 return makeFuture(42);
256 EXPECT_EQ(42, f.getVia(waiter.get()));
261 ManualExecutor x1, x2;
262 bool a = false, b = false, c = false;
264 .then([&]{ a = true; })
265 .then(&x2, [&]{ b = true; })
266 .then([&]{ c = true; });
284 TEST(Via, then2Variadic) {
285 struct Foo { bool a = false; void foo(Try<void>) { a = true; } };
288 makeFuture().then(&x, &Foo::foo, &f);
294 /// Simple executor that does work in another thread
295 class ThreadExecutor : public Executor {
296 folly::MPMCQueue<Func> funcs;
297 std::atomic<bool> done {false};
299 folly::Baton<> baton;
305 while (!funcs.isEmpty()) {
306 funcs.blockingRead(fn);
313 explicit ThreadExecutor(size_t n = 1024)
315 worker = std::thread(std::bind(&ThreadExecutor::work, this));
324 void add(Func fn) override {
325 funcs.blockingWrite(std::move(fn));
328 void waitForStartup() {
333 TEST(Via, viaThenGetWasRacy) {
335 std::unique_ptr<int> val = folly::via(&x)
336 .then([] { return folly::make_unique<int>(42); })
342 class DummyDrivableExecutor : public DrivableExecutor {
344 void add(Func f) override {}
345 void drive() override { ran = true; }
353 auto f = via(&x).then([]{ return true; });
354 EXPECT_TRUE(f.getVia(&x));
360 auto f = via(&x).then();
365 DummyDrivableExecutor x;
366 auto f = makeFuture(true);
367 EXPECT_TRUE(f.getVia(&x));
375 auto f = via(&x).then();
376 EXPECT_FALSE(f.isReady());
378 EXPECT_TRUE(f.isReady());
382 // try rvalue as well
384 auto f = via(&x).then().waitVia(&x);
385 EXPECT_TRUE(f.isReady());
389 DummyDrivableExecutor x;
390 makeFuture(true).waitVia(&x);
395 TEST(Via, viaRaces) {
398 auto tid = std::this_thread::get_id();
404 .then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
405 .then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
406 .then([&](Try<void>&&) { done = true; });
413 while (!done) x.run();