s/valueTry/getTry/
[folly.git] / folly / wangle / test / LaterTest.cpp
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <gtest/gtest.h>
18 #include <thread>
19
20 #include "folly/wangle/ManualExecutor.h"
21 #include "folly/wangle/InlineExecutor.h"
22 #include "folly/wangle/Later.h"
23
24 using namespace folly::wangle;
25
26 struct ManualWaiter {
27   explicit ManualWaiter(std::shared_ptr<ManualExecutor> ex) : ex(ex) {}
28
29   void makeProgress() {
30     ex->wait();
31     ex->run();
32   }
33
34   std::shared_ptr<ManualExecutor> ex;
35 };
36
37 struct LaterFixture : public testing::Test {
38   LaterFixture() :
39     westExecutor(new ManualExecutor),
40     eastExecutor(new ManualExecutor),
41     waiter(new ManualWaiter(westExecutor)),
42     done(false)
43   {
44     t = std::thread([=] {
45       ManualWaiter eastWaiter(eastExecutor);
46       while (!done)
47         eastWaiter.makeProgress();
48       });
49   }
50
51   ~LaterFixture() {
52     done = true;
53     eastExecutor->add([=]() { });
54     t.join();
55   }
56
57   Later<void> later;
58   std::shared_ptr<ManualExecutor> westExecutor;
59   std::shared_ptr<ManualExecutor> eastExecutor;
60   std::shared_ptr<ManualWaiter> waiter;
61   InlineExecutor inlineExecutor;
62   bool done;
63   std::thread t;
64 };
65
66 TEST(Later, construct_and_launch) {
67   bool fulfilled = false;
68   auto later = Later<void>().then([&](Try<void>&& t) {
69     fulfilled = true;
70     return makeFuture<int>(1);
71   });
72
73   // has not started yet.
74   EXPECT_FALSE(fulfilled);
75
76   EXPECT_EQ(later.launch().value(), 1);
77   EXPECT_TRUE(fulfilled);
78 }
79
80 TEST(Later, then_value) {
81   auto future = Later<int>(std::move(1))
82     .then([](Try<int>&& t) {
83       return t.value() == 1;
84     })
85     .launch();
86
87   EXPECT_TRUE(future.value());
88 }
89
90 TEST(Later, then_future) {
91   auto future = Later<int>(1)
92     .then([](Try<int>&& t) {
93       return makeFuture(t.value() == 1);
94     })
95     .launch();
96   EXPECT_TRUE(future.value());
97 }
98
99 TEST_F(LaterFixture, thread_hops) {
100   auto westThreadId = std::this_thread::get_id();
101   auto future = later.via(eastExecutor.get()).then([=](Try<void>&& t) {
102     EXPECT_NE(std::this_thread::get_id(), westThreadId);
103     return makeFuture<int>(1);
104   }).via(westExecutor.get()
105   ).then([=](Try<int>&& t) {
106     EXPECT_EQ(std::this_thread::get_id(), westThreadId);
107     return t.value();
108   }).launch();
109   while (!future.isReady()) {
110     waiter->makeProgress();
111   }
112   EXPECT_EQ(future.value(), 1);
113 }
114
115 TEST_F(LaterFixture, chain_laters) {
116   auto westThreadId = std::this_thread::get_id();
117   auto future = later.via(eastExecutor.get()).then([=](Try<void>&& t) {
118     EXPECT_NE(std::this_thread::get_id(), westThreadId);
119     return makeFuture<int>(1);
120   }).then([=](Try<int>&& t) {
121     int val = t.value();
122     return Later<int>(std::move(val)).via(westExecutor.get())
123       .then([=](Try<int>&& t) mutable {
124         EXPECT_EQ(std::this_thread::get_id(), westThreadId);
125         return t.value();
126       });
127   }).then([=](Try<int>&& t) {
128     EXPECT_EQ(std::this_thread::get_id(), westThreadId);
129     return t.value();
130   }).launch();
131
132   while (!future.isReady()) {
133     waiter->makeProgress();
134   }
135   EXPECT_EQ(future.value(), 1);
136 }
137
138 TEST_F(LaterFixture, fire_and_forget) {
139   auto west = westExecutor.get();
140   later.via(eastExecutor.get()).then([=](Try<void>&& t) {
141     west->add([]() {});
142   }).fireAndForget();
143   waiter->makeProgress();
144 }