proxygen
EvbHandshakeHelperTest.cpp
Go to the documentation of this file.
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  */
17 
18 #include <chrono>
19 #include <thread>
20 
22 #include <folly/futures/Barrier.h>
27 
29 
30 using namespace std::chrono_literals;
31 using namespace folly;
32 using namespace folly::test;
33 using namespace wangle;
34 using namespace testing;
35 
36 class EvbHandshakeHelperTest : public Test {
37  protected:
38  void SetUp() override {
39  original_.getEventBase()->runInEventBaseThreadAndWait([=] {
40  originalThreadId_ = std::this_thread::get_id();
41  auto evb = original_.getEventBase();
42  auto sslSock =
43  new MockAsyncSSLSocket(std::make_shared<SSLContext>(), evb, true);
44 
45  sslSock_ = sslSock;
46  sockPtr_.reset(sslSock);
47  });
48 
49  alternate_.getEventBase()->runInEventBaseThreadAndWait(
50  [=] { alternateThreadId_ = std::this_thread::get_id(); });
51 
53 
54  evbHelper_ = new EvbHandshakeHelper(
56  alternate_.getEventBase());
57  }
58 
59  void TearDown() override {
60  if (evbHelper_) {
61  evbHelper_->destroy();
62  }
63  }
64 
67 
68  std::atomic<std::thread::id> originalThreadId_;
69  std::atomic<std::thread::id> alternateThreadId_;
70 
71  EvbHandshakeHelper* evbHelper_{nullptr};
73 
75 
76  MockAsyncSSLSocket* sslSock_{nullptr};
77  AsyncSSLSocket::UniquePtr sockPtr_{nullptr};
78 };
79 
80 TEST_F(EvbHandshakeHelperTest, TestSuccessPath) {
81  folly::Baton<> barrier;
82 
83  EXPECT_CALL(mockCb_, connectionReadyInternalRaw(_, _, _, _))
84  .WillOnce(Invoke([&](auto sock, auto nextProtocol, auto&&, auto&&) {
85  EXPECT_EQ(original_.getEventBase(), sock->getEventBase());
86  EXPECT_EQ(originalThreadId_, std::this_thread::get_id());
87  EXPECT_EQ("h2", nextProtocol);
88  sock->destroy();
89  barrier.post();
90  }));
91 
92  EXPECT_CALL(*mockHelper_, startInternal(_, _))
93  .WillOnce(Invoke([&](auto sock, auto cb) {
94  EXPECT_EQ(alternate_.getEventBase(), sock->getEventBase());
95  EXPECT_EQ(alternateThreadId_, std::this_thread::get_id());
96 
97  sock->getEventBase()->runInLoop([sock, cb] {
98  cb->connectionReady(
100  "h2",
101  SecureTransportType::TLS,
102  folly::none);
103  });
104  }));
105 
106  original_.getEventBase()->runInEventBaseThreadAndWait(
107  [=] { evbHelper_->start(std::move(sockPtr_), &mockCb_); });
108 
109  if (!barrier.try_wait_for(2s)) {
110  FAIL() << "Timeout waiting for connectionReady callback to be called";
111  }
112 }
113 
115  folly::Baton<> barrier;
116 
117  EXPECT_NE(nullptr, sockPtr_->getEventBase());
118  EXPECT_CALL(mockCb_, connectionError_(_, _, _))
119  .WillOnce(Invoke([&](auto sock, auto&&, auto&&) {
120  EXPECT_EQ(sock, nullptr);
121  EXPECT_EQ(originalThreadId_, std::this_thread::get_id());
122  barrier.post();
123  }));
124 
125  EXPECT_CALL(*mockHelper_, startInternal(_, _))
126  .WillOnce(Invoke([&](auto sock, auto cb) {
127  EXPECT_EQ(alternate_.getEventBase(), sock->getEventBase());
128  EXPECT_EQ(alternateThreadId_, std::this_thread::get_id());
129 
130  sock->getEventBase()->runInLoop([sock, cb, this] {
132  EXPECT_FALSE(mockHelper_->getDestroyPending());
133  cb->connectionError(sock, {}, folly::none);
134  EXPECT_TRUE(mockHelper_->getDestroyPending());
135  EXPECT_EQ(alternate_.getEventBase(), sock->getEventBase());
136  sock->destroy();
137  });
138  }));
139 
140  original_.getEventBase()->runInEventBaseThreadAndWait(
141  [=] { evbHelper_->start(std::move(sockPtr_), &mockCb_); });
142 
143  if (!barrier.try_wait_for(2s)) {
144  FAIL() << "Timeout while waiting for connectionError callback to be called";
145  }
146 }
147 
148 TEST_F(EvbHandshakeHelperTest, TestDropConnection) {
149  folly::Baton<> barrier;
150 
151  EXPECT_CALL(*mockHelper_, dropConnection(_)).WillOnce(Invoke([&](auto) {
152  EXPECT_EQ(alternateThreadId_, std::this_thread::get_id());
153  // Need to wait here else its possible the test destructor may be invoked
154  // before the lamda below actually tries to execute.
155  alternate_.getEventBase()->runInEventBaseThreadAndWait([=]{
156  evbHelper_->connectionError(sslSock_, {}, {});
157  });
158  barrier.post();
159  }));
160 
161  AsyncTransportWrapper* transport;
162  EXPECT_CALL(mockCb_, connectionError_(_, _, _))
163  .WillOnce(SaveArg<0>(&transport));
164 
165  EXPECT_CALL(*mockHelper_, startInternal(_, _))
166  .WillOnce(Invoke([&](auto sock, auto&&) {
167  EXPECT_EQ(alternate_.getEventBase(), sock->getEventBase());
168  EXPECT_EQ(alternateThreadId_, std::this_thread::get_id());
169  sslSock_ = dynamic_cast<MockAsyncSSLSocket*>(sock);
170  sockPtr_.reset(sslSock_);
171  barrier.post();
172  }));
173 
174  original_.getEventBase()->runInEventBaseThreadAndWait(
175  [=] { evbHelper_->start(std::move(sockPtr_), &mockCb_); });
176 
177  if (!barrier.try_wait_for(2s)) {
178  FAIL() << "Timeout while waiting for startInternal to be called";
179  }
180 
181  barrier.reset();
182 
183  original_.getEventBase()->runInEventBaseThreadAndWait(
184  [=] { evbHelper_->dropConnection(SSLErrorEnum::DROPPED); });
185 
186  if (!barrier.try_wait_for(2s)) {
187  FAIL() << "Timeout while waiting for dropConnection to be called";
188  }
189 
190  EXPECT_EQ(nullptr, transport);
191 }
192 
193 TEST_F(EvbHandshakeHelperTest, TestDropConnectionTricky) {
194  folly::Baton<> barrier;
195  folly::Baton<> connectionReadyCalled;
196  folly::futures::Barrier raceBarrier(3);
197 
198 
199  // One of these two methods will be called depending on the race, but
200  // not both of them.
201  bool called = false;
202  EXPECT_CALL(mockCb_, connectionError_(_, _, _))
203  .Times(AtMost(1))
204  .WillOnce(Invoke([&](auto, auto, auto) {
205  EXPECT_FALSE(called);
206  called = true;
207  barrier.post();
208  }));
209 
210  EXPECT_CALL(mockCb_, connectionReadyInternalRaw(_, _, _, _))
211  .Times(AtMost(1))
212  .WillOnce(Invoke([&](auto, auto, auto, auto) {
213  EXPECT_FALSE(called);
214  called = true;
215  barrier.post();
216  }));
217 
218  EXPECT_CALL(*mockHelper_, startInternal(_, _))
219  .WillOnce(Invoke([&](auto sock, auto&&) {
220  EXPECT_EQ(alternate_.getEventBase(), sock->getEventBase());
221  EXPECT_EQ(alternateThreadId_, std::this_thread::get_id());
222  sslSock_ = dynamic_cast<MockAsyncSSLSocket*>(sock);
223  sockPtr_.reset(sslSock_);
224  barrier.post();
225  }));
226 
227  original_.getEventBase()->runInEventBaseThreadAndWait(
228  [=] { evbHelper_->start(std::move(sockPtr_), &mockCb_); });
229 
230  if (!barrier.try_wait_for(2s)) {
231  FAIL() << "Timeout while waiting for startInternal to be called";
232  }
233 
234  barrier.reset();
235 
236  // Race the dropConnection() and handshakeSuccess() calls
237  original_.getEventBase()->runInEventBaseThread([=, &raceBarrier] {
238  raceBarrier.wait().get();
239  evbHelper_->dropConnection(SSLErrorEnum::DROPPED);
240  });
241 
242  alternate_.getEventBase()->runInEventBaseThread(
243  [=, &raceBarrier, &connectionReadyCalled]() mutable {
244  raceBarrier.wait().get();
245  evbHelper_->connectionReady(std::move(sockPtr_), "test", {}, {});
246  connectionReadyCalled.post();
247  });
248 
249  raceBarrier.wait();
250 
251  if (!barrier.try_wait_for(2s)) {
252  FAIL() << "Timeout while waiting for connectionError to be called";
253  }
254 
255  if (!connectionReadyCalled.try_wait_for(2s)) {
256  FAIL() << "Timeout while waiting for connectionReady to call";
257  }
258 }
ScopedEventBaseThread original_
#define FAIL()
Definition: gtest.h:1822
folly::Future< bool > wait()
Definition: Barrier.cpp:72
GTEST_API_ Cardinality AtMost(int n)
MockHandshakeHelperCallback< UseOwnedRawPtrPolicy > mockCb_
TEST_F(EvbHandshakeHelperTest, TestSuccessPath)
std::atomic< std::thread::id > alternateThreadId_
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::atomic< std::thread::id > originalThreadId_
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
FOLLY_ALWAYS_INLINE bool try_wait_for(const std::chrono::duration< Rep, Period > &timeout, const WaitOptions &opt=wait_options()) noexcept
Definition: Baton.h:206
std::unique_ptr< AsyncSSLSocket, Destructor > UniquePtr
std::unique_ptr< AsyncTransportWrapper, Destructor > UniquePtr
PolymorphicAction< internal::InvokeAction< FunctionImpl > > Invoke(FunctionImpl function_impl)
void post() noexcept
Definition: Baton.h:123
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
static set< string > s
#define EXPECT_CALL(obj, call)
const internal::AnythingMatcher _
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
std::unique_ptr< AcceptorHandshakeHelper, folly::DelayedDestruction::Destructor > UniquePtr
ScopedEventBaseThread alternate_
void reset() noexcept
Definition: Baton.h:96
constexpr None none
Definition: Optional.h:87