allow passing function pointers to Future::onError()
[folly.git] / folly / futures / test / TimekeeperTest.cpp
1 /*
2  * Copyright 2017 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 <folly/futures/Timekeeper.h>
18 #include <folly/portability/GTest.h>
19
20 using namespace folly;
21 using std::chrono::milliseconds;
22
23 std::chrono::milliseconds const zero_ms(0);
24 std::chrono::milliseconds const one_ms(1);
25 std::chrono::milliseconds const awhile(10);
26 std::chrono::seconds const too_long(10);
27
28 std::chrono::steady_clock::time_point now() {
29   return std::chrono::steady_clock::now();
30 }
31
32 struct TimekeeperFixture : public testing::Test {
33   TimekeeperFixture() :
34     timeLord_(folly::detail::getTimekeeperSingleton())
35   {}
36
37   std::shared_ptr<Timekeeper> timeLord_;
38 };
39
40 TEST_F(TimekeeperFixture, after) {
41   auto t1 = now();
42   auto f = timeLord_->after(awhile);
43   EXPECT_FALSE(f.isReady());
44   f.get();
45   auto t2 = now();
46
47   EXPECT_GE(t2 - t1, awhile);
48 }
49
50 TEST(Timekeeper, futureGet) {
51   Promise<int> p;
52   auto t = std::thread([&]{ p.setValue(42); });
53   EXPECT_EQ(42, p.getFuture().get());
54   t.join();
55 }
56
57 TEST(Timekeeper, futureGetBeforeTimeout) {
58   Promise<int> p;
59   auto t = std::thread([&]{ p.setValue(42); });
60   // Technically this is a race and if the test server is REALLY overloaded
61   // and it takes more than a second to do that thread it could be flaky. But
62   // I want a low timeout (in human terms) so if this regresses and someone
63   // runs it by hand they're not sitting there forever wondering why it's
64   // blocked, and get a useful error message instead. If it does get flaky,
65   // empirically increase the timeout to the point where it's very improbable.
66   EXPECT_EQ(42, p.getFuture().get(std::chrono::seconds(2)));
67   t.join();
68 }
69
70 TEST(Timekeeper, futureGetTimeout) {
71   Promise<int> p;
72   EXPECT_THROW(p.getFuture().get(one_ms), folly::TimedOut);
73 }
74
75 TEST(Timekeeper, futureSleep) {
76   auto t1 = now();
77   futures::sleep(one_ms).get();
78   EXPECT_GE(now() - t1, one_ms);
79 }
80
81 TEST(Timekeeper, futureDelayed) {
82   auto t1 = now();
83   auto dur = makeFuture()
84     .delayed(one_ms)
85     .then([=]{ return now() - t1; })
86     .get();
87
88   EXPECT_GE(dur, one_ms);
89 }
90
91 TEST(Timekeeper, futureWithinThrows) {
92   Promise<int> p;
93   auto f = p.getFuture()
94     .within(one_ms)
95     .onError([](TimedOut&) { return -1; });
96
97   EXPECT_EQ(-1, f.get());
98 }
99
100 TEST(Timekeeper, futureWithinAlreadyComplete) {
101   auto f = makeFuture(42)
102     .within(one_ms)
103     .onError([&](TimedOut&){ return -1; });
104
105   EXPECT_EQ(42, f.get());
106 }
107
108 TEST(Timekeeper, futureWithinFinishesInTime) {
109   Promise<int> p;
110   auto f = p.getFuture()
111     .within(std::chrono::minutes(1))
112     .onError([&](TimedOut&){ return -1; });
113   p.setValue(42);
114
115   EXPECT_EQ(42, f.get());
116 }
117
118 TEST(Timekeeper, futureWithinVoidSpecialization) {
119   makeFuture().within(one_ms);
120 }
121
122 TEST(Timekeeper, futureWithinException) {
123   Promise<Unit> p;
124   auto f = p.getFuture().within(awhile, std::runtime_error("expected"));
125   EXPECT_THROW(f.get(), std::runtime_error);
126 }
127
128 TEST(Timekeeper, onTimeout) {
129   bool flag = false;
130   makeFuture(42).delayed(10 * one_ms)
131     .onTimeout(zero_ms, [&]{ flag = true; return -1; })
132     .get();
133   EXPECT_TRUE(flag);
134 }
135
136 TEST(Timekeeper, onTimeoutReturnsFuture) {
137   bool flag = false;
138   makeFuture(42).delayed(10 * one_ms)
139     .onTimeout(zero_ms, [&]{ flag = true; return makeFuture(-1); })
140     .get();
141   EXPECT_TRUE(flag);
142 }
143
144 TEST(Timekeeper, onTimeoutVoid) {
145   makeFuture().delayed(one_ms)
146     .onTimeout(zero_ms, [&]{
147      });
148   makeFuture().delayed(one_ms)
149     .onTimeout(zero_ms, [&]{
150        return makeFuture<Unit>(std::runtime_error("expected"));
151      });
152   // just testing compilation here
153 }
154
155 TEST(Timekeeper, interruptDoesntCrash) {
156   auto f = futures::sleep(too_long);
157   f.cancel();
158 }
159
160 TEST(Timekeeper, chainedInterruptTest) {
161   bool test = false;
162   auto f = futures::sleep(milliseconds(100)).then([&](){
163     test = true;
164   });
165   f.cancel();
166   f.wait();
167   EXPECT_FALSE(test);
168 }
169
170 TEST(Timekeeper, executor) {
171   class ExecutorTester : public Executor {
172    public:
173     void add(Func f) override {
174       count++;
175       f();
176     }
177     std::atomic<int> count{0};
178   };
179
180   auto f = makeFuture();
181   ExecutorTester tester;
182   f.via(&tester).within(one_ms).then([&](){}).wait();
183   EXPECT_EQ(2, tester.count);
184 }
185
186 // TODO(5921764)
187 /*
188 TEST(Timekeeper, onTimeoutPropagates) {
189   bool flag = false;
190   EXPECT_THROW(
191     makeFuture(42).delayed(one_ms)
192       .onTimeout(zero_ms, [&]{ flag = true; })
193       .get(),
194     TimedOut);
195   EXPECT_TRUE(flag);
196 }
197 */
198
199 TEST_F(TimekeeperFixture, atBeforeNow) {
200   auto f = timeLord_->at(now() - too_long);
201   EXPECT_TRUE(f.isReady());
202   EXPECT_FALSE(f.hasException());
203 }
204
205 TEST_F(TimekeeperFixture, howToCastDuration) {
206   // I'm not sure whether this rounds up or down but it's irrelevant for the
207   // purpose of this example.
208   auto f = timeLord_->after(std::chrono::duration_cast<Duration>(
209       std::chrono::nanoseconds(1)));
210 }