blob: ec37c57a0ecfdc5b5898f7db1a263728259eb703 [file] [log] [blame]
Yanbiao Li73860e32015-08-19 16:30:16 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Yanbiao Lidf846e52016-01-30 21:53:47 -08003 * Copyright (c) 2014-2016, Regents of the University of California,
Yanbiao Li73860e32015-08-19 16:30:16 -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
26#include "mgmt/face-manager.hpp"
Yanbiao Lidf846e52016-01-30 21:53:47 -080027#include "nfd-manager-common-fixture.hpp"
Yanbiao Li73860e32015-08-19 16:30:16 -070028#include "../face/dummy-face.hpp"
29#include "face/tcp-factory.hpp"
30#include "face/udp-factory.hpp"
31
32#include <ndn-cxx/util/random.hpp>
33#include <ndn-cxx/encoding/tlv.hpp>
Junxiao Shi25c6ce42016-09-09 13:49:59 +000034#include <ndn-cxx/mgmt/nfd/channel-status.hpp>
35#include <ndn-cxx/mgmt/nfd/face-event-notification.hpp>
Yanbiao Li73860e32015-08-19 16:30:16 -070036
37namespace nfd {
38namespace tests {
39
Junxiao Shicde37ad2015-12-24 01:02:05 -070040BOOST_AUTO_TEST_SUITE(Mgmt)
41
Yanbiao Lidf846e52016-01-30 21:53:47 -080042class FaceManagerFixture : public NfdManagerCommonFixture
Yanbiao Li73860e32015-08-19 16:30:16 -070043{
44public:
45 FaceManagerFixture()
46 : m_faceTable(m_forwarder.getFaceTable())
Junxiao Shi9ddf1b52016-08-22 03:58:55 +000047 , m_manager(m_faceTable, m_dispatcher, *m_authenticator)
Yanbiao Li73860e32015-08-19 16:30:16 -070048 {
Junxiao Shi9ddf1b52016-08-22 03:58:55 +000049 setTopPrefix();
Yanbiao Lidf846e52016-01-30 21:53:47 -080050 setPrivilege("faces");
Yanbiao Li73860e32015-08-19 16:30:16 -070051 }
52
53public:
Junxiao Shicde37ad2015-12-24 01:02:05 -070054 enum AddFaceFlags {
55 REMOVE_LAST_NOTIFICATION = 1 << 0,
56 SET_SCOPE_LOCAL = 1 << 1,
57 SET_URI_TEST = 1 << 2,
58 RANDOMIZE_COUNTERS = 1 << 3
59 };
60
61 /** \brief adds a face to the FaceTable
62 * \param options bitwise OR'ed AddFaceFlags
63 */
Yanbiao Li73860e32015-08-19 16:30:16 -070064 shared_ptr<Face>
Junxiao Shicde37ad2015-12-24 01:02:05 -070065 addFace(int flags = 0)
Yanbiao Li73860e32015-08-19 16:30:16 -070066 {
Junxiao Shicde37ad2015-12-24 01:02:05 -070067 std::string uri = "dummy://";
68 ndn::nfd::FaceScope scope = ndn::nfd::FACE_SCOPE_NON_LOCAL;
69
70 if ((flags & SET_SCOPE_LOCAL) != 0) {
71 scope = ndn::nfd::FACE_SCOPE_LOCAL;
72 }
73 if ((flags & SET_URI_TEST) != 0) {
74 uri = "test://";
75 }
76
77 auto face = make_shared<DummyFace>(uri, uri, scope);
Yanbiao Li73860e32015-08-19 16:30:16 -070078 m_faceTable.add(face);
Junxiao Shicde37ad2015-12-24 01:02:05 -070079
80 if ((flags & RANDOMIZE_COUNTERS) != 0) {
81 const face::FaceCounters& counters = face->getCounters();
82 randomizeCounter(counters.nInInterests);
83 randomizeCounter(counters.nOutInterests);
84 randomizeCounter(counters.nInData);
85 randomizeCounter(counters.nOutData);
86 randomizeCounter(counters.nInNacks);
87 randomizeCounter(counters.nOutNacks);
88 randomizeCounter(counters.nInPackets);
89 randomizeCounter(counters.nOutPackets);
90 randomizeCounter(counters.nInBytes);
91 randomizeCounter(counters.nOutBytes);
92 }
93
Yanbiao Li73860e32015-08-19 16:30:16 -070094 advanceClocks(time::milliseconds(1), 10); // wait for notification posted
Junxiao Shicde37ad2015-12-24 01:02:05 -070095 if ((flags & REMOVE_LAST_NOTIFICATION) != 0) {
Yanbiao Li73860e32015-08-19 16:30:16 -070096 m_responses.pop_back();
97 }
Junxiao Shicde37ad2015-12-24 01:02:05 -070098
Yanbiao Li73860e32015-08-19 16:30:16 -070099 return face;
100 }
101
Junxiao Shicde37ad2015-12-24 01:02:05 -0700102private:
103 template<typename T>
104 static typename std::enable_if<std::is_base_of<SimpleCounter, T>::value>::type
105 randomizeCounter(const T& counter)
106 {
107 const_cast<T&>(counter).set(ndn::random::generateWord64());
108 }
109
Yanbiao Li73860e32015-08-19 16:30:16 -0700110protected:
111 FaceTable& m_faceTable;
112 FaceManager m_manager;
113};
114
Junxiao Shicde37ad2015-12-24 01:02:05 -0700115BOOST_FIXTURE_TEST_SUITE(TestFaceManager, FaceManagerFixture)
Yanbiao Li73860e32015-08-19 16:30:16 -0700116
117BOOST_AUTO_TEST_SUITE(DestroyFace)
118
119BOOST_AUTO_TEST_CASE(Existing)
120{
Junxiao Shicde37ad2015-12-24 01:02:05 -0700121 auto addedFace = addFace(REMOVE_LAST_NOTIFICATION | SET_SCOPE_LOCAL); // clear notification for creation
Yanbiao Li73860e32015-08-19 16:30:16 -0700122
123 auto parameters = ControlParameters().setFaceId(addedFace->getId());
124 auto command = makeControlCommandRequest("/localhost/nfd/faces/destroy", parameters);
125
126 receiveInterest(command);
127
128 BOOST_REQUIRE_EQUAL(m_responses.size(), 2); // one response and one notification
129 // notification is already tested, so ignore it
130
131 BOOST_CHECK_EQUAL(checkResponse(1, command->getName(), makeResponse(200, "OK", parameters)),
132 CheckResponseResult::OK);
133
Junxiao Shicde37ad2015-12-24 01:02:05 -0700134 BOOST_CHECK_EQUAL(addedFace->getId(), face::INVALID_FACEID);
Yanbiao Li73860e32015-08-19 16:30:16 -0700135}
136
137BOOST_AUTO_TEST_CASE(NonExisting)
138{
139 auto parameters = ControlParameters().setFaceId(65535);
140 auto command = makeControlCommandRequest("/localhost/nfd/faces/destroy", parameters);
141
142 receiveInterest(command);
143
144 BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
145
146 BOOST_CHECK_EQUAL(checkResponse(0, command->getName(), makeResponse(200, "OK", parameters)),
147 CheckResponseResult::OK);
148}
149
150BOOST_AUTO_TEST_SUITE_END() // DestroyFace
151
152BOOST_AUTO_TEST_CASE(FaceEvents)
153{
Junxiao Shicde37ad2015-12-24 01:02:05 -0700154 auto addedFace = addFace(); // trigger FACE_EVENT_CREATED notification
Yanbiao Li73860e32015-08-19 16:30:16 -0700155 BOOST_CHECK_NE(addedFace->getId(), -1);
156 int64_t faceId = addedFace->getId();
157
158 // check notification
159 {
160 Block payload;
161 ndn::nfd::FaceEventNotification notification;
162 BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
163 BOOST_CHECK_NO_THROW(payload = m_responses[0].getContent().blockFromValue());
164 BOOST_CHECK_EQUAL(payload.type(), ndn::tlv::nfd::FaceEventNotification);
165 BOOST_CHECK_NO_THROW(notification.wireDecode(payload));
166 BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_CREATED);
167 BOOST_CHECK_EQUAL(notification.getFaceId(), faceId);
168 BOOST_CHECK_EQUAL(notification.getRemoteUri(), addedFace->getRemoteUri().toString());
169 BOOST_CHECK_EQUAL(notification.getLocalUri(), addedFace->getLocalUri().toString());
170 BOOST_CHECK_EQUAL(notification.getFaceScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
171 BOOST_CHECK_EQUAL(notification.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
172 BOOST_CHECK_EQUAL(notification.getLinkType(), ndn::nfd::LinkType::LINK_TYPE_POINT_TO_POINT);
173 }
174
175 addedFace->close(); // trigger FaceDestroy FACE_EVENT_DESTROYED
176 advanceClocks(time::milliseconds(1), 10);
177
178 // check notification
179 {
180 Block payload;
181 ndn::nfd::FaceEventNotification notification;
182 BOOST_REQUIRE_EQUAL(m_responses.size(), 2);
183 BOOST_CHECK_NO_THROW(payload = m_responses[1].getContent().blockFromValue());
184 BOOST_CHECK_EQUAL(payload.type(), ndn::tlv::nfd::FaceEventNotification);
185 BOOST_CHECK_NO_THROW(notification.wireDecode(payload));
186 BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_DESTROYED);
187 BOOST_CHECK_EQUAL(notification.getFaceId(), faceId);
188 BOOST_CHECK_EQUAL(notification.getRemoteUri(), addedFace->getRemoteUri().toString());
189 BOOST_CHECK_EQUAL(notification.getLocalUri(), addedFace->getLocalUri().toString());
190 BOOST_CHECK_EQUAL(notification.getFaceScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
191 BOOST_CHECK_EQUAL(notification.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
192 BOOST_CHECK_EQUAL(notification.getLinkType(), ndn::nfd::LinkType::LINK_TYPE_POINT_TO_POINT);
193 }
Junxiao Shicde37ad2015-12-24 01:02:05 -0700194 BOOST_CHECK_EQUAL(addedFace->getId(), face::INVALID_FACEID);
Yanbiao Li73860e32015-08-19 16:30:16 -0700195}
196
Yanbiao Li73860e32015-08-19 16:30:16 -0700197// @todo Refactor when ndn::nfd::FaceStatus implementes operator!= and operator<<
198class FaceStatus : public ndn::nfd::FaceStatus
199{
200public:
201 FaceStatus(const ndn::nfd::FaceStatus& s)
202 : ndn::nfd::FaceStatus(s)
203 {
204 }
205};
206
207bool
208operator!=(const FaceStatus& left, const FaceStatus& right)
209{
210 return left.getRemoteUri() != right.getRemoteUri() ||
Junxiao Shicde37ad2015-12-24 01:02:05 -0700211 left.getLocalUri() != right.getLocalUri() ||
212 left.getFaceScope() != right.getFaceScope() ||
213 left.getFacePersistency() != right.getFacePersistency() ||
214 left.getLinkType() != right.getLinkType() ||
Eric Newberryc05918c2016-09-29 10:38:13 -0700215 left.getFlags() != right.getFlags() ||
Junxiao Shicde37ad2015-12-24 01:02:05 -0700216 left.getNInInterests() != right.getNInInterests() ||
217 left.getNInDatas() != right.getNInDatas() ||
218 left.getNOutInterests() != right.getNOutInterests() ||
219 left.getNOutDatas() != right.getNOutDatas() ||
220 left.getNInBytes() != right.getNInBytes() ||
221 left.getNOutBytes() != right.getNOutBytes();
Yanbiao Li73860e32015-08-19 16:30:16 -0700222}
223
224std::ostream&
225operator<<(std::ostream &os, const FaceStatus& status)
226{
227 os << "[" << status.getRemoteUri() << ", "
228 << status.getLocalUri() << ", "
229 << status.getFacePersistency() << ", "
230 << status.getLinkType() << ", "
Eric Newberryc05918c2016-09-29 10:38:13 -0700231 << status.getFlags() << ", "
Yanbiao Li73860e32015-08-19 16:30:16 -0700232 << status.getNInInterests() << ", "
233 << status.getNInDatas() << ", "
234 << status.getNOutInterests() << ", "
235 << status.getNOutDatas() << ", "
236 << status.getNInBytes() << ", "
237 << status.getNOutBytes() << "]";
238 return os;
239}
240
241BOOST_AUTO_TEST_CASE(FaceDataset)
242{
243 size_t nEntries = 303;
Junxiao Shicde37ad2015-12-24 01:02:05 -0700244 for (size_t i = 0; i < nEntries; ++i) {
245 addFace(REMOVE_LAST_NOTIFICATION | SET_URI_TEST | RANDOMIZE_COUNTERS);
Yanbiao Li73860e32015-08-19 16:30:16 -0700246 }
247
248 receiveInterest(makeInterest("/localhost/nfd/faces/list"));
249
250 Block content;
251 BOOST_CHECK_NO_THROW(content = concatenateResponses());
252 BOOST_CHECK_NO_THROW(content.parse());
253 BOOST_REQUIRE_EQUAL(content.elements().size(), nEntries);
254
Yanbiao Li73860e32015-08-19 16:30:16 -0700255 std::set<FaceId> faceIds;
256 for (size_t idx = 0; idx < nEntries; ++idx) {
257 BOOST_TEST_MESSAGE("processing element: " << idx);
258
259 ndn::nfd::FaceStatus decodedStatus;
260 BOOST_REQUIRE_NO_THROW(decodedStatus.wireDecode(content.elements()[idx]));
Junxiao Shida93f1f2015-11-11 06:13:16 -0700261 BOOST_CHECK(m_faceTable.get(decodedStatus.getFaceId()) != nullptr);
Yanbiao Li73860e32015-08-19 16:30:16 -0700262 faceIds.insert(decodedStatus.getFaceId());
Yanbiao Li73860e32015-08-19 16:30:16 -0700263 }
264
265 BOOST_CHECK_EQUAL(faceIds.size(), nEntries);
Junxiao Shida93f1f2015-11-11 06:13:16 -0700266 // TODO#3325 check dataset contents including counter values
Yanbiao Li73860e32015-08-19 16:30:16 -0700267}
268
269BOOST_AUTO_TEST_CASE(FaceQuery)
270{
Junxiao Shicde37ad2015-12-24 01:02:05 -0700271 auto face1 = addFace(REMOVE_LAST_NOTIFICATION); // dummy://
272 auto face2 = addFace(REMOVE_LAST_NOTIFICATION | SET_SCOPE_LOCAL); // dummy://, local
273 auto face3 = addFace(REMOVE_LAST_NOTIFICATION | SET_URI_TEST); // test://
Yanbiao Li73860e32015-08-19 16:30:16 -0700274
275 auto generateQueryName = [] (const ndn::nfd::FaceQueryFilter& filter) {
276 return Name("/localhost/nfd/faces/query").append(filter.wireEncode());
277 };
278
279 auto querySchemeName =
280 generateQueryName(ndn::nfd::FaceQueryFilter().setUriScheme("dummy"));
281 auto queryIdName =
282 generateQueryName(ndn::nfd::FaceQueryFilter().setFaceId(face1->getId()));
283 auto queryScopeName =
284 generateQueryName(ndn::nfd::FaceQueryFilter().setFaceScope(ndn::nfd::FACE_SCOPE_NON_LOCAL));
285 auto invalidQueryName =
286 Name("/localhost/nfd/faces/query").append(ndn::makeStringBlock(tlv::Content, "invalid"));
287
288 receiveInterest(makeInterest(querySchemeName)); // face1 and face2 expected
289 receiveInterest(makeInterest(queryIdName)); // face1 expected
290 receiveInterest(makeInterest(queryScopeName)); // face1 and face3 expected
291 receiveInterest(makeInterest(invalidQueryName)); // nack expected
292
293 BOOST_REQUIRE_EQUAL(m_responses.size(), 4);
294
295 Block content;
296 ndn::nfd::FaceStatus status;
297
298 content = m_responses[0].getContent();
299 BOOST_CHECK_NO_THROW(content.parse());
300 BOOST_CHECK_EQUAL(content.elements().size(), 2); // face1 and face2
301 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[0]));
302 BOOST_CHECK_EQUAL(face1->getId(), status.getFaceId());
303 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[1]));
304 BOOST_CHECK_EQUAL(face2->getId(), status.getFaceId());
305
306 content = m_responses[1].getContent();
307 BOOST_CHECK_NO_THROW(content.parse());
308 BOOST_CHECK_EQUAL(content.elements().size(), 1); // face1
309 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[0]));
310 BOOST_CHECK_EQUAL(face1->getId(), status.getFaceId());
311
312 content = m_responses[2].getContent();
313 BOOST_CHECK_NO_THROW(content.parse());
314 BOOST_CHECK_EQUAL(content.elements().size(), 2); // face1 and face3
315 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[0]));
316 BOOST_CHECK_EQUAL(face1->getId(), status.getFaceId());
317 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[1]));
318 BOOST_CHECK_EQUAL(face3->getId(), status.getFaceId());
319
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200320 ControlResponse expectedResponse(400, "Malformed filter"); // nack, 400, malformed filter
Yanbiao Li73860e32015-08-19 16:30:16 -0700321 BOOST_CHECK_EQUAL(checkResponse(3, invalidQueryName, expectedResponse, tlv::ContentType_Nack),
322 CheckResponseResult::OK);
323}
324
325class TestChannel : public Channel
326{
327public:
328 TestChannel(const std::string& uri)
329 {
330 setUri(FaceUri(uri));
331 }
332};
333
334class TestProtocolFactory : public ProtocolFactory
335{
336public:
337 virtual void
338 createFace(const FaceUri& uri,
339 ndn::nfd::FacePersistency persistency,
Eric Newberryf40551a2016-09-05 15:41:16 -0700340 bool wantLocalFieldsEnabled,
Yanbiao Li73860e32015-08-19 16:30:16 -0700341 const FaceCreatedCallback& onCreated,
Davide Pesaventob84bd3a2016-04-22 02:21:45 +0200342 const FaceCreationFailedCallback& onConnectFailed) override
Yanbiao Li73860e32015-08-19 16:30:16 -0700343 {
344 }
345
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200346 virtual std::vector<shared_ptr<const Channel>>
Davide Pesaventob84bd3a2016-04-22 02:21:45 +0200347 getChannels() const override
Yanbiao Li73860e32015-08-19 16:30:16 -0700348 {
349 return m_channels;
350 }
351
352public:
353 shared_ptr<TestChannel>
354 addChannel(const std::string& channelUri)
355 {
356 auto channel = make_shared<TestChannel>(channelUri);
357 m_channels.push_back(channel);
358 return channel;
359 }
360
361private:
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200362 std::vector<shared_ptr<const Channel>> m_channels;
Yanbiao Li73860e32015-08-19 16:30:16 -0700363};
364
365BOOST_AUTO_TEST_CASE(ChannelDataset)
366{
367 auto factory = make_shared<TestProtocolFactory>();
368 m_manager.m_factories["test"] = factory;
369
370 std::map<std::string, shared_ptr<TestChannel>> addedChannels;
371 size_t nEntries = 404;
372 for (size_t i = 0 ; i < nEntries ; i ++) {
373 auto channel = factory->addChannel("test" + boost::lexical_cast<std::string>(i) + "://");
374 addedChannels[channel->getUri().toString()] = channel;
375 }
376
377 receiveInterest(makeInterest("/localhost/nfd/faces/channels"));
378
379 Block content;
380 BOOST_CHECK_NO_THROW(content = concatenateResponses());
381 BOOST_CHECK_NO_THROW(content.parse());
382 BOOST_REQUIRE_EQUAL(content.elements().size(), nEntries);
383
384 for (size_t idx = 0; idx < nEntries; ++idx) {
385 BOOST_TEST_MESSAGE("processing element: " << idx);
386
387 ndn::nfd::ChannelStatus decodedStatus;
388 BOOST_CHECK_NO_THROW(decodedStatus.wireDecode(content.elements()[idx]));
389 BOOST_CHECK(addedChannels.find(decodedStatus.getLocalUri()) != addedChannels.end());
390 }
391}
392
393BOOST_AUTO_TEST_SUITE_END() // TestFaceManager
394BOOST_AUTO_TEST_SUITE_END() // Mgmt
395
396} // namespace tests
397} // namespace nfd