blob: 02bcd7883f6d19a27a76e79c972d2229bdba82f2 [file] [log] [blame]
Yanbiao Li73860e32015-08-19 16:30:16 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Regents of the University of California,
4 * 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"
27#include "manager-common-fixture.hpp"
28#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>
34#include <ndn-cxx/management/nfd-channel-status.hpp>
35#include <ndn-cxx/management/nfd-face-event-notification.hpp>
36
37namespace nfd {
38namespace tests {
39
40class FaceManagerFixture : public ManagerCommonFixture
41{
42public:
43 FaceManagerFixture()
44 : m_faceTable(m_forwarder.getFaceTable())
45 , m_manager(m_faceTable, m_dispatcher, m_validator)
46 {
47 setTopPrefixAndPrivilege("/localhost/nfd", "faces");
48 }
49
50public:
51 template<typename Face>
52 shared_ptr<Face>
53 addFace(bool wantRemoveLastNotification = false)
54 {
55 auto face = make_shared<Face>();
56 m_faceTable.add(face);
57 advanceClocks(time::milliseconds(1), 10); // wait for notification posted
58 if (wantRemoveLastNotification) {
59 m_responses.pop_back();
60 }
61 return face;
62 }
63
64protected:
65 FaceTable& m_faceTable;
66 FaceManager m_manager;
67};
68
69BOOST_FIXTURE_TEST_SUITE(Mgmt, FaceManagerFixture)
70BOOST_AUTO_TEST_SUITE(TestFaceManager)
71
72BOOST_AUTO_TEST_SUITE(DestroyFace)
73
74BOOST_AUTO_TEST_CASE(Existing)
75{
76 auto addedFace = addFace<DummyFace>(true); // clear notification for creation
77
78 auto parameters = ControlParameters().setFaceId(addedFace->getId());
79 auto command = makeControlCommandRequest("/localhost/nfd/faces/destroy", parameters);
80
81 receiveInterest(command);
82
83 BOOST_REQUIRE_EQUAL(m_responses.size(), 2); // one response and one notification
84 // notification is already tested, so ignore it
85
86 BOOST_CHECK_EQUAL(checkResponse(1, command->getName(), makeResponse(200, "OK", parameters)),
87 CheckResponseResult::OK);
88
89 BOOST_CHECK_EQUAL(addedFace->getId(), -1);
90}
91
92BOOST_AUTO_TEST_CASE(NonExisting)
93{
94 auto parameters = ControlParameters().setFaceId(65535);
95 auto command = makeControlCommandRequest("/localhost/nfd/faces/destroy", parameters);
96
97 receiveInterest(command);
98
99 BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
100
101 BOOST_CHECK_EQUAL(checkResponse(0, command->getName(), makeResponse(200, "OK", parameters)),
102 CheckResponseResult::OK);
103}
104
105BOOST_AUTO_TEST_SUITE_END() // DestroyFace
106
107BOOST_AUTO_TEST_CASE(FaceEvents)
108{
109 auto addedFace = addFace<DummyFace>(); // trigger FACE_EVENT_CREATED notification
110 BOOST_CHECK_NE(addedFace->getId(), -1);
111 int64_t faceId = addedFace->getId();
112
113 // check notification
114 {
115 Block payload;
116 ndn::nfd::FaceEventNotification notification;
117 BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
118 BOOST_CHECK_NO_THROW(payload = m_responses[0].getContent().blockFromValue());
119 BOOST_CHECK_EQUAL(payload.type(), ndn::tlv::nfd::FaceEventNotification);
120 BOOST_CHECK_NO_THROW(notification.wireDecode(payload));
121 BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_CREATED);
122 BOOST_CHECK_EQUAL(notification.getFaceId(), faceId);
123 BOOST_CHECK_EQUAL(notification.getRemoteUri(), addedFace->getRemoteUri().toString());
124 BOOST_CHECK_EQUAL(notification.getLocalUri(), addedFace->getLocalUri().toString());
125 BOOST_CHECK_EQUAL(notification.getFaceScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
126 BOOST_CHECK_EQUAL(notification.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
127 BOOST_CHECK_EQUAL(notification.getLinkType(), ndn::nfd::LinkType::LINK_TYPE_POINT_TO_POINT);
128 }
129
130 addedFace->close(); // trigger FaceDestroy FACE_EVENT_DESTROYED
131 advanceClocks(time::milliseconds(1), 10);
132
133 // check notification
134 {
135 Block payload;
136 ndn::nfd::FaceEventNotification notification;
137 BOOST_REQUIRE_EQUAL(m_responses.size(), 2);
138 BOOST_CHECK_NO_THROW(payload = m_responses[1].getContent().blockFromValue());
139 BOOST_CHECK_EQUAL(payload.type(), ndn::tlv::nfd::FaceEventNotification);
140 BOOST_CHECK_NO_THROW(notification.wireDecode(payload));
141 BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_DESTROYED);
142 BOOST_CHECK_EQUAL(notification.getFaceId(), faceId);
143 BOOST_CHECK_EQUAL(notification.getRemoteUri(), addedFace->getRemoteUri().toString());
144 BOOST_CHECK_EQUAL(notification.getLocalUri(), addedFace->getLocalUri().toString());
145 BOOST_CHECK_EQUAL(notification.getFaceScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
146 BOOST_CHECK_EQUAL(notification.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
147 BOOST_CHECK_EQUAL(notification.getLinkType(), ndn::nfd::LinkType::LINK_TYPE_POINT_TO_POINT);
148 }
149 BOOST_CHECK_EQUAL(addedFace->getId(), -1);
150}
151
Yanbiao Li73860e32015-08-19 16:30:16 -0700152class TestFace : public DummyFace
153{
154public:
155 explicit
156 TestFace(const std::string& uri = "test://")
157 : DummyFace(uri, uri)
158 {
159 getMutableCounters().getNInInterests().set(ndn::random::generateWord64());
160 getMutableCounters().getNInDatas().set(ndn::random::generateWord64());
161 getMutableCounters().getNOutInterests().set(ndn::random::generateWord64());
162 getMutableCounters().getNOutDatas().set(ndn::random::generateWord64());
163 getMutableCounters().getNInBytes().set(ndn::random::generateWord64());
164 getMutableCounters().getNOutBytes().set(ndn::random::generateWord64());
165 }
166};
167
168// @todo Refactor when ndn::nfd::FaceStatus implementes operator!= and operator<<
169class FaceStatus : public ndn::nfd::FaceStatus
170{
171public:
172 FaceStatus(const ndn::nfd::FaceStatus& s)
173 : ndn::nfd::FaceStatus(s)
174 {
175 }
176};
177
178bool
179operator!=(const FaceStatus& left, const FaceStatus& right)
180{
181 return left.getRemoteUri() != right.getRemoteUri() ||
182 left.getLocalUri() != right.getLocalUri() ||
183 left.getFaceScope() != right.getFaceScope() ||
184 left.getFacePersistency() != right.getFacePersistency() ||
185 left.getLinkType() != right.getLinkType() ||
186 left.getNInInterests() != right.getNInInterests() ||
187 left.getNInDatas() != right.getNInDatas() ||
188 left.getNOutInterests() != right.getNOutInterests() ||
189 left.getNOutDatas() != right.getNOutDatas() ||
190 left.getNInBytes() != right.getNInBytes() ||
191 left.getNOutBytes() != right.getNOutBytes();
192}
193
194std::ostream&
195operator<<(std::ostream &os, const FaceStatus& status)
196{
197 os << "[" << status.getRemoteUri() << ", "
198 << status.getLocalUri() << ", "
199 << status.getFacePersistency() << ", "
200 << status.getLinkType() << ", "
201 << status.getNInInterests() << ", "
202 << status.getNInDatas() << ", "
203 << status.getNOutInterests() << ", "
204 << status.getNOutDatas() << ", "
205 << status.getNInBytes() << ", "
206 << status.getNOutBytes() << "]";
207 return os;
208}
209
210BOOST_AUTO_TEST_CASE(FaceDataset)
211{
212 size_t nEntries = 303;
213 for (size_t i = 0 ; i < nEntries ; i ++) {
214 addFace<TestFace>(true);
215 }
216
217 receiveInterest(makeInterest("/localhost/nfd/faces/list"));
218
219 Block content;
220 BOOST_CHECK_NO_THROW(content = concatenateResponses());
221 BOOST_CHECK_NO_THROW(content.parse());
222 BOOST_REQUIRE_EQUAL(content.elements().size(), nEntries);
223
Yanbiao Li73860e32015-08-19 16:30:16 -0700224 std::set<FaceId> faceIds;
225 for (size_t idx = 0; idx < nEntries; ++idx) {
226 BOOST_TEST_MESSAGE("processing element: " << idx);
227
228 ndn::nfd::FaceStatus decodedStatus;
229 BOOST_REQUIRE_NO_THROW(decodedStatus.wireDecode(content.elements()[idx]));
Junxiao Shida93f1f2015-11-11 06:13:16 -0700230 BOOST_CHECK(m_faceTable.get(decodedStatus.getFaceId()) != nullptr);
Yanbiao Li73860e32015-08-19 16:30:16 -0700231 faceIds.insert(decodedStatus.getFaceId());
Yanbiao Li73860e32015-08-19 16:30:16 -0700232 }
233
234 BOOST_CHECK_EQUAL(faceIds.size(), nEntries);
Junxiao Shida93f1f2015-11-11 06:13:16 -0700235 // TODO#3325 check dataset contents including counter values
Yanbiao Li73860e32015-08-19 16:30:16 -0700236}
237
238BOOST_AUTO_TEST_CASE(FaceQuery)
239{
240 auto face1 = addFace<DummyFace>(true); // dummy://
241 auto face2 = addFace<DummyLocalFace>(true); // dummy://, local
242 auto face3 = addFace<TestFace>(true); // test://
243
244 auto generateQueryName = [] (const ndn::nfd::FaceQueryFilter& filter) {
245 return Name("/localhost/nfd/faces/query").append(filter.wireEncode());
246 };
247
248 auto querySchemeName =
249 generateQueryName(ndn::nfd::FaceQueryFilter().setUriScheme("dummy"));
250 auto queryIdName =
251 generateQueryName(ndn::nfd::FaceQueryFilter().setFaceId(face1->getId()));
252 auto queryScopeName =
253 generateQueryName(ndn::nfd::FaceQueryFilter().setFaceScope(ndn::nfd::FACE_SCOPE_NON_LOCAL));
254 auto invalidQueryName =
255 Name("/localhost/nfd/faces/query").append(ndn::makeStringBlock(tlv::Content, "invalid"));
256
257 receiveInterest(makeInterest(querySchemeName)); // face1 and face2 expected
258 receiveInterest(makeInterest(queryIdName)); // face1 expected
259 receiveInterest(makeInterest(queryScopeName)); // face1 and face3 expected
260 receiveInterest(makeInterest(invalidQueryName)); // nack expected
261
262 BOOST_REQUIRE_EQUAL(m_responses.size(), 4);
263
264 Block content;
265 ndn::nfd::FaceStatus status;
266
267 content = m_responses[0].getContent();
268 BOOST_CHECK_NO_THROW(content.parse());
269 BOOST_CHECK_EQUAL(content.elements().size(), 2); // face1 and face2
270 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[0]));
271 BOOST_CHECK_EQUAL(face1->getId(), status.getFaceId());
272 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[1]));
273 BOOST_CHECK_EQUAL(face2->getId(), status.getFaceId());
274
275 content = m_responses[1].getContent();
276 BOOST_CHECK_NO_THROW(content.parse());
277 BOOST_CHECK_EQUAL(content.elements().size(), 1); // face1
278 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[0]));
279 BOOST_CHECK_EQUAL(face1->getId(), status.getFaceId());
280
281 content = m_responses[2].getContent();
282 BOOST_CHECK_NO_THROW(content.parse());
283 BOOST_CHECK_EQUAL(content.elements().size(), 2); // face1 and face3
284 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[0]));
285 BOOST_CHECK_EQUAL(face1->getId(), status.getFaceId());
286 BOOST_CHECK_NO_THROW(status.wireDecode(content.elements()[1]));
287 BOOST_CHECK_EQUAL(face3->getId(), status.getFaceId());
288
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200289 ControlResponse expectedResponse(400, "Malformed filter"); // nack, 400, malformed filter
Yanbiao Li73860e32015-08-19 16:30:16 -0700290 BOOST_CHECK_EQUAL(checkResponse(3, invalidQueryName, expectedResponse, tlv::ContentType_Nack),
291 CheckResponseResult::OK);
292}
293
294class TestChannel : public Channel
295{
296public:
297 TestChannel(const std::string& uri)
298 {
299 setUri(FaceUri(uri));
300 }
301};
302
303class TestProtocolFactory : public ProtocolFactory
304{
305public:
306 virtual void
307 createFace(const FaceUri& uri,
308 ndn::nfd::FacePersistency persistency,
309 const FaceCreatedCallback& onCreated,
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200310 const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE
Yanbiao Li73860e32015-08-19 16:30:16 -0700311 {
312 }
313
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200314 virtual std::vector<shared_ptr<const Channel>>
Yanbiao Li73860e32015-08-19 16:30:16 -0700315 getChannels() const DECL_OVERRIDE
316 {
317 return m_channels;
318 }
319
320public:
321 shared_ptr<TestChannel>
322 addChannel(const std::string& channelUri)
323 {
324 auto channel = make_shared<TestChannel>(channelUri);
325 m_channels.push_back(channel);
326 return channel;
327 }
328
329private:
Davide Pesavento1d7e7af2015-10-10 23:54:08 +0200330 std::vector<shared_ptr<const Channel>> m_channels;
Yanbiao Li73860e32015-08-19 16:30:16 -0700331};
332
333BOOST_AUTO_TEST_CASE(ChannelDataset)
334{
335 auto factory = make_shared<TestProtocolFactory>();
336 m_manager.m_factories["test"] = factory;
337
338 std::map<std::string, shared_ptr<TestChannel>> addedChannels;
339 size_t nEntries = 404;
340 for (size_t i = 0 ; i < nEntries ; i ++) {
341 auto channel = factory->addChannel("test" + boost::lexical_cast<std::string>(i) + "://");
342 addedChannels[channel->getUri().toString()] = channel;
343 }
344
345 receiveInterest(makeInterest("/localhost/nfd/faces/channels"));
346
347 Block content;
348 BOOST_CHECK_NO_THROW(content = concatenateResponses());
349 BOOST_CHECK_NO_THROW(content.parse());
350 BOOST_REQUIRE_EQUAL(content.elements().size(), nEntries);
351
352 for (size_t idx = 0; idx < nEntries; ++idx) {
353 BOOST_TEST_MESSAGE("processing element: " << idx);
354
355 ndn::nfd::ChannelStatus decodedStatus;
356 BOOST_CHECK_NO_THROW(decodedStatus.wireDecode(content.elements()[idx]));
357 BOOST_CHECK(addedChannels.find(decodedStatus.getLocalUri()) != addedChannels.end());
358 }
359}
360
361BOOST_AUTO_TEST_SUITE_END() // TestFaceManager
362BOOST_AUTO_TEST_SUITE_END() // Mgmt
363
364} // namespace tests
365} // namespace nfd