util: make DummyClientFace public API
refs #2164
Change-Id: I4a21b70faab1fc1f5cde8430ef602f2425150df9
diff --git a/src/util/dummy-client-face.cpp b/src/util/dummy-client-face.cpp
new file mode 100644
index 0000000..a7ab505
--- /dev/null
+++ b/src/util/dummy-client-face.cpp
@@ -0,0 +1,185 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "dummy-client-face.hpp"
+#include "../transport/transport.hpp"
+#include "../management/nfd-controller.hpp"
+#include "../management/nfd-control-response.hpp"
+
+namespace ndn {
+namespace util {
+
+const DummyClientFace::Options DummyClientFace::DEFAULT_OPTIONS { true, false };
+
+class DummyClientFace::Transport : public ndn::Transport
+{
+public:
+ void
+ receive(const Block& block)
+ {
+ if (static_cast<bool>(m_receiveCallback))
+ m_receiveCallback(block);
+ }
+
+ virtual void
+ close()
+ {
+ }
+
+ virtual void
+ pause()
+ {
+ }
+
+ virtual void
+ resume()
+ {
+ }
+
+ virtual void
+ send(const Block& wire)
+ {
+ if (wire.type() == tlv::Interest) {
+ shared_ptr<Interest> interest = make_shared<Interest>(wire);
+ (*m_onInterest)(*interest);
+ }
+ else if (wire.type() == tlv::Data) {
+ shared_ptr<Data> data = make_shared<Data>(wire);
+ (*m_onData)(*data);
+ }
+ }
+
+ virtual void
+ send(const Block& header, const Block& payload)
+ {
+ this->send(payload);
+ }
+
+ boost::asio::io_service&
+ getIoService()
+ {
+ return *m_ioService;
+ }
+
+private:
+ friend class DummyClientFace;
+ EventEmitter<Interest>* m_onInterest;
+ EventEmitter<Data>* m_onData;
+};
+
+DummyClientFace::DummyClientFace(const Options& options, shared_ptr<Transport> transport)
+ : Face(transport)
+ , m_transport(transport)
+{
+ this->construct(options);
+}
+
+DummyClientFace::DummyClientFace(const Options& options, shared_ptr<Transport> transport,
+ boost::asio::io_service& ioService)
+ : Face(transport, ioService)
+ , m_transport(transport)
+{
+ this->construct(options);
+}
+
+void
+DummyClientFace::construct(const Options& options)
+{
+ m_transport->m_onInterest = &onInterest;
+ m_transport->m_onData = &onData;
+
+ if (options.enablePacketLogging)
+ this->enablePacketLogging();
+
+ if (options.enableRegistrationReply)
+ this->enableRegistrationReply();
+}
+
+void
+DummyClientFace::enablePacketLogging()
+{
+ onInterest += [this] (const Interest& interest) { this->sentInterests.push_back(interest); };
+ onData += [this] (const Data& data) { this->sentDatas.push_back(data); };
+}
+
+void
+DummyClientFace::enableRegistrationReply()
+{
+ onInterest += [this] (const Interest& interest) {
+ static const Name localhostRegistration("/localhost/nfd/rib");
+ if (!localhostRegistration.isPrefixOf(interest.getName()))
+ return;
+
+ nfd::ControlParameters params(interest.getName().get(-5).blockFromValue());
+ params.setFaceId(1);
+ params.setOrigin(0);
+ if (interest.getName().get(3) == name::Component("register")) {
+ params.setCost(0);
+ }
+
+ nfd::ControlResponse resp;
+ resp.setCode(200);
+ resp.setBody(params.wireEncode());
+
+ shared_ptr<Data> data = make_shared<Data>(interest.getName());
+ data->setContent(resp.wireEncode());
+
+ KeyChain keyChain;
+ keyChain.signWithSha256(*data);
+
+ this->getIoService().post([this, data] { this->receive(*data); });
+ };
+}
+
+template<typename Packet>
+void
+DummyClientFace::receive(const Packet& packet)
+{
+ m_transport->receive(packet.wireEncode());
+}
+
+template void
+DummyClientFace::receive<Interest>(const Interest& packet);
+
+template void
+DummyClientFace::receive<Data>(const Data& packet);
+
+
+shared_ptr<DummyClientFace>
+makeDummyClientFace(const DummyClientFace::Options& options)
+{
+ // cannot use make_shared<DummyClientFace> before DummyClientFace constructor is private
+ return shared_ptr<DummyClientFace>(
+ new DummyClientFace(options, make_shared<DummyClientFace::Transport>()));
+}
+
+shared_ptr<DummyClientFace>
+makeDummyClientFace(boost::asio::io_service& ioService,
+ const DummyClientFace::Options& options)
+{
+ // cannot use make_shared<DummyClientFace> before DummyClientFace constructor is private
+ return shared_ptr<DummyClientFace>(
+ new DummyClientFace(options, make_shared<DummyClientFace::Transport>(),
+ ref(ioService)));
+}
+
+} // namespace util
+} // namespace ndn
diff --git a/src/util/dummy-client-face.hpp b/src/util/dummy-client-face.hpp
new file mode 100644
index 0000000..5ea9fab
--- /dev/null
+++ b/src/util/dummy-client-face.hpp
@@ -0,0 +1,133 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_UTIL_DUMMY_CLIENT_FACE_HPP
+#define NDN_UTIL_DUMMY_CLIENT_FACE_HPP
+
+#include "../face.hpp"
+#include "event-emitter.hpp"
+
+namespace ndn {
+namespace util {
+
+/** \brief a client-side face for unit testing
+ */
+class DummyClientFace : public ndn::Face
+{
+public:
+ /** \brief options for DummyClientFace
+ */
+ struct Options
+ {
+ /** \brief if true, packets sent out of DummyClientFace will be appended to a container
+ */
+ bool enablePacketLogging;
+
+ /** \brief if true, prefix registration command will be automatically
+ * replied with a successful response
+ */
+ bool enableRegistrationReply;
+ };
+
+ /** \brief cause the Face to receive a packet
+ * \tparam Packet either Interest or Data
+ */
+ template<typename Packet>
+ void
+ receive(const Packet& packet);
+
+private: // constructors
+ class Transport;
+
+ // constructors are private; use makeDummyClientFace to create DummyClientFace
+
+ DummyClientFace(const Options& options, shared_ptr<Transport> transport);
+
+ DummyClientFace(const Options& options, shared_ptr<Transport> transport,
+ boost::asio::io_service& ioService);
+
+ void
+ construct(const Options& options);
+
+ friend shared_ptr<DummyClientFace>
+ makeDummyClientFace(const DummyClientFace::Options& options);
+
+ friend shared_ptr<DummyClientFace>
+ makeDummyClientFace(boost::asio::io_service& ioService, const DummyClientFace::Options& options);
+
+private:
+ void
+ enablePacketLogging();
+
+ void
+ enableRegistrationReply();
+
+public:
+ /** \brief default options
+ *
+ * enablePacketLogging=true
+ * enableRegistrationReply=false
+ */
+ static const Options DEFAULT_OPTIONS;
+
+ /** \brief Interests sent out of this DummyClientFace
+ *
+ * Sent Interests are appended to this container if options.enablePacketLogger is true.
+ * User of this class is responsible for cleaning up the container, if necessary.
+ * After .expressInterest, .processEvents must be called before the Interest would show up here.
+ */
+ std::vector<Interest> sentInterests;
+
+ /** \brief Data sent out of this DummyClientFace
+ *
+ * Sent Data are appended to this container if options.enablePacketLogger is true.
+ * User of this class is responsible for cleaning up the container, if necessary.
+ * After .put, .processEvents must be called before the Data would show up here.
+ */
+ std::vector<Data> sentDatas;
+
+ /** \brief Event to be called whenever an Interest is received
+ *
+ * After .expressInterest, .processEvents must be called before this event would be triggered.
+ */
+ util::EventEmitter<Interest> onInterest;
+
+ /** \brief Event to be called whenever a Data packet is received
+ *
+ * After .put, .processEvents must be called before this event would be triggered.
+ */
+ util::EventEmitter<Data> onData;
+
+private:
+ shared_ptr<Transport> m_transport;
+};
+
+shared_ptr<DummyClientFace>
+makeDummyClientFace(const DummyClientFace::Options& options = DummyClientFace::DEFAULT_OPTIONS);
+
+shared_ptr<DummyClientFace>
+makeDummyClientFace(boost::asio::io_service& ioService,
+ const DummyClientFace::Options& options = DummyClientFace::DEFAULT_OPTIONS);
+
+} // namespace util
+} // namespace ndn
+
+#endif // NDN_UTIL_DUMMY_CLIENT_FACE_HPP