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/FutureSplitter.h>
18#include <folly/portability/GTest.h>
19
20using namespace folly;
21
22TEST(FutureSplitter, splitFutureSuccess) {
23 Promise<int> p;
24 folly::FutureSplitter<int> sp(
25 p.getSemiFuture().via(&InlineExecutor::instance()));
26 auto f1 = sp.getFuture();
27 EXPECT_FALSE(f1.isReady());
28 p.setValue(1);
29 EXPECT_TRUE(f1.isReady());
30 EXPECT_TRUE(f1.hasValue());
31 auto f2 = sp.getFuture();
32 EXPECT_TRUE(f2.isReady());
33 EXPECT_TRUE(f2.hasValue());
34}
35
36TEST(FutureSplitter, splitFutureSuccessSemiFuture) {
37 Promise<int> p;
38 folly::FutureSplitter<int> sp(
39 p.getSemiFuture().via(&InlineExecutor::instance()));
40 auto f1 = sp.getSemiFuture();
41 EXPECT_FALSE(f1.isReady());
42 p.setValue(1);
43 EXPECT_TRUE(f1.isReady());
44 EXPECT_TRUE(f1.hasValue());
45 auto f2 = sp.getSemiFuture();
46 EXPECT_TRUE(f2.isReady());
47 EXPECT_TRUE(f2.hasValue());
48}
49
50TEST(FutureSplitter, splitFutureSuccessNullExecutor) {
51 Promise<int> p;
52 auto sf = p.getSemiFuture();
53 // Double via because a null executor to SemiFuture.via is invalid but we
54 // are testing a situation where we have a FutureSplitter from a future with
55 // a null executor to account for legacy code.
56 auto f = std::move(sf).via(&InlineExecutor::instance()).via(nullptr);
57 folly::FutureSplitter<int> sp(std::move(f));
58 auto f1 = sp.getFuture();
59 EXPECT_FALSE(f1.isReady());
60 p.setValue(1);
61 EXPECT_TRUE(f1.isReady());
62 EXPECT_TRUE(f1.hasValue());
63 auto f2 = sp.getFuture();
64 EXPECT_TRUE(f2.isReady());
65 EXPECT_TRUE(f2.hasValue());
66}
67
68TEST(FutureSplitter, splitFutureCopyable) {
69 Promise<int> p;
70 folly::FutureSplitter<int> sp1(
71 p.getSemiFuture().via(&InlineExecutor::instance()));
72 folly::FutureSplitter<int> sp2(sp1);
73 auto f1 = sp1.getFuture();
74 EXPECT_FALSE(f1.isReady());
75 p.setValue(1);
76 EXPECT_TRUE(f1.isReady());
77 EXPECT_TRUE(f1.hasValue());
78 auto f2 = sp2.getFuture();
79 EXPECT_TRUE(f2.isReady());
80 EXPECT_TRUE(f2.hasValue());
81 folly::FutureSplitter<int> sp3(sp1);
82 auto f3 = sp3.getFuture();
83 EXPECT_TRUE(f3.isReady());
84 EXPECT_TRUE(f3.hasValue());
85}
86
87TEST(FutureSplitter, splitFutureMovable) {
88 Promise<int> p;
89 folly::FutureSplitter<int> sp1(
90 p.getSemiFuture().via(&InlineExecutor::instance()));
91 auto f1 = sp1.getFuture();
92 folly::FutureSplitter<int> sp2(std::move(sp1));
93 EXPECT_FALSE(f1.isReady());
94 p.setValue(1);
95 EXPECT_TRUE(f1.isReady());
96 EXPECT_TRUE(f1.hasValue());
97 auto f2 = sp2.getFuture();
98 EXPECT_TRUE(f2.isReady());
99 EXPECT_TRUE(f2.hasValue());
100 folly::FutureSplitter<int> sp3(std::move(sp2));
101 auto f3 = sp3.getFuture();
102 EXPECT_TRUE(f3.isReady());
103 EXPECT_TRUE(f3.hasValue());
104}
105
106TEST(FutureSplitter, splitFutureCopyAssignable) {
107 Promise<int> p;
108 folly::FutureSplitter<int> sp1(
109 p.getSemiFuture().via(&InlineExecutor::instance()));
110 folly::FutureSplitter<int> sp2{};
111 sp2 = sp1;
112 auto f1 = sp1.getFuture();
113 EXPECT_FALSE(f1.isReady());
114 p.setValue(1);
115 EXPECT_TRUE(f1.isReady());
116 EXPECT_TRUE(f1.hasValue());
117 auto f2 = sp2.getFuture();
118 EXPECT_TRUE(f2.isReady());
119 EXPECT_TRUE(f2.hasValue());
120 folly::FutureSplitter<int> sp3(sp1);
121 auto f3 = sp3.getFuture();
122 EXPECT_TRUE(f3.isReady());
123 EXPECT_TRUE(f3.hasValue());
124}
125
126TEST(FutureSplitter, splitFutureMoveAssignable) {
127 Promise<int> p;
128 folly::FutureSplitter<int> sp1(
129 p.getSemiFuture().via(&InlineExecutor::instance()));
130 auto f1 = sp1.getFuture();
131 folly::FutureSplitter<int> sp2{};
132 sp2 = std::move(sp1);
133 EXPECT_FALSE(f1.isReady());
134 p.setValue(1);
135 EXPECT_TRUE(f1.isReady());
136 EXPECT_TRUE(f1.hasValue());
137 auto f2 = sp2.getFuture();
138 EXPECT_TRUE(f2.isReady());
139 EXPECT_TRUE(f2.hasValue());
140 folly::FutureSplitter<int> sp3(std::move(sp2));
141 auto f3 = sp3.getFuture();
142 EXPECT_TRUE(f3.isReady());
143 EXPECT_TRUE(f3.hasValue());
144}
145
146TEST(FutureSplitter, splitFutureScope) {
147 Promise<int> p;
148 auto pSP = std::make_unique<folly::FutureSplitter<int>>(
149 p.getSemiFuture().via(&InlineExecutor::instance()));
150 auto f1 = pSP->getFuture();
151 EXPECT_FALSE(f1.isReady());
152 pSP.reset();
153 EXPECT_NO_THROW(EXPECT_FALSE(f1.isReady()));
154 p.setValue(1);
155 EXPECT_TRUE(f1.isReady());
156 EXPECT_TRUE(f1.hasValue());
157 EXPECT_EQ(1, std::move(f1).get());
158}
159
160TEST(FutureSplitter, splitFutureFailure) {
161 Promise<int> p;
162 folly::FutureSplitter<int> sp(
163 p.getSemiFuture().via(&InlineExecutor::instance()));
164 auto f1 = sp.getFuture();
165 EXPECT_FALSE(f1.isReady());
166 try {
167 throw std::runtime_error("Oops");
168 } catch (std::exception& e) {
169 p.setException(exception_wrapper(std::current_exception(), e));
170 }
171 EXPECT_TRUE(f1.isReady());
172 EXPECT_TRUE(f1.hasException());
173 auto f2 = sp.getFuture();
174 EXPECT_TRUE(f2.isReady());
175 EXPECT_TRUE(f2.hasException());
176}
177
178TEST(FutureSplitter, splitFuturePriority) {
179 std::vector<int8_t> priorities = {
180 folly::Executor::LO_PRI,
181 folly::Executor::MID_PRI,
182 folly::Executor::HI_PRI,
183 };
184
185 for (const auto priority : priorities) {
186 Promise<int> p;
187 folly::FutureSplitter<int> sp(
188 p.getSemiFuture().via(&InlineExecutor::instance(), priority));
189 auto fut = sp.getFuture();
190 EXPECT_EQ(priority, fut.getPriority());
191 }
192}
193