blob: c18989419c25b42681b05063a3b7d4aec5c3456f [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 Li73860e32015-08-19 16:30:16 -070027#include "face/tcp-factory.hpp"
28#include "face/udp-factory.hpp"
29
Davide Pesavento97210d52016-10-14 15:45:48 +020030#include "nfd-manager-common-fixture.hpp"
31#include "../face/dummy-face.hpp"
32
Yanbiao Li73860e32015-08-19 16:30:16 -070033#include <ndn-cxx/util/random.hpp>
34#include <ndn-cxx/encoding/tlv.hpp>
Junxiao Shi25c6ce42016-09-09 13:49:59 +000035#include <ndn-cxx/mgmt/nfd/channel-status.hpp>
36#include <ndn-cxx/mgmt/nfd/face-event-notification.hpp>
Yanbiao Li73860e32015-08-19 16:30:16 -070037
38namespace nfd {
39namespace tests {
40
Yanbiao Lidf846e52016-01-30 21:53:47 -080041class FaceManagerFixture : public NfdManagerCommonFixture
Yanbiao Li73860e32015-08-19 16:30:16 -070042{
43public:
44 FaceManagerFixture()
45 : m_faceTable(m_forwarder.getFaceTable())
Junxiao Shi9ddf1b52016-08-22 03:58:55 +000046 , m_manager(m_faceTable, m_dispatcher, *m_authenticator)
Yanbiao Li73860e32015-08-19 16:30:16 -070047 {
Junxiao Shi9ddf1b52016-08-22 03:58:55 +000048 setTopPrefix();
Yanbiao Lidf846e52016-01-30 21:53:47 -080049 setPrivilege("faces");
Yanbiao Li73860e32015-08-19 16:30:16 -070050 }
51
52public:
Junxiao Shicde37ad2015-12-24 01:02:05 -070053 enum AddFaceFlags {
54 REMOVE_LAST_NOTIFICATION = 1 << 0,
55 SET_SCOPE_LOCAL = 1 << 1,
56 SET_URI_TEST = 1 << 2,
57 RANDOMIZE_COUNTERS = 1 << 3
58 };
59
60 /** \brief adds a face to the FaceTable
61 * \param options bitwise OR'ed AddFaceFlags
62 */
Yanbiao Li73860e32015-08-19 16:30:16 -070063 shared_ptr<Face>
Junxiao Shicde37ad2015-12-24 01:02:05 -070064 addFace(int flags = 0)
Yanbiao Li73860e32015-08-19 16:30:16 -070065 {
Junxiao Shicde37ad2015-12-24 01:02:05 -070066 std::string uri = "dummy://";
67 ndn::nfd::FaceScope scope = ndn::nfd::FACE_SCOPE_NON_LOCAL;
68
69 if ((flags & SET_SCOPE_LOCAL) != 0) {
70 scope = ndn::nfd::FACE_SCOPE_LOCAL;
71 }
72 if ((flags & SET_URI_TEST) != 0) {
73 uri = "test://";
74 }
75
76 auto face = make_shared<DummyFace>(uri, uri, scope);
Yanbiao Li73860e32015-08-19 16:30:16 -070077 m_faceTable.add(face);
Junxiao Shicde37ad2015-12-24 01:02:05 -070078
79 if ((flags & RANDOMIZE_COUNTERS) != 0) {
80 const face::FaceCounters& counters = face->getCounters();
81 randomizeCounter(counters.nInInterests);
82 randomizeCounter(counters.nOutInterests);
83 randomizeCounter(counters.nInData);
84 randomizeCounter(counters.nOutData);
85 randomizeCounter(counters.nInNacks);
86 randomizeCounter(counters.nOutNacks);
87 randomizeCounter(counters.nInPackets);
88 randomizeCounter(counters.nOutPackets);
89 randomizeCounter(counters.nInBytes);
90 randomizeCounter(counters.nOutBytes);
91 }
92
Yanbiao Li73860e32015-08-19 16:30:16 -070093 advanceClocks(time::milliseconds(1), 10); // wait for notification posted
Junxiao Shicde37ad2015-12-24 01:02:05 -070094 if ((flags & REMOVE_LAST_NOTIFICATION) != 0) {
Yanbiao Li73860e32015-08-19 16:30:16 -070095 m_responses.pop_back();
96 }
Junxiao Shicde37ad2015-12-24 01:02:05 -070097
Yanbiao Li73860e32015-08-19 16:30:16 -070098 return face;
99 }
100
Junxiao Shicde37ad2015-12-24 01:02:05 -0700101private:
102 template<typename T>
103 static typename std::enable_if<std::is_base_of<SimpleCounter, T>::value>::type
104 randomizeCounter(const T& counter)
105 {
106 const_cast<T&>(counter).set(ndn::random::generateWord64());
107 }
108
Yanbiao Li73860e32015-08-19 16:30:16 -0700109protected:
110 FaceTable& m_faceTable;
111 FaceManager m_manager;
112};
113
Davide Pesavento97210d52016-10-14 15:45:48 +0200114BOOST_AUTO_TEST_SUITE(Mgmt)
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
Davide Pesavento97210d52016-10-14 15:45:48 +0200152BOOST_AUTO_TEST_SUITE(Datasets)
Yanbiao Li73860e32015-08-19 16:30:16 -0700153
154BOOST_AUTO_TEST_CASE(FaceDataset)
155{
156 size_t nEntries = 303;
Junxiao Shicde37ad2015-12-24 01:02:05 -0700157 for (size_t i = 0; i < nEntries; ++i) {
158 addFace(REMOVE_LAST_NOTIFICATION | SET_URI_TEST | RANDOMIZE_COUNTERS);
Yanbiao Li73860e32015-08-19 16:30:16 -0700159 }
160
161 receiveInterest(makeInterest("/localhost/nfd/faces/list"));
162
163 Block content;
164 BOOST_CHECK_NO_THROW(content = concatenateResponses());
165 BOOST_CHECK_NO_THROW(content.parse());
166 BOOST_REQUIRE_EQUAL(content.elements().size(), nEntries);
167
Yanbiao Li73860e32015-08-19 16:30:16 -0700168 std::set<FaceId> faceIds;
169 for (size_t idx = 0; idx < nEntries; ++idx) {
170 BOOST_TEST_MESSAGE("processing element: " << idx);
171
172 ndn::nfd::FaceStatus decodedStatus;
173 BOOST_REQUIRE_NO_THROW(decodedStatus.wireDecode(content.elements()[idx]));
Junxiao Shida93f1f2015-11-11 06:13:16 -0700174 BOOST_CHECK(m_faceTable.get(decodedStatus.getFaceId()) != nullptr);
Yanbiao Li73860e32015-08-19 16:30:16 -0700175 faceIds.insert(decodedStatus.getFaceId());
Yanbiao Li73860e32015-08-19 16:30:16 -0700176 }
177
178 BOOST_CHECK_EQUAL(faceIds.size(), nEntries);
Junxiao Shida93f1f2015-11-11 06:13:16 -0700179 // TODO#3325 check dataset contents including counter values
Yanbiao Li73860e32015-08-19 16:30:16 -0700180}
181
182BOOST_AUTO_TEST_CASE(FaceQuery)
183{
Junxiao Shicde37ad2015-12-24 01:02:05 -0700184 auto face1 = addFace(REMOVE_LAST_NOTIFICATION); // dummy://
185 auto face2 = addFace(REMOVE_LAST_NOTIFICATION | SET_SCOPE_LOCAL); // dummy://, local
186 auto face3 = addFace(REMOVE_LAST_NOTIFICATION | SET_URI_TEST); // test://
Yanbiao Li73860e32015-08-19 16:30:16 -0700187
188 auto generateQueryName = [] (const ndn::nfd::FaceQueryFilter& filter) {
189 return Name("/localhost/nfd/faces/query").append(filter.wireEncode());
190 };
191
192 auto querySchemeName =
193 generateQueryName(ndn::nfd::FaceQueryFilter().setUriScheme("dummy"));
194 auto queryIdName =
195 generateQueryName(ndn::nfd::FaceQueryFilter().setFaceId(face1->getId()));
196 auto queryScopeName =
197 generateQueryName(ndn::nfd::FaceQueryFilter().setFaceScope(ndn::nfd::FACE_SCOPE_NON_LOCAL));
198 auto invalidQueryName =
199 Name("/localhost/nfd/faces/query").append(ndn::makeStringBlock(tlv::Content, "invalid"));
200
201 receiveInterest(makeInterest(querySchemeName)); // face1 and face2 expected
202 receiveInterest(makeInterest(queryIdName)); // face1 expected
203 receiveInterest(makeInterest(queryScopeName)); // face1 and face3 expected
204 receiveInterest(makeInterest(invalidQueryName)); // nack expected
205
206 BOOST_REQUIRE_EQUAL(m_responses.size(), 4);
207
208 Block content;
209 ndn::nfd::FaceStatus status;
210
211 content = m_responses[0].getContent();
212 BOOST_CHECK_NO_THROW(content.parse());
213 BOOST_CHECK_EQUAL(content.elements().size(), 2); // face1 and face2
214 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[0]));
215 BOOST_CHECK_EQUAL(face1->getId(), status.getFaceId());
216 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[1]));
217 BOOST_CHECK_EQUAL(face2->getId(), status.getFaceId());
218
219 content = m_responses[1].getContent();
220 BOOST_CHECK_NO_THROW(content.parse());
221 BOOST_CHECK_EQUAL(content.elements().size(), 1); // face1
222 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[0]));
223 BOOST_CHECK_EQUAL(face1->getId(), status.getFaceId());
224
225 content = m_responses[2].getContent();
226 BOOST_CHECK_NO_THROW(content.parse());
227 BOOST_CHECK_EQUAL(content.elements().size(), 2); // face1 and face3
228 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[0]));
229 BOOST_CHECK_EQUAL(face1->getId(), status.getFaceId());
230 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[1]));
231 BOOST_CHECK_EQUAL(face3->getId(), status.getFaceId());
232
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200233 ControlResponse expectedResponse(400, "Malformed filter"); // nack, 400, malformed filter
Yanbiao Li73860e32015-08-19 16:30:16 -0700234 BOOST_CHECK_EQUAL(checkResponse(3, invalidQueryName, expectedResponse, tlv::ContentType_Nack),
235 CheckResponseResult::OK);
236}
237
238class TestChannel : public Channel
239{
240public:
Davide Pesavento97210d52016-10-14 15:45:48 +0200241 explicit
Yanbiao Li73860e32015-08-19 16:30:16 -0700242 TestChannel(const std::string& uri)
243 {
244 setUri(FaceUri(uri));
245 }
246};
247
248class TestProtocolFactory : public ProtocolFactory
249{
250public:
251 virtual void
252 createFace(const FaceUri& uri,
253 ndn::nfd::FacePersistency persistency,
Eric Newberryf40551a2016-09-05 15:41:16 -0700254 bool wantLocalFieldsEnabled,
Yanbiao Li73860e32015-08-19 16:30:16 -0700255 const FaceCreatedCallback& onCreated,
Davide Pesavento97210d52016-10-14 15:45:48 +0200256 const FaceCreationFailedCallback& onConnectFailed) final
Yanbiao Li73860e32015-08-19 16:30:16 -0700257 {
258 }
259
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200260 virtual std::vector<shared_ptr<const Channel>>
Davide Pesavento97210d52016-10-14 15:45:48 +0200261 getChannels() const final
Yanbiao Li73860e32015-08-19 16:30:16 -0700262 {
263 return m_channels;
264 }
265
266public:
267 shared_ptr<TestChannel>
268 addChannel(const std::string& channelUri)
269 {
270 auto channel = make_shared<TestChannel>(channelUri);
271 m_channels.push_back(channel);
272 return channel;
273 }
274
275private:
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200276 std::vector<shared_ptr<const Channel>> m_channels;
Yanbiao Li73860e32015-08-19 16:30:16 -0700277};
278
279BOOST_AUTO_TEST_CASE(ChannelDataset)
280{
281 auto factory = make_shared<TestProtocolFactory>();
282 m_manager.m_factories["test"] = factory;
283
284 std::map<std::string, shared_ptr<TestChannel>> addedChannels;
285 size_t nEntries = 404;
286 for (size_t i = 0 ; i < nEntries ; i ++) {
287 auto channel = factory->addChannel("test" + boost::lexical_cast<std::string>(i) + "://");
288 addedChannels[channel->getUri().toString()] = channel;
289 }
290
291 receiveInterest(makeInterest("/localhost/nfd/faces/channels"));
292
293 Block content;
294 BOOST_CHECK_NO_THROW(content = concatenateResponses());
295 BOOST_CHECK_NO_THROW(content.parse());
296 BOOST_REQUIRE_EQUAL(content.elements().size(), nEntries);
297
298 for (size_t idx = 0; idx < nEntries; ++idx) {
299 BOOST_TEST_MESSAGE("processing element: " << idx);
300
301 ndn::nfd::ChannelStatus decodedStatus;
302 BOOST_CHECK_NO_THROW(decodedStatus.wireDecode(content.elements()[idx]));
303 BOOST_CHECK(addedChannels.find(decodedStatus.getLocalUri()) != addedChannels.end());
304 }
305}
306
Davide Pesavento97210d52016-10-14 15:45:48 +0200307BOOST_AUTO_TEST_SUITE_END() // Datasets
308
309BOOST_AUTO_TEST_SUITE(Notifications)
310
311BOOST_AUTO_TEST_CASE(FaceEventNotification)
312{
313 auto addedFace = addFace(); // trigger FACE_EVENT_CREATED notification
314 BOOST_CHECK_NE(addedFace->getId(), -1);
315 int64_t faceId = addedFace->getId();
316
317 // check notification
318 {
319 Block payload;
320 ndn::nfd::FaceEventNotification notification;
321 BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
322 BOOST_CHECK_NO_THROW(payload = m_responses[0].getContent().blockFromValue());
323 BOOST_CHECK_EQUAL(payload.type(), ndn::tlv::nfd::FaceEventNotification);
324 BOOST_CHECK_NO_THROW(notification.wireDecode(payload));
325 BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_CREATED);
326 BOOST_CHECK_EQUAL(notification.getFaceId(), faceId);
327 BOOST_CHECK_EQUAL(notification.getRemoteUri(), addedFace->getRemoteUri().toString());
328 BOOST_CHECK_EQUAL(notification.getLocalUri(), addedFace->getLocalUri().toString());
329 BOOST_CHECK_EQUAL(notification.getFaceScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
330 BOOST_CHECK_EQUAL(notification.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
331 BOOST_CHECK_EQUAL(notification.getLinkType(), ndn::nfd::LinkType::LINK_TYPE_POINT_TO_POINT);
332 }
333
334 addedFace->close(); // trigger FaceDestroy FACE_EVENT_DESTROYED
335 advanceClocks(time::milliseconds(1), 10);
336
337 // check notification
338 {
339 Block payload;
340 ndn::nfd::FaceEventNotification notification;
341 BOOST_REQUIRE_EQUAL(m_responses.size(), 2);
342 BOOST_CHECK_NO_THROW(payload = m_responses[1].getContent().blockFromValue());
343 BOOST_CHECK_EQUAL(payload.type(), ndn::tlv::nfd::FaceEventNotification);
344 BOOST_CHECK_NO_THROW(notification.wireDecode(payload));
345 BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_DESTROYED);
346 BOOST_CHECK_EQUAL(notification.getFaceId(), faceId);
347 BOOST_CHECK_EQUAL(notification.getRemoteUri(), addedFace->getRemoteUri().toString());
348 BOOST_CHECK_EQUAL(notification.getLocalUri(), addedFace->getLocalUri().toString());
349 BOOST_CHECK_EQUAL(notification.getFaceScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
350 BOOST_CHECK_EQUAL(notification.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
351 BOOST_CHECK_EQUAL(notification.getLinkType(), ndn::nfd::LinkType::LINK_TYPE_POINT_TO_POINT);
352 }
353 BOOST_CHECK_EQUAL(addedFace->getId(), face::INVALID_FACEID);
354}
355
356BOOST_AUTO_TEST_SUITE_END() // Notifications
357
Yanbiao Li73860e32015-08-19 16:30:16 -0700358BOOST_AUTO_TEST_SUITE_END() // TestFaceManager
359BOOST_AUTO_TEST_SUITE_END() // Mgmt
360
361} // namespace tests
362} // namespace nfd