proxygen
FutureDAGTest.cpp
Go to the documentation of this file.
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  */
17 #include <boost/thread/barrier.hpp>
19 
20 using namespace folly;
21 
22 struct FutureDAGTest : public testing::Test {
24 
25  Handle add() {
26  auto node = std::make_unique<TestNode>(this);
27  auto handle = node->handle;
28  nodes.emplace(handle, std::move(node));
29  return handle;
30  }
31 
32  void reset() {
33  Handle source_node;
34  std::unordered_set<Handle> memo;
35  for (auto& node : nodes) {
36  for (Handle handle : node.second->dependencies) {
37  memo.insert(handle);
38  }
39  }
40  for (auto& node : nodes) {
41  if (memo.find(node.first) == memo.end()) {
42  source_node = node.first;
43  }
44  }
45  for (auto it = nodes.cbegin(); it != nodes.cend();) {
46  if (it->first != source_node) {
47  it = nodes.erase(it);
48  } else {
49  ++it;
50  }
51  }
52  dag->reset();
53  }
54 
55  void remove(Handle a) {
56  for (auto& node : nodes) {
57  node.second->dependencies.erase(a);
58  }
59  nodes.erase(a);
60  dag->remove(a);
61  }
62 
63  void dependency(Handle a, Handle b) {
64  nodes.at(b)->dependencies.insert(a);
65  dag->dependency(a, b);
66  }
67 
68  void checkOrder() {
69  EXPECT_EQ(nodes.size(), order.size());
70  for (auto& kv : nodes) {
71  auto handle = kv.first;
72  auto& node = kv.second;
73  auto it = order.begin();
74  while (*it != handle) {
75  it++;
76  }
77  for (auto dep : node->dependencies) {
78  EXPECT_TRUE(std::find(it, order.end(), dep) == order.end());
79  }
80  }
81  }
82 
83  struct TestNode {
85  : func([this, test] {
86  test->order.push_back(handle);
87  return Future<Unit>();
88  }),
89  handle(test->dag->add(func)) {}
90 
92  const Handle handle;
93  std::set<Handle> dependencies;
94  };
95 
96  const std::shared_ptr<FutureDAG> dag = FutureDAG::create();
97  std::map<Handle, std::unique_ptr<TestNode>> nodes;
98  std::vector<Handle> order;
99 };
100 
101 TEST_F(FutureDAGTest, SingleNode) {
102  add();
103  ASSERT_NO_THROW(dag->go().get());
104  checkOrder();
105 }
106 
107 TEST_F(FutureDAGTest, RemoveSingleNode) {
108  auto h1 = add();
109  auto h2 = add();
110  (void)h1;
111  remove(h2);
112  ASSERT_NO_THROW(dag->go().get());
113  checkOrder();
114 }
115 
116 TEST_F(FutureDAGTest, RemoveNodeComplex) {
117  auto h1 = add();
118  auto h2 = add();
119  auto h3 = add();
120  dependency(h1, h3);
121  dependency(h2, h1);
122  remove(h3);
123  remove(h2);
124  remove(h1);
125  ASSERT_NO_THROW(dag->go().get());
126  checkOrder();
127 }
128 
129 TEST_F(FutureDAGTest, ResetDAG) {
130  auto h1 = add();
131  auto h2 = add();
132  auto h3 = add();
133  dependency(h3, h1);
134  dependency(h2, h3);
135 
136  reset();
137  ASSERT_NO_THROW(dag->go().get());
138  checkOrder();
139 }
140 
142  auto h1 = add();
143  auto h2 = add();
144  auto h3 = add();
145  dependency(h1, h2);
146  dependency(h1, h3);
147  ASSERT_NO_THROW(dag->go().get());
148  checkOrder();
149 }
150 
152  auto h1 = add();
153  auto h2 = add();
154  auto h3 = add();
155  dependency(h1, h3);
156  dependency(h2, h3);
157  ASSERT_NO_THROW(dag->go().get());
158  checkOrder();
159 }
160 
161 TEST_F(FutureDAGTest, FanOutFanIn) {
162  auto h1 = add();
163  auto h2 = add();
164  auto h3 = add();
165  auto h4 = add();
166  dependency(h1, h3);
167  dependency(h1, h2);
168  dependency(h2, h4);
169  dependency(h3, h4);
170  ASSERT_NO_THROW(dag->go().get());
171  checkOrder();
172 }
173 
175  auto A = add();
176  auto B = add();
177  auto C = add();
178  auto D = add();
179  auto E = add();
180  auto F = add();
181  auto G = add();
182  auto H = add();
183  auto I = add();
184  auto J = add();
185  auto K = add();
186  auto L = add();
187  auto M = add();
188  auto N = add();
189 
190  dependency(A, B);
191  dependency(A, C);
192  dependency(A, D);
193  dependency(A, J);
194  dependency(C, H);
195  dependency(D, E);
196  dependency(E, F);
197  dependency(E, G);
198  dependency(F, H);
199  dependency(G, H);
200  dependency(H, I);
201  dependency(J, K);
202  dependency(K, L);
203  dependency(K, M);
204  dependency(L, N);
205  dependency(I, N);
206 
207  ASSERT_NO_THROW(dag->go().get());
208  checkOrder();
209 }
210 
212 
214  return makeFuture<Unit>(std::runtime_error("oops"));
215 };
216 
217 TEST_F(FutureDAGTest, ThrowBegin) {
218  auto h1 = dag->add(throwFunc);
219  auto h2 = dag->add(makeFutureFunc);
220  dag->dependency(h1, h2);
221  EXPECT_THROW(dag->go().get(), std::runtime_error);
222 }
223 
224 TEST_F(FutureDAGTest, ThrowEnd) {
225  auto h1 = dag->add(makeFutureFunc);
226  auto h2 = dag->add(throwFunc);
227  dag->dependency(h1, h2);
228  EXPECT_THROW(dag->go().get(), std::runtime_error);
229 }
230 
232  auto h1 = add();
233  dependency(h1, h1);
234  EXPECT_THROW(dag->go().get(), std::runtime_error);
235 }
236 
238  auto h1 = add();
239  auto h2 = add();
240  dependency(h1, h2);
241  dependency(h2, h1);
242  EXPECT_THROW(dag->go().get(), std::runtime_error);
243 }
244 
246  auto h1 = add();
247  auto h2 = add();
248  auto h3 = add();
249  dependency(h1, h2);
250  dependency(h2, h3);
251  dependency(h3, h1);
252  EXPECT_THROW(dag->go().get(), std::runtime_error);
253 }
254 
255 TEST_F(FutureDAGTest, DestroyBeforeComplete) {
256  auto barrier = std::make_shared<boost::barrier>(2);
257  Future<Unit> f;
258  {
259  auto localDag = FutureDAG::create();
260  auto h1 = localDag->add([barrier] {
261  auto p = std::make_shared<Promise<Unit>>();
262  std::thread t([p, barrier] {
263  barrier->wait();
264  p->setValue();
265  });
266  t.detach();
267  return p->getFuture();
268  });
269  auto h2 = localDag->add(makeFutureFunc);
270  localDag->dependency(h1, h2);
271  f = localDag->go();
272  }
273  barrier->wait();
274  ASSERT_NO_THROW(std::move(f).get());
275 }
auto f
std::unique_ptr< int > A
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
std::set< Handle > dependencies
char b
auto add
Definition: BaseTest.cpp:70
FutureDAG::Handle Handle
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
std::function< Future< Unit >)> FutureFunc
Definition: FutureDAG.h:30
static std::shared_ptr< FutureDAG > create()
Definition: FutureDAG.h:25
#define D(name, bit)
Definition: CpuId.h:145
void dependency(Handle a, Handle b)
char a
#define C(name, bit)
Definition: CpuId.h:204
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
**Optimized Holders **The template hazptr_array< M > provides most of the functionality *of M hazptr_holder s but with faster construction destruction *for M
Definition: Hazptr.h:104
std::vector< Handle > order
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
FutureDAG::FutureFunc throwFunc
TestNode(FutureDAGTest *test)
FutureDAG::FutureFunc makeFutureFunc
std::map< Handle, std::unique_ptr< TestNode > > nodes
int order
const FutureDAG::FutureFunc func
#define ASSERT_NO_THROW(statement)
Definition: gtest.h:1851
Future< typename std::decay< T >::type > makeFuture(T &&t)
Definition: Future-inl.h:1310