suppress warnings in tests for deprecated functions
[folly.git] / folly / futures / test / CallbackLifetimeTest.cpp
1 /*
2  * Copyright 2017-present 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/Future.h>
18
19 #include <thread>
20
21 #include <folly/futures/test/TestExecutor.h>
22 #include <folly/portability/GTest.h>
23
24 using namespace folly;
25
26 namespace {
27
28 /***
29  *  The basic premise is to check that the callback passed to then or onError
30  *  is destructed before wait returns on the resulting future.
31  *
32  *  The approach is to use callbacks where the destructor sleeps 500ms and then
33  *  mutates a counter allocated on the caller stack. The caller checks the
34  *  counter immediately after calling wait. Were the callback not destructed
35  *  before wait returns, then we would very likely see an unchanged counter just
36  *  after wait returns. But if, as we expect, the callback were destructed
37  *  before wait returns, then we must be guaranteed to see a mutated counter
38  *  just after wait returns.
39  *
40  *  Note that the failure condition is not strictly guaranteed under load. :(
41  */
42 class CallbackLifetimeTest : public testing::Test {
43  public:
44   using CounterPtr = std::unique_ptr<size_t>;
45
46   static bool kRaiseWillThrow() {
47     return true;
48   }
49   static constexpr auto kDelay() {
50     return std::chrono::milliseconds(500);
51   }
52
53   auto mkC() {
54     return std::make_unique<size_t>(0);
55   }
56   auto mkCGuard(CounterPtr& ptr) {
57     return makeGuard([&] {
58       /* sleep override */ std::this_thread::sleep_for(kDelay());
59       ++*ptr;
60     });
61   }
62
63   static void raise() {
64     if (kRaiseWillThrow()) { // to avoid marking [[noreturn]]
65       throw std::runtime_error("raise");
66     }
67   }
68   static Future<Unit> raiseFut() {
69     raise();
70     return makeFuture();
71   }
72
73   TestExecutor executor{2}; // need at least 2 threads for internal futures
74 };
75 } // namespace
76
77 TEST_F(CallbackLifetimeTest, thenReturnsValue) {
78   auto c = mkC();
79   via(&executor).then([_ = mkCGuard(c)]{}).wait();
80   EXPECT_EQ(1, *c);
81 }
82
83 TEST_F(CallbackLifetimeTest, thenReturnsValueThrows) {
84   auto c = mkC();
85   via(&executor).then([_ = mkCGuard(c)] { raise(); }).wait();
86   EXPECT_EQ(1, *c);
87 }
88
89 TEST_F(CallbackLifetimeTest, thenReturnsFuture) {
90   auto c = mkC();
91   via(&executor).then([_ = mkCGuard(c)] { return makeFuture(); }).wait();
92   EXPECT_EQ(1, *c);
93 }
94
95 TEST_F(CallbackLifetimeTest, thenReturnsFutureThrows) {
96   auto c = mkC();
97   via(&executor).then([_ = mkCGuard(c)] { return raiseFut(); }).wait();
98   EXPECT_EQ(1, *c);
99 }
100
101 TEST_F(CallbackLifetimeTest, onErrorTakesExnReturnsValueMatch) {
102   auto c = mkC();
103   via(&executor)
104       .then(raise)
105       .onError([_ = mkCGuard(c)](std::exception&){})
106       .wait();
107   EXPECT_EQ(1, *c);
108 }
109
110 TEST_F(CallbackLifetimeTest, onErrorTakesExnReturnsValueMatchThrows) {
111   auto c = mkC();
112   via(&executor)
113       .then(raise)
114       .onError([_ = mkCGuard(c)](std::exception&) { raise(); })
115       .wait();
116   EXPECT_EQ(1, *c);
117 }
118
119 TEST_F(CallbackLifetimeTest, onErrorTakesExnReturnsValueWrong) {
120   auto c = mkC();
121   via(&executor)
122       .then(raise)
123       .onError([_ = mkCGuard(c)](std::logic_error&){})
124       .wait();
125   EXPECT_EQ(1, *c);
126 }
127
128 TEST_F(CallbackLifetimeTest, onErrorTakesExnReturnsValueWrongThrows) {
129   auto c = mkC();
130   via(&executor)
131       .then(raise)
132       .onError([_ = mkCGuard(c)](std::logic_error&) { raise(); })
133       .wait();
134   EXPECT_EQ(1, *c);
135 }
136
137 TEST_F(CallbackLifetimeTest, onErrorTakesExnReturnsFutureMatch) {
138   auto c = mkC();
139   via(&executor)
140       .then(raise)
141       .onError([_ = mkCGuard(c)](std::exception&) { return makeFuture(); })
142       .wait();
143   EXPECT_EQ(1, *c);
144 }
145
146 TEST_F(CallbackLifetimeTest, onErrorTakesExnReturnsFutureMatchThrows) {
147   auto c = mkC();
148   via(&executor)
149       .then(raise)
150       .onError([_ = mkCGuard(c)](std::exception&) { return raiseFut(); })
151       .wait();
152   EXPECT_EQ(1, *c);
153 }
154
155 TEST_F(CallbackLifetimeTest, onErrorTakesExnReturnsFutureWrong) {
156   auto c = mkC();
157   via(&executor)
158       .then(raise)
159       .onError([_ = mkCGuard(c)](std::logic_error&) { return makeFuture(); })
160       .wait();
161   EXPECT_EQ(1, *c);
162 }
163
164 TEST_F(CallbackLifetimeTest, onErrorTakesExnReturnsFutureWrongThrows) {
165   auto c = mkC();
166   via(&executor)
167       .then(raise)
168       .onError([_ = mkCGuard(c)](std::logic_error&) { return raiseFut(); })
169       .wait();
170   EXPECT_EQ(1, *c);
171 }
172
173 TEST_F(CallbackLifetimeTest, onErrorTakesWrapReturnsValue) {
174   auto c = mkC();
175   via(&executor)
176       .then(raise)
177       .onError([_ = mkCGuard(c)](exception_wrapper &&){})
178       .wait();
179   EXPECT_EQ(1, *c);
180 }
181
182 TEST_F(CallbackLifetimeTest, onErrorTakesWrapReturnsValueThrows) {
183   auto c = mkC();
184   via(&executor)
185       .then(raise)
186       .onError([_ = mkCGuard(c)](exception_wrapper &&) { raise(); })
187       .wait();
188   EXPECT_EQ(1, *c);
189 }
190
191 TEST_F(CallbackLifetimeTest, onErrorTakesWrapReturnsFuture) {
192   auto c = mkC();
193   via(&executor)
194       .then(raise)
195       .onError([_ = mkCGuard(c)](exception_wrapper &&) { return makeFuture(); })
196       .wait();
197   EXPECT_EQ(1, *c);
198 }
199
200 TEST_F(CallbackLifetimeTest, onErrorTakesWrapReturnsFutureThrows) {
201   auto c = mkC();
202   via(&executor)
203       .then(raise)
204       .onError([_ = mkCGuard(c)](exception_wrapper &&) { return raiseFut(); })
205       .wait();
206   EXPECT_EQ(1, *c);
207 }