c7b06dd69a4017a66b5f7eb1df389fbdb92ccde9
[folly.git] / folly / futures / test / ExecutorTest.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/futures/InlineExecutor.h>
21 #include <folly/futures/ManualExecutor.h>
22 #include <folly/futures/QueuedImmediateExecutor.h>
23 #include <folly/Baton.h>
24
25 using namespace folly;
26
27 TEST(ManualExecutor, runIsStable) {
28   ManualExecutor x;
29   size_t count = 0;
30   auto f1 = [&]() { count++; };
31   auto f2 = [&]() { x.add(f1); x.add(f1); };
32   x.add(f2);
33   x.run();
34 }
35
36 TEST(ManualExecutor, scheduleDur) {
37   ManualExecutor x;
38   size_t count = 0;
39   std::chrono::milliseconds dur {10};
40   x.schedule([&]{ count++; }, dur);
41   EXPECT_EQ(count, 0);
42   x.run();
43   EXPECT_EQ(count, 0);
44   x.advance(dur/2);
45   EXPECT_EQ(count, 0);
46   x.advance(dur/2);
47   EXPECT_EQ(count, 1);
48 }
49
50 TEST(ManualExecutor, clockStartsAt0) {
51   ManualExecutor x;
52   EXPECT_EQ(x.now(), x.now().min());
53 }
54
55 TEST(ManualExecutor, scheduleAbs) {
56   ManualExecutor x;
57   size_t count = 0;
58   x.scheduleAt([&]{ count++; }, x.now() + std::chrono::milliseconds(10));
59   EXPECT_EQ(count, 0);
60   x.advance(std::chrono::milliseconds(10));
61   EXPECT_EQ(count, 1);
62 }
63
64 TEST(ManualExecutor, advanceTo) {
65   ManualExecutor x;
66   size_t count = 0;
67   x.scheduleAt([&]{ count++; }, std::chrono::steady_clock::now());
68   EXPECT_EQ(count, 0);
69   x.advanceTo(std::chrono::steady_clock::now());
70   EXPECT_EQ(count, 1);
71 }
72
73 TEST(ManualExecutor, advanceBack) {
74   ManualExecutor x;
75   size_t count = 0;
76   x.advance(std::chrono::microseconds(5));
77   x.schedule([&]{ count++; }, std::chrono::microseconds(6));
78   EXPECT_EQ(count, 0);
79   x.advanceTo(x.now() - std::chrono::microseconds(1));
80   EXPECT_EQ(count, 0);
81 }
82
83 TEST(ManualExecutor, advanceNeg) {
84   ManualExecutor x;
85   size_t count = 0;
86   x.advance(std::chrono::microseconds(5));
87   x.schedule([&]{ count++; }, std::chrono::microseconds(6));
88   EXPECT_EQ(count, 0);
89   x.advance(std::chrono::microseconds(-1));
90   EXPECT_EQ(count, 0);
91 }
92
93 TEST(ManualExecutor, waitForDoesNotDeadlock) {
94   ManualExecutor east, west;
95   folly::Baton<> baton;
96   auto f = makeFuture()
97     .via(&east)
98     .then([](Try<void>){ return makeFuture(); })
99     .via(&west);
100   std::thread t([&]{
101     baton.post();
102     west.waitFor(f);
103   });
104   baton.wait();
105   east.run();
106   t.join();
107 }
108
109 TEST(Executor, InlineExecutor) {
110   InlineExecutor x;
111   size_t counter = 0;
112   x.add([&]{
113     x.add([&]{
114       EXPECT_EQ(counter, 0);
115       counter++;
116     });
117     EXPECT_EQ(counter, 1);
118     counter++;
119   });
120   EXPECT_EQ(counter, 2);
121 }
122
123 TEST(Executor, QueuedImmediateExecutor) {
124   QueuedImmediateExecutor x;
125   size_t counter = 0;
126   x.add([&]{
127     x.add([&]{
128       EXPECT_EQ(1, counter);
129       counter++;
130     });
131     EXPECT_EQ(0, counter);
132     counter++;
133   });
134   EXPECT_EQ(2, counter);
135 }
136
137 TEST(Executor, Runnable) {
138   InlineExecutor x;
139   size_t counter = 0;
140   struct Runnable {
141     std::function<void()> fn;
142     void operator()() { fn(); }
143   };
144   Runnable f;
145   f.fn = [&]{ counter++; };
146   x.add(f);
147   EXPECT_EQ(counter, 1);
148 }
149
150 TEST(Executor, RunnablePtr) {
151   InlineExecutor x;
152   struct Runnable {
153     std::function<void()> fn;
154     void operator()() { fn(); }
155   };
156   size_t counter = 0;
157   auto fnp = std::make_shared<Runnable>();
158   fnp->fn = [&]{ counter++; };
159   x.addPtr(fnp);
160   EXPECT_EQ(counter, 1);
161 }
162
163 TEST(Executor, ThrowableThen) {
164   InlineExecutor x;
165   auto f = Future<void>().via(&x).then([](){
166     throw std::runtime_error("Faildog");
167   });
168   EXPECT_THROW(f.value(), std::exception);
169 }
170
171 class CrappyExecutor : public Executor {
172  public:
173   void add(Func f) override {
174     throw std::runtime_error("bad");
175   }
176 };
177
178 TEST(Executor, CrappyExecutor) {
179   CrappyExecutor x;
180   bool flag = false;
181   auto f = folly::via(&x).onError([&](std::runtime_error& e) {
182     EXPECT_STREQ("bad", e.what());
183     flag = true;
184   });
185   EXPECT_TRUE(flag);
186 }