1 | /* |
2 | * Copyright 2015-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 | #include <folly/portability/GTest.h> |
19 | |
20 | using namespace folly; |
21 | |
22 | TEST(Reduce, basic) { |
23 | auto makeFutures = [](int count) { |
24 | std::vector<Future<int>> fs; |
25 | for (int i = 1; i <= count; ++i) { |
26 | fs.emplace_back(makeFuture(i)); |
27 | } |
28 | return fs; |
29 | }; |
30 | |
31 | // Empty (Try) |
32 | { |
33 | auto fs = makeFutures(0); |
34 | |
35 | Future<double> f1 = |
36 | reduce(fs, 1.2, [](double a, Try<int>&& b) { return a + *b + 0.1; }); |
37 | EXPECT_EQ(1.2, std::move(f1).get()); |
38 | } |
39 | |
40 | // One (Try) |
41 | { |
42 | auto fs = makeFutures(1); |
43 | |
44 | Future<double> f1 = |
45 | reduce(fs, 0.0, [](double a, Try<int>&& b) { return a + *b + 0.1; }); |
46 | EXPECT_EQ(1.1, std::move(f1).get()); |
47 | } |
48 | |
49 | // Returning values (Try) |
50 | { |
51 | auto fs = makeFutures(3); |
52 | |
53 | Future<double> f1 = |
54 | reduce(fs, 0.0, [](double a, Try<int>&& b) { return a + *b + 0.1; }); |
55 | EXPECT_EQ(6.3, std::move(f1).get()); |
56 | } |
57 | |
58 | // Returning values |
59 | { |
60 | auto fs = makeFutures(3); |
61 | |
62 | Future<double> f1 = |
63 | reduce(fs, 0.0, [](double a, int&& b) { return a + b + 0.1; }); |
64 | EXPECT_EQ(6.3, std::move(f1).get()); |
65 | } |
66 | |
67 | // Returning futures (Try) |
68 | { |
69 | auto fs = makeFutures(3); |
70 | |
71 | Future<double> f2 = reduce(fs, 0.0, [](double a, Try<int>&& b) { |
72 | return makeFuture<double>(a + *b + 0.1); |
73 | }); |
74 | EXPECT_EQ(6.3, std::move(f2).get()); |
75 | } |
76 | |
77 | // Returning futures |
78 | { |
79 | auto fs = makeFutures(3); |
80 | |
81 | Future<double> f2 = reduce(fs, 0.0, [](double a, int&& b) { |
82 | return makeFuture<double>(a + b + 0.1); |
83 | }); |
84 | EXPECT_EQ(6.3, std::move(f2).get()); |
85 | } |
86 | } |
87 | |
88 | TEST(Reduce, chain) { |
89 | auto makeFutures = [](int count) { |
90 | std::vector<Future<int>> fs; |
91 | for (int i = 1; i <= count; ++i) { |
92 | fs.emplace_back(makeFuture(i)); |
93 | } |
94 | return fs; |
95 | }; |
96 | |
97 | { |
98 | auto f = collectAll(makeFutures(3)).reduce(0, [](int a, Try<int>&& b) { |
99 | return a + *b; |
100 | }); |
101 | EXPECT_EQ(6, std::move(f).get()); |
102 | } |
103 | { |
104 | auto f = |
105 | collect(makeFutures(3)).reduce(0, [](int a, int&& b) { return a + b; }); |
106 | EXPECT_EQ(6, std::move(f).get()); |
107 | } |
108 | } |
109 | |
110 | TEST(Reduce, unorderedReduce) { |
111 | { |
112 | std::vector<Future<int>> fs; |
113 | fs.push_back(makeFuture(1)); |
114 | fs.push_back(makeFuture(2)); |
115 | fs.push_back(makeFuture(3)); |
116 | |
117 | Future<double> f = |
118 | unorderedReduce(fs.begin(), fs.end(), 0.0, [](double /* a */, int&& b) { |
119 | return double(b); |
120 | }); |
121 | EXPECT_EQ(3.0, std::move(f).get()); |
122 | } |
123 | { |
124 | Promise<int> p1; |
125 | Promise<int> p2; |
126 | Promise<int> p3; |
127 | |
128 | std::vector<Future<int>> fs; |
129 | fs.push_back(p1.getFuture()); |
130 | fs.push_back(p2.getFuture()); |
131 | fs.push_back(p3.getFuture()); |
132 | |
133 | Future<double> f = |
134 | unorderedReduce(fs.begin(), fs.end(), 0.0, [](double /* a */, int&& b) { |
135 | return double(b); |
136 | }); |
137 | p3.setValue(3); |
138 | p2.setValue(2); |
139 | p1.setValue(1); |
140 | EXPECT_EQ(1.0, std::move(f).get()); |
141 | } |
142 | } |
143 | |
144 | TEST(Reduce, unorderedReduceException) { |
145 | Promise<int> p1; |
146 | Promise<int> p2; |
147 | Promise<int> p3; |
148 | |
149 | std::vector<Future<int>> fs; |
150 | fs.push_back(p1.getFuture()); |
151 | fs.push_back(p2.getFuture()); |
152 | fs.push_back(p3.getFuture()); |
153 | |
154 | Future<double> f = |
155 | unorderedReduce(fs.begin(), fs.end(), 0.0, [](double /* a */, int&& b) { |
156 | return b + 0.0; |
157 | }); |
158 | p3.setValue(3); |
159 | p2.setException(exception_wrapper(std::runtime_error("blah" ))); |
160 | p1.setValue(1); |
161 | EXPECT_THROW(std::move(f).get(), std::runtime_error); |
162 | } |
163 | |
164 | TEST(Reduce, unorderedReduceFuture) { |
165 | Promise<int> p1; |
166 | Promise<int> p2; |
167 | Promise<int> p3; |
168 | |
169 | std::vector<Future<int>> fs; |
170 | fs.push_back(p1.getFuture()); |
171 | fs.push_back(p2.getFuture()); |
172 | fs.push_back(p3.getFuture()); |
173 | |
174 | std::vector<Promise<double>> ps(3); |
175 | |
176 | Future<int> f = |
177 | unorderedReduce(fs.begin(), fs.end(), 0.0, [&](double /* a */, int&& b) { |
178 | return ps[b - 1].getFuture(); |
179 | }); |
180 | p3.setValue(3); |
181 | p2.setValue(2); |
182 | p1.setValue(1); |
183 | |
184 | ps[0].setValue(1.0); |
185 | ps[1].setValue(2.0); |
186 | ps[2].setValue(3.0); |
187 | |
188 | EXPECT_EQ(1.0, std::move(f).get()); |
189 | } |
190 | |