2 * Copyright 2015 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>
23 #include <gtest/gtest.h>
26 using namespace std::chrono;
27 using namespace folly;
29 // Runs func num_times in parallel, expects that all of them will take
30 // at least min_duration and at least 1 execution will take less than
32 template <typename D, typename F>
33 void multiAttemptExpectDurationWithin(size_t num_tries,
37 vector<thread> threads(num_tries);
38 vector<D> durations(num_tries, D::min());
39 for (size_t i = 0; i < num_tries; ++i) {
40 threads[i] = thread([&,i]{
41 auto start = steady_clock::now();
43 durations[i] = duration_cast<D>(steady_clock::now() - start);
46 for (auto& t : threads) {
49 sort(durations.begin(), durations.end());
50 for (auto d : durations) {
51 EXPECT_GE(d, min_duration);
53 EXPECT_LE(durations[0], max_duration);
56 TEST(RetryingTest, has_op_call) {
57 using ew = exception_wrapper;
58 auto policy_raw = [](size_t n, const ew&) { return n < 3; };
59 auto policy_fut = [](size_t n, const ew&) { return makeFuture(n < 3); };
60 using namespace futures::detail;
61 EXPECT_TRUE(retrying_policy_traits<decltype(policy_raw)>::is_raw::value);
62 EXPECT_TRUE(retrying_policy_traits<decltype(policy_fut)>::is_fut::value);
65 TEST(RetryingTest, basic) {
66 auto r = futures::retrying(
67 [](size_t n, const exception_wrapper&) { return n < 3; },
70 ? makeFuture<size_t>(runtime_error("ha"))
74 EXPECT_EQ(2, r.value());
77 TEST(RetryingTest, policy_future) {
78 atomic<size_t> sleeps {0};
79 auto r = futures::retrying(
80 [&](size_t n, const exception_wrapper&) {
82 ? makeFuture(++sleeps).then([] { return true; })
87 ? makeFuture<size_t>(runtime_error("ha"))
91 EXPECT_EQ(2, r.value());
95 TEST(RetryingTest, policy_basic) {
96 auto r = futures::retrying(
97 futures::retryingPolicyBasic(3),
100 ? makeFuture<size_t>(runtime_error("ha"))
104 EXPECT_EQ(2, r.value());
107 TEST(RetryingTest, policy_capped_jittered_exponential_backoff) {
108 multiAttemptExpectDurationWithin(5, milliseconds(200), milliseconds(400), []{
109 using ms = milliseconds;
110 auto r = futures::retrying(
111 futures::retryingPolicyCappedJitteredExponentialBackoff(
112 3, ms(100), ms(1000), 0.1, mt19937_64(0),
113 [](size_t, const exception_wrapper&) { return true; }),
116 ? makeFuture<size_t>(runtime_error("ha"))
120 EXPECT_EQ(2, r.value());
124 TEST(RetryingTest, policy_sleep_defaults) {
125 multiAttemptExpectDurationWithin(5, milliseconds(200), milliseconds(400), []{
126 // To ensure that this compiles with default params.
127 using ms = milliseconds;
128 auto r = futures::retrying(
129 futures::retryingPolicyCappedJitteredExponentialBackoff(
130 3, ms(100), ms(1000), 0.1),
133 ? makeFuture<size_t>(runtime_error("ha"))
137 EXPECT_EQ(2, r.value());
142 TEST(RetryingTest, policy_sleep_cancel) {
143 multiAttemptExpectDurationWithin(5, milliseconds(0), milliseconds(10), []{
145 using ms = milliseconds;
146 auto r = futures::retrying(
147 futures::retryingPolicyCappedJitteredExponentialBackoff(
148 5, ms(100), ms(1000), 0.1, rng,
149 [](size_t n, const exception_wrapper&) { return true; }),
152 ? makeFuture<size_t>(runtime_error("ha"))
158 EXPECT_EQ(2, r.value());