blob: 96cba88212034d595bcb6f2f2195952b1390bfaa [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/*
Eric Newberryb49313d2017-12-24 20:22:27 -07003 * Copyright (c) 2014-2018, 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 Newberryb49313d2017-12-24 20:22:27 -070057 BOOST_CHECK_EQUAL(this->transport->getSendQueueCapacity(), QUEUE_UNSUPPORTED);
Eric Newberry8717e872015-11-23 12:41:50 -070058}
59
Davide Pesavento32065652017-01-15 01:52:21 -050060BOOST_AUTO_TEST_CASE(PersistencyChange)
61{
Davide Pesavento22fba352017-10-17 15:53:51 -040062 TRANSPORT_TEST_INIT();
Davide Pesavento32065652017-01-15 01:52:21 -050063
64 BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND), true);
65 BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERSISTENT), true);
66 BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERMANENT), true);
67}
68
Weiwei Liudcdf6212016-08-31 14:34:22 -070069BOOST_AUTO_TEST_CASE(ChangePersistencyFromPermanentWhenDown)
70{
71 // when persistency is changed out of permanent while transport is DOWN,
72 // the transport immediately goes into FAILED state
73
Davide Pesavento22fba352017-10-17 15:53:51 -040074 TRANSPORT_TEST_INIT(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
Weiwei Liudcdf6212016-08-31 14:34:22 -070075
Davide Pesavento22fba352017-10-17 15:53:51 -040076 transport->afterStateChange.connectSingleShot(
77 [this] (TransportState oldState, TransportState newState) {
78 BOOST_CHECK_EQUAL(oldState, TransportState::UP);
79 BOOST_CHECK_EQUAL(newState, TransportState::DOWN);
80 limitedIo.afterOp();
81 });
Weiwei Liudcdf6212016-08-31 14:34:22 -070082 remoteSocket.close();
Davide Pesavento00335782018-02-10 22:31:33 -050083 BOOST_REQUIRE_EQUAL(limitedIo.run(1, 1_s), LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -070084
85 bool didStateChange = false;
86 transport->afterStateChange.connectSingleShot(
Davide Pesaventoac238f22017-09-12 15:19:40 -040087 [&didStateChange] (TransportState oldState, TransportState newState) {
Weiwei Liudcdf6212016-08-31 14:34:22 -070088 didStateChange = true;
89 BOOST_CHECK_EQUAL(oldState, TransportState::DOWN);
90 BOOST_CHECK_EQUAL(newState, TransportState::FAILED);
91 });
92 transport->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
93 BOOST_CHECK(didStateChange);
94}
95
Davide Pesavento22fba352017-10-17 15:53:51 -040096BOOST_FIXTURE_TEST_CASE_TEMPLATE(PermanentReconnect, T, TcpTransportFixtures, T)
97{
98 TRANSPORT_TEST_INIT(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
99
100 this->transport->afterStateChange.connectSingleShot(
101 [this] (TransportState oldState, TransportState newState) {
102 BOOST_CHECK_EQUAL(oldState, TransportState::UP);
103 BOOST_CHECK_EQUAL(newState, TransportState::DOWN);
104 this->limitedIo.afterOp();
105 });
106 this->remoteSocket.close();
Davide Pesavento00335782018-02-10 22:31:33 -0500107 BOOST_REQUIRE_EQUAL(this->limitedIo.run(1, 1_s), LimitedIo::EXCEED_OPS);
Davide Pesavento22fba352017-10-17 15:53:51 -0400108
109 this->transport->afterStateChange.connectSingleShot(
110 [this] (TransportState oldState, TransportState newState) {
111 BOOST_CHECK_EQUAL(oldState, TransportState::DOWN);
112 BOOST_CHECK_EQUAL(newState, TransportState::UP);
113 this->limitedIo.afterOp();
114 });
Davide Pesavento00335782018-02-10 22:31:33 -0500115 BOOST_REQUIRE_EQUAL(this->limitedIo.run(1, 1_s), LimitedIo::EXCEED_OPS);
Davide Pesavento22fba352017-10-17 15:53:51 -0400116}
117
Weiwei Liudcdf6212016-08-31 14:34:22 -0700118class PermanentTcpTransportReconnectObserver : public TcpTransport
119{
120public:
121 PermanentTcpTransportReconnectObserver(protocol::socket&& socket, LimitedIo& io)
122 : TcpTransport(std::move(socket), ndn::nfd::FACE_PERSISTENCY_PERMANENT)
123 , m_io(io)
124 {
125 }
126
127protected:
128 void
129 reconnect() final
130 {
131 TcpTransport::reconnect();
132 m_io.afterOp();
133 }
134
135 void
136 handleReconnect(const boost::system::error_code& error) final
137 {
138 TcpTransport::handleReconnect(error);
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400139
140 // don't count this invocation as an "op" if the reconnection attempt failed,
141 // because in that case we will instead count the handleReconnectTimeout()
142 // that will eventually be called as well
143 if (getState() == TransportState::UP)
144 m_io.afterOp();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700145 }
146
147 void
148 handleReconnectTimeout() final
149 {
150 TcpTransport::handleReconnectTimeout();
151 m_io.afterOp();
152 }
153
154private:
155 LimitedIo& m_io;
156};
157
158static double
159asFloatMilliseconds(const time::nanoseconds& t)
160{
161 return static_cast<double>(t.count()) / 1000000.0;
162}
163
Davide Pesavento22fba352017-10-17 15:53:51 -0400164BOOST_FIXTURE_TEST_CASE_TEMPLATE(PermanentReconnectWithExponentialBackoff, T, TcpTransportFixtures, T)
Weiwei Liudcdf6212016-08-31 14:34:22 -0700165{
Davide Pesavento22fba352017-10-17 15:53:51 -0400166 TRANSPORT_TEST_CHECK_PRECONDITIONS();
167 // do not initialize
Weiwei Liudcdf6212016-08-31 14:34:22 -0700168
Davide Pesavento22fba352017-10-17 15:53:51 -0400169 tcp::endpoint remoteEp(this->address, 7070);
170 this->startAccept(remoteEp);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700171
Davide Pesavento22fba352017-10-17 15:53:51 -0400172 tcp::socket sock(this->g_io);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700173 sock.async_connect(remoteEp, [this] (const boost::system::error_code& error) {
174 BOOST_REQUIRE_EQUAL(error, boost::system::errc::success);
Davide Pesavento22fba352017-10-17 15:53:51 -0400175 this->limitedIo.afterOp();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700176 });
Davide Pesavento00335782018-02-10 22:31:33 -0500177 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, 1_s), LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700178
Davide Pesavento22fba352017-10-17 15:53:51 -0400179 auto transportObserver =
180 make_unique<PermanentTcpTransportReconnectObserver>(std::move(sock), std::ref(this->limitedIo));
Weiwei Liudcdf6212016-08-31 14:34:22 -0700181 BOOST_REQUIRE_EQUAL(transportObserver->getState(), TransportState::UP);
182
183 // break the TCP connection
Davide Pesavento22fba352017-10-17 15:53:51 -0400184 this->stopAccept();
185 this->remoteSocket.close();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700186
187 // measure retry intervals
Weiwei Liudcdf6212016-08-31 14:34:22 -0700188 auto retryTime1 = time::steady_clock::now();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700189
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400190 auto expectedWait1 = TcpTransport::s_initialReconnectWait;
Davide Pesavento00335782018-02-10 22:31:33 -0500191 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, expectedWait1 + 1_s), // add some slack
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400192 LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700193 auto retryTime2 = time::steady_clock::now();
194 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::DOWN);
195
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400196 auto expectedWait2 = time::duration_cast<time::nanoseconds>(expectedWait1 *
197 TcpTransport::s_reconnectWaitMultiplier);
Davide Pesavento00335782018-02-10 22:31:33 -0500198 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, expectedWait2 + 1_s), // add some slack
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400199 LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700200 auto retryTime3 = time::steady_clock::now();
201 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::DOWN);
202
203 // check that the backoff algorithm works
204 BOOST_CHECK_CLOSE(asFloatMilliseconds(retryTime2 - retryTime1),
Davide Pesavento00335782018-02-10 22:31:33 -0500205 asFloatMilliseconds(expectedWait1), 20.0); // 200ms tolerance
Weiwei Liudcdf6212016-08-31 14:34:22 -0700206 BOOST_CHECK_CLOSE(asFloatMilliseconds(retryTime3 - retryTime2),
Davide Pesavento00335782018-02-10 22:31:33 -0500207 asFloatMilliseconds(expectedWait2), 10.0); // 200ms tolerance
Weiwei Liudcdf6212016-08-31 14:34:22 -0700208
209 // reestablish the TCP connection
Davide Pesavento22fba352017-10-17 15:53:51 -0400210 this->startAccept(remoteEp);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700211
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400212 auto expectedWait3 = time::duration_cast<time::nanoseconds>(expectedWait2 *
213 TcpTransport::s_reconnectWaitMultiplier);
214 BOOST_REQUIRE_EQUAL(this->limitedIo.run(3, // reconnect, handleReconnect, async_accept
Davide Pesavento00335782018-02-10 22:31:33 -0500215 expectedWait3 + 1_s), LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700216 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::UP);
217
218 // break the TCP connection again
Davide Pesavento22fba352017-10-17 15:53:51 -0400219 this->stopAccept();
220 this->remoteSocket.close();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700221
222 // measure retry intervals
Weiwei Liudcdf6212016-08-31 14:34:22 -0700223 auto retryTime4 = time::steady_clock::now();
Davide Pesavento00335782018-02-10 22:31:33 -0500224 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, expectedWait1 + 1_s), // add some slack
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400225 LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700226 auto retryTime5 = time::steady_clock::now();
227 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::DOWN);
228
229 // check that the timeout restarts from the initial value after a successful reconnection
230 BOOST_CHECK_CLOSE(asFloatMilliseconds(retryTime5 - retryTime4),
Davide Pesavento00335782018-02-10 22:31:33 -0500231 asFloatMilliseconds(expectedWait1), 20.0); // 200ms tolerance
Weiwei Liudcdf6212016-08-31 14:34:22 -0700232}
233
Yukai Tu16aabbc2015-10-06 05:08:42 -0700234BOOST_AUTO_TEST_SUITE_END() // TestTcpTransport
235BOOST_AUTO_TEST_SUITE_END() // Face
236
237} // namespace tests
238} // namespace face
239} // namespace nfd