face: connect to Transport during construction

This allows DummyClientFace to receive packets without sending.

refs #2318

Change-Id: I7451d2c4a873e4680cfb380c9029b1edcd4af7fb
diff --git a/src/detail/face-impl.hpp b/src/detail/face-impl.hpp
index 248aca3..460d316 100644
--- a/src/detail/face-impl.hpp
+++ b/src/detail/face-impl.hpp
@@ -101,15 +101,21 @@
   /////////////////////////////////////////////////////////////////////////////////////////////////
 
   void
-  asyncExpressInterest(const shared_ptr<const Interest>& interest,
-                       const OnData& onData, const OnTimeout& onTimeout)
+  ensureConnected(bool wantResume = true)
   {
     if (!m_face.m_transport->isConnected())
       m_face.m_transport->connect(m_face.m_ioService,
                                   bind(&Face::onReceiveElement, &m_face, _1));
 
-    if (!m_face.m_transport->isExpectingData())
+    if (wantResume && !m_face.m_transport->isExpectingData())
       m_face.m_transport->resume();
+  }
+
+  void
+  asyncExpressInterest(const shared_ptr<const Interest>& interest,
+                       const OnData& onData, const OnTimeout& onTimeout)
+  {
+    this->ensureConnected();
 
     m_pendingInterestTable.push_back(make_shared<PendingInterest>(interest, onData, onTimeout));
 
@@ -141,12 +147,7 @@
   void
   asyncPutData(const shared_ptr<const Data>& data)
   {
-    if (!m_face.m_transport->isConnected())
-      m_face.m_transport->connect(m_face.m_ioService,
-                                  bind(&Face::onReceiveElement, &m_face, _1));
-
-    if (!m_face.m_transport->isExpectingData())
-      m_face.m_transport->resume();
+    this->ensureConnected();
 
     if (!data->getLocalControlHeader().empty(false, true))
       {
diff --git a/src/face.cpp b/src/face.cpp
index 8535924..57f9605 100644
--- a/src/face.cpp
+++ b/src/face.cpp
@@ -150,6 +150,7 @@
 
   m_impl->m_pitTimeoutCheckTimer      = make_shared<monotonic_deadline_timer>(ref(m_ioService));
   m_impl->m_processEventsTimeoutTimer = make_shared<monotonic_deadline_timer>(ref(m_ioService));
+  m_impl->ensureConnected(false);
 
   std::string protocol = "nrd-0.1";
 
diff --git a/src/util/dummy-client-face.cpp b/src/util/dummy-client-face.cpp
index a7ab505..ff24326 100644
--- a/src/util/dummy-client-face.cpp
+++ b/src/util/dummy-client-face.cpp
@@ -166,7 +166,7 @@
 shared_ptr<DummyClientFace>
 makeDummyClientFace(const DummyClientFace::Options& options)
 {
-  // cannot use make_shared<DummyClientFace> before DummyClientFace constructor is private
+  // cannot use make_shared<DummyClientFace> because DummyClientFace constructor is private
   return shared_ptr<DummyClientFace>(
          new DummyClientFace(options, make_shared<DummyClientFace::Transport>()));
 }
@@ -175,7 +175,7 @@
 makeDummyClientFace(boost::asio::io_service& ioService,
                     const DummyClientFace::Options& options)
 {
-  // cannot use make_shared<DummyClientFace> before DummyClientFace constructor is private
+  // cannot use make_shared<DummyClientFace> because DummyClientFace constructor is private
   return shared_ptr<DummyClientFace>(
          new DummyClientFace(options, make_shared<DummyClientFace::Transport>(),
                              ref(ioService)));
diff --git a/tests/unit-tests/test-faces.cpp b/tests/unit-tests/test-face.cpp
similarity index 93%
rename from tests/unit-tests/test-faces.cpp
rename to tests/unit-tests/test-face.cpp
index 57effc9..33c3643 100644
--- a/tests/unit-tests/test-faces.cpp
+++ b/tests/unit-tests/test-face.cpp
@@ -34,11 +34,11 @@
 using ndn::util::DummyClientFace;
 using ndn::util::makeDummyClientFace;
 
-class FacesFixture : public UnitTestTimeFixture
+class FaceFixture : public UnitTestTimeFixture
 {
 public:
   explicit
-  FacesFixture(bool enableRegistrationReply = true)
+  FaceFixture(bool enableRegistrationReply = true)
     : face(makeDummyClientFace(io, { true, enableRegistrationReply }))
   {
   }
@@ -47,16 +47,16 @@
   shared_ptr<DummyClientFace> face;
 };
 
-class FacesNoRegistrationReplyFixture : public FacesFixture
+class FacesNoRegistrationReplyFixture : public FaceFixture
 {
 public:
   FacesNoRegistrationReplyFixture()
-    : FacesFixture(false)
+    : FaceFixture(false)
   {
   }
 };
 
-BOOST_FIXTURE_TEST_SUITE(TestFaces, FacesFixture)
+BOOST_FIXTURE_TEST_SUITE(TestFace, FaceFixture)
 
 BOOST_AUTO_TEST_CASE(ExpressInterestData)
 {
@@ -327,6 +327,22 @@
   BOOST_CHECK_EQUAL(nInInterests, 2);
 }
 
+BOOST_FIXTURE_TEST_CASE(SetInterestFilterNoReg, FacesNoRegistrationReplyFixture) // Bug 2318
+{
+  // This behavior is specific to DummyClientFace.
+  // Regular Face won't accept incoming packets until something is sent.
+
+  int hit = 0;
+  face->setInterestFilter(Name("/"), bind([&hit] { ++hit; }));
+  face->processEvents(time::milliseconds(-1));
+
+  auto interest = make_shared<Interest>("/A");
+  face->receive(*interest);
+  face->processEvents(time::milliseconds(-1));
+
+  BOOST_CHECK_EQUAL(hit, 1);
+}
+
 BOOST_AUTO_TEST_CASE(ProcessEvents)
 {
   face->processEvents(time::milliseconds(-1)); // io_service::reset()/poll() inside