daemon: Support query that explicitly specify version

Change-Id: I8eac2c5d2a646fbb965691498f8d416a86b70763
diff --git a/src/daemon/name-server.cpp b/src/daemon/name-server.cpp
index f796e13..7411697 100644
--- a/src/daemon/name-server.cpp
+++ b/src/daemon/name-server.cpp
@@ -95,7 +95,8 @@
 
   NDNS_LOG_TRACE("query record: " << interest.getName());
 
-  if (m_dbMgr.find(rrset)) {
+  if (m_dbMgr.find(rrset) &&
+      (re.version.empty() || re.version == rrset.getVersion())) {
     // find the record: NDNS-RESP, NDNS-AUTH, NDNS-RAW, or NDNS-NACK
     shared_ptr<Data> answer = make_shared<Data>(rrset.getData());
     NDNS_LOG_TRACE("answer query with existing Data: " << answer->getName());
diff --git a/src/ndns-label.cpp b/src/ndns-label.cpp
index 585509c..1b1cc80 100644
--- a/src/ndns-label.cpp
+++ b/src/ndns-label.cpp
@@ -18,6 +18,7 @@
  */
 
 #include "ndns-label.hpp"
+
 #include <ndn-cxx/data.hpp>
 #include <ndn-cxx/interest.hpp>
 
@@ -59,7 +60,7 @@
           const Name& hint, const Name& zone,
           MatchResult& result)
 {
-  // [hint / FHLabel] / zoneName / <Update>|rrLabel / UPDATE|rrType
+  // [hint / FHLabel] / zoneName / <Update>|rrLabel / UPDATE|rrType / [VERSION]
 
   const Name& name = interest.getName();
   size_t skip = calculateSkip(name, hint, zone);
@@ -67,9 +68,17 @@
   if (name.size() - skip < 1)
     return false;
 
-  result.rrType = name.get(-1);
-  result.rrLabel = name.getSubName(skip, std::max<size_t>(0, name.size() - skip - 1));
-  result.version = name::Component();
+  size_t offset = 1;
+  if (name.get(-offset).isVersion()) {
+    result.version = name.get(-offset);
+    ++offset;
+  }
+  else {
+    result.version = name::Component();
+  }
+
+  result.rrType = name.get(-offset);
+  result.rrLabel = name.getSubName(skip, std::max<size_t>(0, name.size() - skip - offset));
 
   return true;
 }
diff --git a/tests/main.cpp b/tests/main.cpp
index 7d4602b..f9bf6b6 100644
--- a/tests/main.cpp
+++ b/tests/main.cpp
@@ -20,27 +20,52 @@
 #define BOOST_TEST_MAIN 1
 #define BOOST_TEST_DYN_LINK 1
 
+#include "config.hpp"
+#include "logger.hpp"
+
 #include <boost/version.hpp>
 #include <boost/test/unit_test.hpp>
 #include <boost/noncopyable.hpp>
+#include <boost/filesystem.hpp>
 
-#include "logger.hpp"
-#include "config.hpp"
+#include <fstream>
+#include <iostream>
 
 namespace ndn {
 namespace ndns {
 namespace tests {
 
-class UnitTestsLogging : boost::noncopyable
+class GlobalConfigurationFixture : boost::noncopyable
 {
 public:
-  UnitTestsLogging()
+  GlobalConfigurationFixture()
   {
     log::init("unit-tests.log4cxx");
+
+    if (std::getenv("HOME"))
+      m_home = std::getenv("HOME");
+
+    boost::filesystem::path dir(TEST_CONFIG_PATH);
+    dir /= "test-home";
+    setenv("HOME", dir.generic_string().c_str(), 1);
+    boost::filesystem::create_directories(dir);
+    std::ofstream clientConf((dir / ".ndn" / "client.conf").generic_string().c_str());
+    clientConf << "pib=pib-sqlite3\n"
+               << "tpm=tpm-file" << std::endl;
   }
+
+  ~GlobalConfigurationFixture()
+  {
+    if (!m_home.empty()) {
+      setenv("HOME", m_home.c_str(), 1);
+    }
+  }
+
+private:
+  std::string m_home;
 };
 
-BOOST_GLOBAL_FIXTURE(UnitTestsLogging)
+BOOST_GLOBAL_FIXTURE(GlobalConfigurationFixture)
 #if (BOOST_VERSION >= 105900)
 ;
 #endif // BOOST_VERSION >= 105900
diff --git a/tests/unit/daemon/name-server.cpp b/tests/unit/daemon/name-server.cpp
index 32f911c..9e7a926 100644
--- a/tests/unit/daemon/name-server.cpp
+++ b/tests/unit/daemon/name-server.cpp
@@ -130,6 +130,34 @@
   run();
 
   BOOST_CHECK_EQUAL(nDataBack, 2);
+
+  // explicit interest with correct version
+  face->receive(Interest("/test19/KEY/dsk-1/ID-CERT/%FDd"));
+
+  face->onSendData.connectSingleShot([&] (const Data& data) {
+    ++nDataBack;
+
+    Response resp;
+    BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
+    BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RAW);
+  });
+
+  run();
+  BOOST_CHECK_EQUAL(nDataBack, 3);
+
+  // explicit interest with wrong version
+  face->receive(Interest("/test19/KEY/dsk-1/ID-CERT/%FD010101010"));
+
+  face->onSendData.connectSingleShot([&] (const Data& data) {
+    ++nDataBack;
+
+    Response resp;
+    BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
+    BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_NACK);
+  });
+
+  run();
+  BOOST_CHECK_EQUAL(nDataBack, 4);
 }
 
 BOOST_AUTO_TEST_CASE(UpdateReplaceRr)
diff --git a/tests/unit/ndns-label.cpp b/tests/unit/ndns-label.cpp
index cb2e47e..09bb182 100644
--- a/tests/unit/ndns-label.cpp
+++ b/tests/unit/ndns-label.cpp
@@ -42,9 +42,9 @@
   BOOST_CHECK_EQUAL(re.version, name::Component());
 
   BOOST_CHECK_EQUAL(matchName(interest2, hint, zone, re), true);
-  BOOST_CHECK_EQUAL(re.rrLabel, Name("/www/dsk-111/NS"));
-  BOOST_CHECK_EQUAL(re.rrType, name::Component::fromEscapedString("%FD%00"));
-  BOOST_CHECK_EQUAL(re.version, name::Component());
+  BOOST_CHECK_EQUAL(re.rrLabel, Name("/www/dsk-111"));
+  BOOST_CHECK_EQUAL(re.rrType, name::Component("NS"));
+  BOOST_CHECK_EQUAL(re.version, name::Component::fromEscapedString("%FD%00"));
 }
 
 BOOST_AUTO_TEST_CASE(MatchData)
@@ -54,7 +54,6 @@
   Name zone("/net/ndnsim");
 
   Data data1("/att/%F0./net/ndnsim/NDNS/www/dsk-111/NS/%FD%00");
-  Data data2("/att/%F0./net/ndnsim/NDNS/www/dsk-111/NS");
 
   MatchResult re;
   BOOST_CHECK_EQUAL(matchName(data1, hint, zone, re), true);
@@ -62,11 +61,6 @@
   BOOST_CHECK_EQUAL(re.rrType, name::Component("NS"));
   BOOST_REQUIRE_NO_THROW(re.version.toVersion());
   BOOST_CHECK_EQUAL(re.version.toVersion(), 0);
-
-  BOOST_CHECK_EQUAL(matchName(data2, hint, zone, re), true);
-  BOOST_CHECK_EQUAL(re.rrLabel, Name("/www"));
-  BOOST_CHECK_EQUAL(re.rrType, name::Component("dsk-111"));
-  BOOST_REQUIRE_THROW(re.version.toVersion(), ndn::tlv::Error);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/wscript b/tests/wscript
index 25708c0..58de95d 100644
--- a/tests/wscript
+++ b/tests/wscript
@@ -31,8 +31,10 @@
         name='unit-tests-main',
         target='unit-tests-main',
         source='main.cpp',
-        defines=['BOOST_TEST_MODULE=NDNS Unit Tests'],
-        use='ndns-objects BOOST')
+        defines=['BOOST_TEST_MODULE=NDNS Unit Tests',
+                 'TEST_CONFIG_PATH=\"%s/conf-test\"' %(bld.bldnode)],
+        use='ndns-objects BOOST'
+    )
 
     unit_tests = bld.program(
         target='../unit-tests',