src: Add link support in consumer & producer

Change-Id: Icdb7c8cc12a69f0a519bf656392f1cc0b20f4a11
Refs: #3543
diff --git a/tests/unit-tests/consumer.t.cpp b/tests/unit-tests/consumer.t.cpp
index f7f39ce..15ede8b 100644
--- a/tests/unit-tests/consumer.t.cpp
+++ b/tests/unit-tests/consumer.t.cpp
@@ -290,6 +290,80 @@
   BOOST_CHECK_EQUAL(finalCount, 1);
 }
 
+BOOST_AUTO_TEST_CASE(CosumerWithLink)
+{
+  auto contentData = createEncryptedContent();
+  auto cKeyData = createEncryptedCKey();
+  auto dKeyData = createEncryptedDKey();
+
+  int contentCount = 0;
+  int cKeyCount = 0;
+  int dKeyCount = 0;
+  int resultCount = 0;
+
+  Name prefix("/Prefix");
+  // prepare face1
+  face1.setInterestFilter(prefix,
+                          [&] (const InterestFilter&, const Interest& i) {
+                            BOOST_CHECK(i.getLink().getDelegations().size() == 3);
+                            if (i.matchesData(*contentData)) {
+                              contentCount++;
+                              face1.put(*contentData);
+                              return;
+                            }
+                            if (i.matchesData(*cKeyData)) {
+                              cKeyCount++;
+                              face1.put(*cKeyData);
+                              return;
+                            }
+                            if (i.matchesData(*dKeyData)) {
+                              dKeyCount++;
+                              face1.put(*dKeyData);
+                              return;
+                            }
+                            return;
+                          },
+                          RegisterPrefixSuccessCallback(),
+                          [] (const Name&, const std::string& e) { });
+
+  do {
+    advanceClocks(time::milliseconds(10), 20);
+  } while (passPacket());
+
+  // create consumer
+  std::string dbDir = tmpPath.c_str();
+  dbDir += "/test.db";
+
+  Link ckeylink("ckey", {{10, "/ckey1"}, {20, "/ckey2"}, {100, "/ckey3"}});
+  Link dkeylink("dkey", {{10, "/dkey1"}, {20, "/dkey2"}, {100, "/dkey3"}});
+  Link datalink("data", {{10, "/data1"}, {20, "/data2"}, {100, "/data3"}});
+  keyChain.sign(ckeylink);
+  keyChain.sign(dkeylink);
+  keyChain.sign(datalink);
+
+  Consumer consumer(face2, groupName, uName, dbDir, ckeylink, dkeylink);
+  consumer.addDecryptionKey(uKeyName, fixtureUDKeyBuf);
+
+  consumer.consume(contentName,
+                   [&](const Data& data, const Buffer& result){
+                     BOOST_CHECK(true);
+                     resultCount++;
+                   },
+                   [](const ErrorCode& code, const std::string& str){
+                     BOOST_CHECK(false);
+                   },
+                   datalink);
+
+  do {
+    advanceClocks(time::milliseconds(10), 200);
+  } while (passPacket());
+
+  BOOST_CHECK_EQUAL(resultCount, 1);
+  BOOST_CHECK_EQUAL(contentCount, 1);
+  BOOST_CHECK_EQUAL(cKeyCount, 1);
+  BOOST_CHECK_EQUAL(dKeyCount, 1);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace test
diff --git a/tests/unit-tests/producer.t.cpp b/tests/unit-tests/producer.t.cpp
index 6367608..37d08d2 100755
--- a/tests/unit-tests/producer.t.cpp
+++ b/tests/unit-tests/producer.t.cpp
@@ -171,10 +171,8 @@
     advanceClocks(time::milliseconds(10), 20);
   } while (passPacket());
 
-  /*
-  Verify that content key is correctly encrypted for each domain, and the
-  produce method encrypts provided data with the same content key.
-  */
+  // Verify that content key is correctly encrypted for each domain, and the
+  // produce method encrypts provided data with the same content key.
   Producer producer(prefix, suffix, face1, dbDir);
   ProducerDB testDb(dbDir);
   Buffer contentKey;
@@ -327,10 +325,8 @@
     advanceClocks(time::milliseconds(10), 20);
   } while (passPacket());
 
-  /*
-  Verify that if a key is found, but not within the right timeslot, the search
-  is refined until a valid timeslot is found.
-  */
+  // Verify that if a key is found, but not within the right timeslot, the search
+  // is refined until a valid timeslot is found.
   Producer producer(prefix, suffix, face1, dbDir);
   producer.createContentKey(testTime,
           [&](const std::vector<Data>& result){
@@ -378,10 +374,8 @@
     advanceClocks(time::milliseconds(10), 20);
   } while (passPacket());
 
-  /*
-  Verify that if no response is received, the producer appropriately times out.
-  The result vector should not contain elements that have timed out.
-  */
+  // Verify that if no response is received, the producer appropriately times out.
+  // The result vector should not contain elements that have timed out.
   Producer producer(prefix, suffix, face1, dbDir);
   producer.createContentKey(testTime,
           [&](const std::vector<Data>& result){
@@ -394,6 +388,51 @@
   } while (passPacket());
 }
 
+BOOST_AUTO_TEST_CASE(ProducerWithLink)
+{
+  std::string dbDir = tmpPath.c_str();
+  dbDir += "/test.db";
+
+  Name prefix("/prefix");
+  Name suffix("/suffix");
+  Name expectedInterest = prefix;
+  expectedInterest.append(NAME_COMPONENT_READ);
+  expectedInterest.append(suffix);
+  expectedInterest.append(NAME_COMPONENT_E_KEY);
+
+  time::system_clock::TimePoint testTime = time::fromIsoString("20150101T100001");
+
+  size_t timeoutCount = 0;
+  face2.setInterestFilter(prefix,
+        [&] (const InterestFilter&, const Interest& i) {
+           BOOST_CHECK_EQUAL(i.getName(), expectedInterest);
+           BOOST_CHECK(i.getLink().getDelegations().size() == 3);
+           timeoutCount++;
+           return;
+        },
+        RegisterPrefixSuccessCallback(),
+        [] (const Name&, const std::string& e) { });
+
+  do {
+    advanceClocks(time::milliseconds(10), 20);
+  } while (passPacket());
+
+  // Verify that if no response is received, the producer appropriately times out.
+  // The result vector should not contain elements that have timed out.
+  Link link("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}});
+  keyChain.sign(link);
+  Producer producer(prefix, suffix, face1, dbDir, 3, link);
+  producer.createContentKey(testTime,
+          [&](const std::vector<Data>& result){
+            BOOST_CHECK_EQUAL(timeoutCount, 4);
+            BOOST_CHECK_EQUAL(result.size(), 0);
+          });
+
+  do {
+    advanceClocks(time::milliseconds(10), 800);
+  } while (passPacket());
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace tests