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