d2b91f99cecab241a79ff5d2a77a86453853294d
[folly.git] / folly / futures / test / WaitTest.cpp
1 /*
2  * Copyright 2015 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
19 #include <folly/futures/Future.h>
20 #include <folly/io/async/EventBase.h>
21 #include <folly/Baton.h>
22
23 using namespace folly;
24 using std::vector;
25 using std::chrono::milliseconds;
26
27 TEST(Wait, waitImmediate) {
28   makeFuture().wait();
29   auto done = makeFuture(42).wait().value();
30   EXPECT_EQ(42, done);
31
32   vector<int> v{1,2,3};
33   auto done_v = makeFuture(v).wait().value();
34   EXPECT_EQ(v.size(), done_v.size());
35   EXPECT_EQ(v, done_v);
36
37   vector<Future<void>> v_f;
38   v_f.push_back(makeFuture());
39   v_f.push_back(makeFuture());
40   auto done_v_f = collectAll(v_f).wait().value();
41   EXPECT_EQ(2, done_v_f.size());
42
43   vector<Future<bool>> v_fb;
44   v_fb.push_back(makeFuture(true));
45   v_fb.push_back(makeFuture(false));
46   auto fut = collectAll(v_fb);
47   auto done_v_fb = std::move(fut.wait().value());
48   EXPECT_EQ(2, done_v_fb.size());
49 }
50
51 TEST(Wait, wait) {
52   Promise<int> p;
53   Future<int> f = p.getFuture();
54   std::atomic<bool> flag{false};
55   std::atomic<int> result{1};
56   std::atomic<std::thread::id> id;
57
58   std::thread t([&](Future<int>&& tf){
59       auto n = tf.then([&](Try<int> && t) {
60           id = std::this_thread::get_id();
61           return t.value();
62         });
63       flag = true;
64       result.store(n.wait().value());
65     },
66     std::move(f)
67     );
68   while(!flag){}
69   EXPECT_EQ(result.load(), 1);
70   p.setValue(42);
71   t.join();
72   // validate that the callback ended up executing in this thread, which
73   // is more to ensure that this test actually tests what it should
74   EXPECT_EQ(id, std::this_thread::get_id());
75   EXPECT_EQ(result.load(), 42);
76 }
77
78 struct MoveFlag {
79   MoveFlag() = default;
80   MoveFlag& operator=(const MoveFlag&) = delete;
81   MoveFlag(const MoveFlag&) = delete;
82   MoveFlag(MoveFlag&& other) noexcept {
83     other.moved = true;
84   }
85   bool moved{false};
86 };
87
88 TEST(Wait, waitReplacesSelf) {
89   // wait
90   {
91     // lvalue
92     auto f1 = makeFuture(MoveFlag());
93     f1.wait();
94     EXPECT_FALSE(f1.value().moved);
95
96     // rvalue
97     auto f2 = makeFuture(MoveFlag()).wait();
98     EXPECT_FALSE(f2.value().moved);
99   }
100
101   // wait(Duration)
102   {
103     // lvalue
104     auto f1 = makeFuture(MoveFlag());
105     f1.wait(milliseconds(1));
106     EXPECT_FALSE(f1.value().moved);
107
108     // rvalue
109     auto f2 = makeFuture(MoveFlag()).wait(milliseconds(1));
110     EXPECT_FALSE(f2.value().moved);
111   }
112
113   // waitVia
114   {
115     folly::EventBase eb;
116     // lvalue
117     auto f1 = makeFuture(MoveFlag());
118     f1.waitVia(&eb);
119     EXPECT_FALSE(f1.value().moved);
120
121     // rvalue
122     auto f2 = makeFuture(MoveFlag()).waitVia(&eb);
123     EXPECT_FALSE(f2.value().moved);
124   }
125 }
126
127 TEST(Wait, waitWithDuration) {
128  {
129   Promise<int> p;
130   Future<int> f = p.getFuture();
131   f.wait(milliseconds(1));
132   EXPECT_FALSE(f.isReady());
133   p.setValue(1);
134   EXPECT_TRUE(f.isReady());
135  }
136  {
137   Promise<int> p;
138   Future<int> f = p.getFuture();
139   p.setValue(1);
140   f.wait(milliseconds(1));
141   EXPECT_TRUE(f.isReady());
142  }
143  {
144   vector<Future<bool>> v_fb;
145   v_fb.push_back(makeFuture(true));
146   v_fb.push_back(makeFuture(false));
147   auto f = collectAll(v_fb);
148   f.wait(milliseconds(1));
149   EXPECT_TRUE(f.isReady());
150   EXPECT_EQ(2, f.value().size());
151  }
152  {
153   vector<Future<bool>> v_fb;
154   Promise<bool> p1;
155   Promise<bool> p2;
156   v_fb.push_back(p1.getFuture());
157   v_fb.push_back(p2.getFuture());
158   auto f = collectAll(v_fb);
159   f.wait(milliseconds(1));
160   EXPECT_FALSE(f.isReady());
161   p1.setValue(true);
162   EXPECT_FALSE(f.isReady());
163   p2.setValue(true);
164   EXPECT_TRUE(f.isReady());
165  }
166  {
167   auto f = makeFuture().wait(milliseconds(1));
168   EXPECT_TRUE(f.isReady());
169  }
170
171  {
172    Promise<void> p;
173    auto start = std::chrono::steady_clock::now();
174    auto f = p.getFuture().wait(milliseconds(100));
175    auto elapsed = std::chrono::steady_clock::now() - start;
176    EXPECT_GE(elapsed, milliseconds(100));
177    EXPECT_FALSE(f.isReady());
178    p.setValue();
179    EXPECT_TRUE(f.isReady());
180  }
181
182  {
183    // Try to trigger the race where the resultant Future is not yet complete
184    // even if we didn't hit the timeout, and make sure we deal with it properly
185    Promise<void> p;
186    folly::Baton<> b;
187    auto t = std::thread([&]{
188      b.post();
189      /* sleep override */ std::this_thread::sleep_for(milliseconds(100));
190      p.setValue();
191    });
192    b.wait();
193    auto f = p.getFuture().wait(std::chrono::seconds(3600));
194    EXPECT_TRUE(f.isReady());
195    t.join();
196  }
197 }