2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <folly/futures/Future.h>
22 #include <folly/portability/GTest.h>
25 using namespace std::chrono;
26 using namespace folly;
28 // Runs func num_times in parallel, expects that all of them will take
29 // at least min_duration and at least 1 execution will take less than
31 template <typename D, typename F>
32 void multiAttemptExpectDurationWithin(size_t num_tries,
36 vector<thread> threads(num_tries);
37 vector<D> durations(num_tries, D::min());
38 for (size_t i = 0; i < num_tries; ++i) {
39 threads[i] = thread([&,i]{
40 auto start = steady_clock::now();
42 durations[i] = duration_cast<D>(steady_clock::now() - start);
45 for (auto& t : threads) {
48 sort(durations.begin(), durations.end());
49 for (auto d : durations) {
50 EXPECT_GE(d, min_duration);
52 EXPECT_LE(durations[0], max_duration);
55 TEST(RetryingTest, has_op_call) {
56 using ew = exception_wrapper;
57 auto policy_raw = [](size_t n, const ew&) { return n < 3; };
58 auto policy_fut = [](size_t n, const ew&) { return makeFuture(n < 3); };
59 using namespace futures::detail;
60 EXPECT_TRUE(retrying_policy_traits<decltype(policy_raw)>::is_raw::value);
61 EXPECT_TRUE(retrying_policy_traits<decltype(policy_fut)>::is_fut::value);
64 TEST(RetryingTest, basic) {
65 auto r = futures::retrying(
66 [](size_t n, const exception_wrapper&) { return n < 3; },
69 ? makeFuture<size_t>(runtime_error("ha"))
73 EXPECT_EQ(2, r.value());
76 TEST(RetryingTest, policy_future) {
77 atomic<size_t> sleeps {0};
78 auto r = futures::retrying(
79 [&](size_t n, const exception_wrapper&) {
81 ? makeFuture(++sleeps).then([] { return true; })
86 ? makeFuture<size_t>(runtime_error("ha"))
90 EXPECT_EQ(2, r.value());
94 TEST(RetryingTest, policy_basic) {
95 auto r = futures::retrying(
96 futures::retryingPolicyBasic(3),
99 ? makeFuture<size_t>(runtime_error("ha"))
103 EXPECT_EQ(2, r.value());
106 TEST(RetryingTest, policy_capped_jittered_exponential_backoff) {
107 multiAttemptExpectDurationWithin(5, milliseconds(200), milliseconds(400), []{
108 using ms = milliseconds;
109 auto r = futures::retrying(
110 futures::retryingPolicyCappedJitteredExponentialBackoff(
111 3, ms(100), ms(1000), 0.1, mt19937_64(0),
112 [](size_t, const exception_wrapper&) { return true; }),
115 ? makeFuture<size_t>(runtime_error("ha"))
119 EXPECT_EQ(2, r.value());
123 TEST(RetryingTest, policy_sleep_defaults) {
124 multiAttemptExpectDurationWithin(5, milliseconds(200), milliseconds(400), []{
125 // To ensure that this compiles with default params.
126 using ms = milliseconds;
127 auto r = futures::retrying(
128 futures::retryingPolicyCappedJitteredExponentialBackoff(
129 3, ms(100), ms(1000), 0.1),
132 ? makeFuture<size_t>(runtime_error("ha"))
136 EXPECT_EQ(2, r.value());
141 TEST(RetryingTest, policy_sleep_cancel) {
142 multiAttemptExpectDurationWithin(5, milliseconds(0), milliseconds(10), []{
144 using ms = milliseconds;
145 auto r = futures::retrying(
146 futures::retryingPolicyCappedJitteredExponentialBackoff(
147 5, ms(100), ms(1000), 0.1, rng,
148 [](size_t n, const exception_wrapper&) { return true; }),
151 ? makeFuture<size_t>(runtime_error("ha"))
157 EXPECT_EQ(2, r.value());