blob: 2f4171b4f2f612d7b61901334e9db8769b43bb01 [file] [log] [blame]
Yukai Tu16aabbc2015-10-06 05:08:42 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi84d62cb2017-07-12 16:15:18 +00002/*
Davide Pesavento32065652017-01-15 01:52:21 -05003 * Copyright (c) 2014-2017, Regents of the University of California,
Yukai Tu16aabbc2015-10-06 05:08:42 -07004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
Eric Newberry65caf202015-12-17 15:08:16 -070026#include "transport-test-common.hpp"
27
Eric Newberryf68f3782015-12-11 00:31:32 -070028#include "tcp-transport-fixture.hpp"
Yukai Tu16aabbc2015-10-06 05:08:42 -070029
Davide Pesavento22fba352017-10-17 15:53:51 -040030#include <boost/mpl/vector.hpp>
31
Yukai Tu16aabbc2015-10-06 05:08:42 -070032namespace nfd {
33namespace face {
34namespace tests {
35
Yukai Tu16aabbc2015-10-06 05:08:42 -070036BOOST_AUTO_TEST_SUITE(Face)
Davide Pesavento22fba352017-10-17 15:53:51 -040037BOOST_FIXTURE_TEST_SUITE(TestTcpTransport, IpTransportFixture<TcpTransportFixture>)
Eric Newberry8717e872015-11-23 12:41:50 -070038
Davide Pesavento22fba352017-10-17 15:53:51 -040039using TcpTransportFixtures = boost::mpl::vector<
40 GENERATE_IP_TRANSPORT_FIXTURE_INSTANTIATIONS(TcpTransportFixture)
41>;
42
43BOOST_FIXTURE_TEST_CASE_TEMPLATE(StaticProperties, T, TcpTransportFixtures, T)
Eric Newberry8717e872015-11-23 12:41:50 -070044{
Davide Pesavento22fba352017-10-17 15:53:51 -040045 TRANSPORT_TEST_INIT();
Eric Newberry8717e872015-11-23 12:41:50 -070046
Davide Pesavento22fba352017-10-17 15:53:51 -040047 checkStaticPropertiesInitialized(*this->transport);
Eric Newberry8717e872015-11-23 12:41:50 -070048
Davide Pesavento22fba352017-10-17 15:53:51 -040049 BOOST_CHECK_EQUAL(this->transport->getLocalUri(), FaceUri(tcp::endpoint(this->address, this->localEp.port())));
50 BOOST_CHECK_EQUAL(this->transport->getRemoteUri(), FaceUri(tcp::endpoint(this->address, 7070)));
51 BOOST_CHECK_EQUAL(this->transport->getScope(),
52 this->addressScope == AddressScope::Loopback ? ndn::nfd::FACE_SCOPE_LOCAL
53 : ndn::nfd::FACE_SCOPE_NON_LOCAL);
54 BOOST_CHECK_EQUAL(this->transport->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
55 BOOST_CHECK_EQUAL(this->transport->getLinkType(), ndn::nfd::LINK_TYPE_POINT_TO_POINT);
56 BOOST_CHECK_EQUAL(this->transport->getMtu(), MTU_UNLIMITED);
Eric Newberry8717e872015-11-23 12:41:50 -070057}
58
Davide Pesavento32065652017-01-15 01:52:21 -050059BOOST_AUTO_TEST_CASE(PersistencyChange)
60{
Davide Pesavento22fba352017-10-17 15:53:51 -040061 TRANSPORT_TEST_INIT();
Davide Pesavento32065652017-01-15 01:52:21 -050062
63 BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND), true);
64 BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERSISTENT), true);
65 BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERMANENT), true);
66}
67
Weiwei Liudcdf6212016-08-31 14:34:22 -070068BOOST_AUTO_TEST_CASE(ChangePersistencyFromPermanentWhenDown)
69{
70 // when persistency is changed out of permanent while transport is DOWN,
71 // the transport immediately goes into FAILED state
72
Davide Pesavento22fba352017-10-17 15:53:51 -040073 TRANSPORT_TEST_INIT(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
Weiwei Liudcdf6212016-08-31 14:34:22 -070074
Davide Pesavento22fba352017-10-17 15:53:51 -040075 transport->afterStateChange.connectSingleShot(
76 [this] (TransportState oldState, TransportState newState) {
77 BOOST_CHECK_EQUAL(oldState, TransportState::UP);
78 BOOST_CHECK_EQUAL(newState, TransportState::DOWN);
79 limitedIo.afterOp();
80 });
Weiwei Liudcdf6212016-08-31 14:34:22 -070081 remoteSocket.close();
82 BOOST_REQUIRE_EQUAL(limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
83
84 bool didStateChange = false;
85 transport->afterStateChange.connectSingleShot(
Davide Pesaventoac238f22017-09-12 15:19:40 -040086 [&didStateChange] (TransportState oldState, TransportState newState) {
Weiwei Liudcdf6212016-08-31 14:34:22 -070087 didStateChange = true;
88 BOOST_CHECK_EQUAL(oldState, TransportState::DOWN);
89 BOOST_CHECK_EQUAL(newState, TransportState::FAILED);
90 });
91 transport->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
92 BOOST_CHECK(didStateChange);
93}
94
Davide Pesavento22fba352017-10-17 15:53:51 -040095BOOST_FIXTURE_TEST_CASE_TEMPLATE(PermanentReconnect, T, TcpTransportFixtures, T)
96{
97 TRANSPORT_TEST_INIT(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
98
99 this->transport->afterStateChange.connectSingleShot(
100 [this] (TransportState oldState, TransportState newState) {
101 BOOST_CHECK_EQUAL(oldState, TransportState::UP);
102 BOOST_CHECK_EQUAL(newState, TransportState::DOWN);
103 this->limitedIo.afterOp();
104 });
105 this->remoteSocket.close();
106 BOOST_REQUIRE_EQUAL(this->limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
107
108 this->transport->afterStateChange.connectSingleShot(
109 [this] (TransportState oldState, TransportState newState) {
110 BOOST_CHECK_EQUAL(oldState, TransportState::DOWN);
111 BOOST_CHECK_EQUAL(newState, TransportState::UP);
112 this->limitedIo.afterOp();
113 });
114 BOOST_REQUIRE_EQUAL(this->limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
115}
116
Weiwei Liudcdf6212016-08-31 14:34:22 -0700117class PermanentTcpTransportReconnectObserver : public TcpTransport
118{
119public:
120 PermanentTcpTransportReconnectObserver(protocol::socket&& socket, LimitedIo& io)
121 : TcpTransport(std::move(socket), ndn::nfd::FACE_PERSISTENCY_PERMANENT)
122 , m_io(io)
123 {
124 }
125
126protected:
127 void
128 reconnect() final
129 {
130 TcpTransport::reconnect();
131 m_io.afterOp();
132 }
133
134 void
135 handleReconnect(const boost::system::error_code& error) final
136 {
137 TcpTransport::handleReconnect(error);
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400138
139 // don't count this invocation as an "op" if the reconnection attempt failed,
140 // because in that case we will instead count the handleReconnectTimeout()
141 // that will eventually be called as well
142 if (getState() == TransportState::UP)
143 m_io.afterOp();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700144 }
145
146 void
147 handleReconnectTimeout() final
148 {
149 TcpTransport::handleReconnectTimeout();
150 m_io.afterOp();
151 }
152
153private:
154 LimitedIo& m_io;
155};
156
157static double
158asFloatMilliseconds(const time::nanoseconds& t)
159{
160 return static_cast<double>(t.count()) / 1000000.0;
161}
162
Davide Pesavento22fba352017-10-17 15:53:51 -0400163BOOST_FIXTURE_TEST_CASE_TEMPLATE(PermanentReconnectWithExponentialBackoff, T, TcpTransportFixtures, T)
Weiwei Liudcdf6212016-08-31 14:34:22 -0700164{
Davide Pesavento22fba352017-10-17 15:53:51 -0400165 TRANSPORT_TEST_CHECK_PRECONDITIONS();
166 // do not initialize
Weiwei Liudcdf6212016-08-31 14:34:22 -0700167
Davide Pesavento22fba352017-10-17 15:53:51 -0400168 tcp::endpoint remoteEp(this->address, 7070);
169 this->startAccept(remoteEp);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700170
Davide Pesavento22fba352017-10-17 15:53:51 -0400171 tcp::socket sock(this->g_io);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700172 sock.async_connect(remoteEp, [this] (const boost::system::error_code& error) {
173 BOOST_REQUIRE_EQUAL(error, boost::system::errc::success);
Davide Pesavento22fba352017-10-17 15:53:51 -0400174 this->limitedIo.afterOp();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700175 });
Davide Pesavento22fba352017-10-17 15:53:51 -0400176 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, time::seconds(1)), LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700177
Davide Pesavento22fba352017-10-17 15:53:51 -0400178 auto transportObserver =
179 make_unique<PermanentTcpTransportReconnectObserver>(std::move(sock), std::ref(this->limitedIo));
Weiwei Liudcdf6212016-08-31 14:34:22 -0700180 BOOST_REQUIRE_EQUAL(transportObserver->getState(), TransportState::UP);
181
182 // break the TCP connection
Davide Pesavento22fba352017-10-17 15:53:51 -0400183 this->stopAccept();
184 this->remoteSocket.close();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700185
186 // measure retry intervals
Weiwei Liudcdf6212016-08-31 14:34:22 -0700187 auto retryTime1 = time::steady_clock::now();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700188
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400189 auto expectedWait1 = TcpTransport::s_initialReconnectWait;
190 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, expectedWait1 + time::seconds(1)), // add some slack
191 LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700192 auto retryTime2 = time::steady_clock::now();
193 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::DOWN);
194
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400195 auto expectedWait2 = time::duration_cast<time::nanoseconds>(expectedWait1 *
196 TcpTransport::s_reconnectWaitMultiplier);
197 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, expectedWait2 + time::seconds(1)), // add some slack
198 LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700199 auto retryTime3 = time::steady_clock::now();
200 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::DOWN);
201
202 // check that the backoff algorithm works
203 BOOST_CHECK_CLOSE(asFloatMilliseconds(retryTime2 - retryTime1),
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400204 asFloatMilliseconds(expectedWait1), 10.0);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700205 BOOST_CHECK_CLOSE(asFloatMilliseconds(retryTime3 - retryTime2),
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400206 asFloatMilliseconds(expectedWait2), 10.0);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700207
208 // reestablish the TCP connection
Davide Pesavento22fba352017-10-17 15:53:51 -0400209 this->startAccept(remoteEp);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700210
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400211 auto expectedWait3 = time::duration_cast<time::nanoseconds>(expectedWait2 *
212 TcpTransport::s_reconnectWaitMultiplier);
213 BOOST_REQUIRE_EQUAL(this->limitedIo.run(3, // reconnect, handleReconnect, async_accept
214 expectedWait3 + time::seconds(1)), LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700215 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::UP);
216
217 // break the TCP connection again
Davide Pesavento22fba352017-10-17 15:53:51 -0400218 this->stopAccept();
219 this->remoteSocket.close();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700220
221 // measure retry intervals
Weiwei Liudcdf6212016-08-31 14:34:22 -0700222 auto retryTime4 = time::steady_clock::now();
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400223 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, expectedWait1 + time::seconds(1)), // add some slack
224 LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700225 auto retryTime5 = time::steady_clock::now();
226 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::DOWN);
227
228 // check that the timeout restarts from the initial value after a successful reconnection
229 BOOST_CHECK_CLOSE(asFloatMilliseconds(retryTime5 - retryTime4),
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400230 asFloatMilliseconds(expectedWait1), 10.0);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700231}
232
Yukai Tu16aabbc2015-10-06 05:08:42 -0700233BOOST_AUTO_TEST_SUITE_END() // TestTcpTransport
234BOOST_AUTO_TEST_SUITE_END() // Face
235
236} // namespace tests
237} // namespace face
238} // namespace nfd