util: make SegmentFetcher test suite run faster

UnitTestTimeFixture::advanceClocks is invoked with less ticks of
larger duration when feasible, so that test cases run faster.

UnitTestTimeFixture is synchronized from NFD codebase.

refs #2734

Change-Id: Ifd338f1008af8662bb9ea8f798f6cc2a922fb865
diff --git a/tests/unit-tests/security/certificate-cache-ttl.t.cpp b/tests/unit-tests/security/certificate-cache-ttl.t.cpp
index 4d3430d..6d35811 100644
--- a/tests/unit-tests/security/certificate-cache-ttl.t.cpp
+++ b/tests/unit-tests/security/certificate-cache-ttl.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -29,7 +29,8 @@
 namespace ndn {
 namespace tests {
 
-BOOST_AUTO_TEST_SUITE(SecurityCertificateCacheTtl)
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(TestCertificateCacheTtl)
 
 class CertificateCacheFixture : public UnitTestTimeFixture
 {
@@ -69,7 +70,7 @@
   cache->insertCertificate(cert1);
   cache->insertCertificate(cert2);
 
-  advanceClocks(time::nanoseconds(0));
+  advanceClocks(time::nanoseconds(1));
   BOOST_CHECK_EQUAL(cache->getSize(), 2);
 
   scheduler.scheduleEvent(time::milliseconds(200), [&] {
@@ -97,7 +98,7 @@
 {
   cache->insertCertificate(cert1); // 500ms
 
-  advanceClocks(time::nanoseconds(0));
+  advanceClocks(time::nanoseconds(1));
   BOOST_CHECK_EQUAL(cache->getSize(), 1);
 
   advanceClocks(time::milliseconds(400));
@@ -106,7 +107,7 @@
     // Refresh certificate in cache
   cache->insertCertificate(cert1); // +500ms
 
-  advanceClocks(time::nanoseconds(0));
+  advanceClocks(time::nanoseconds(1));
   BOOST_CHECK_EQUAL(cache->getSize(), 1);
 
   advanceClocks(time::milliseconds(400));
@@ -121,16 +122,17 @@
   cache->insertCertificate(cert1);
   cache->insertCertificate(cert2);
 
-  advanceClocks(time::nanoseconds(0));
+  advanceClocks(time::nanoseconds(1));
   BOOST_CHECK_EQUAL(cache->getSize(), 2);
 
   cache->reset();
 
-  advanceClocks(time::nanoseconds(0));
+  advanceClocks(time::nanoseconds(1));
   BOOST_CHECK_EQUAL(cache->getSize(), 0);
 }
 
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() // TestCertificateCacheTtl
+BOOST_AUTO_TEST_SUITE_END() // Security
 
 } // namespace tests
 } // namespace ndn
diff --git a/tests/unit-tests/security/validator-config.t.cpp b/tests/unit-tests/security/validator-config.t.cpp
index 1c72e69..005ca9b 100644
--- a/tests/unit-tests/security/validator-config.t.cpp
+++ b/tests/unit-tests/security/validator-config.t.cpp
@@ -38,7 +38,8 @@
 
 using namespace ndn::tests;
 
-BOOST_FIXTURE_TEST_SUITE(SecurityValidatorConfig, IdentityManagementFixture)
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_FIXTURE_TEST_SUITE(TestValidatorConfig, IdentityManagementFixture)
 
 BOOST_AUTO_TEST_CASE(NameFilter)
 {
@@ -1287,7 +1288,7 @@
 
 BOOST_FIXTURE_TEST_CASE(Nrd, FacesFixture)
 {
-  advanceClocks(time::milliseconds(0));
+  advanceClocks(time::nanoseconds(1));
 
   std::vector<CertificateSubjectDescription> subjectDescription;
 
@@ -1577,7 +1578,8 @@
   advanceClocks(time::milliseconds(10), 20);
 }
 
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() // TestValidatorConfig
+BOOST_AUTO_TEST_SUITE_END() // Security
 
 } // namespace tests
 } // namespace security
diff --git a/tests/unit-tests/unit-test-time-fixture.hpp b/tests/unit-tests/unit-test-time-fixture.hpp
index 8d7ac17..9f43258 100644
--- a/tests/unit-tests/unit-test-time-fixture.hpp
+++ b/tests/unit-tests/unit-test-time-fixture.hpp
@@ -29,6 +29,8 @@
 namespace ndn {
 namespace tests {
 
+/** \brief a test fixture that overrides steady clock and system clock
+ */
 class UnitTestTimeFixture
 {
 public:
@@ -44,12 +46,47 @@
     time::setCustomClocks(nullptr, nullptr);
   }
 
+  /** \brief advance steady and system clocks
+   *
+   *  Clocks are advanced in increments of \p tick for \p nTicks ticks.
+   *  After each tick, io_service is polled to process pending I/O events.
+   *
+   *  Exceptions thrown during I/O events are propagated to the caller.
+   *  Clock advancing would stop in case of an exception.
+   */
   void
   advanceClocks(const time::nanoseconds& tick, size_t nTicks = 1)
   {
-    for (size_t i = 0; i < nTicks; ++i) {
-      steadyClock->advance(tick);
-      systemClock->advance(tick);
+    this->advanceClocks(tick, tick * nTicks);
+  }
+
+  /** \brief advance steady and system clocks
+   *
+   *  Clocks are advanced in increments of \p tick for \p total time.
+   *  The last increment might be shorter than \p tick.
+   *  After each tick, io_service is polled to process pending I/O events.
+   *
+   *  Exceptions thrown during I/O events are propagated to the caller.
+   *  Clock advancing would stop in case of an exception.
+   */
+  void
+  advanceClocks(const time::nanoseconds& tick, const time::nanoseconds& total)
+  {
+    BOOST_ASSERT(tick > time::nanoseconds::zero());
+    BOOST_ASSERT(total >= time::nanoseconds::zero());
+
+    time::nanoseconds remaining = total;
+    while (remaining > time::nanoseconds::zero()) {
+      if (remaining >= tick) {
+        steadyClock->advance(tick);
+        systemClock->advance(tick);
+        remaining -= tick;
+      }
+      else {
+        steadyClock->advance(remaining);
+        systemClock->advance(remaining);
+        remaining = time::nanoseconds::zero();
+      }
 
       if (io.stopped())
         io.reset();
diff --git a/tests/unit-tests/util/segment-fetcher.t.cpp b/tests/unit-tests/util/segment-fetcher.t.cpp
index 8fbbb45..462e759 100644
--- a/tests/unit-tests/util/segment-fetcher.t.cpp
+++ b/tests/unit-tests/util/segment-fetcher.t.cpp
@@ -38,7 +38,8 @@
 
 using namespace ndn::tests;
 
-BOOST_AUTO_TEST_SUITE(UtilSegmentFetcher)
+BOOST_AUTO_TEST_SUITE(Util)
+BOOST_AUTO_TEST_SUITE(TestSegmentFetcher)
 
 class Fixture : public IdentityManagementTimeFixture
 {
@@ -46,7 +47,7 @@
   Fixture()
     : face(io, m_keyChain)
     , nErrors(0)
-    , nDatas(0)
+    , nData(0)
     , dataSize(0)
   {
   }
@@ -56,7 +57,7 @@
   {
     const uint8_t buffer[] = "Hello, world!";
 
-    shared_ptr<Data> data = make_shared<Data>(Name(baseName).appendSegment(segment));
+    auto data = make_shared<Data>(Name(baseName).appendSegment(segment));
     data->setContent(buffer, sizeof(buffer));
 
     if (isFinal) {
@@ -77,7 +78,7 @@
   void
   onComplete(const ConstBufferPtr& data)
   {
-    ++nDatas;
+    ++nData;
     dataSize = data->size();
     dataString = std::string(reinterpret_cast<const char*>(data->get()));
   }
@@ -88,7 +89,7 @@
     const Interest& lastInterest = face.sentInterests.back();
     lp::Nack nack = makeNack(lastInterest, nackReason);
     face.receive(nack);
-    advanceClocks(time::milliseconds(1), 10);
+    advanceClocks(time::milliseconds(10));
   }
 
 public:
@@ -96,7 +97,7 @@
 
   uint32_t nErrors;
   uint32_t lastError;
-  uint32_t nDatas;
+  uint32_t nData;
   size_t dataSize;
   std::string dataString;
 };
@@ -109,20 +110,20 @@
                         bind(&Fixture::onComplete, this, _1),
                         bind(&Fixture::onError, this, _1));
 
-  advanceClocks(time::milliseconds(1), 99);
-
-  BOOST_CHECK_EQUAL(nErrors, 0);
-  BOOST_CHECK_EQUAL(nDatas, 0);
+  advanceClocks(time::milliseconds(1));
   BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
-  BOOST_CHECK_EQUAL(face.sentData.size(), 0);
 
   const Interest& interest = face.sentInterests[0];
   BOOST_CHECK_EQUAL(interest.getName(), "/hello/world");
   BOOST_CHECK_EQUAL(interest.getMustBeFresh(), true);
   BOOST_CHECK_EQUAL(interest.getChildSelector(), 1);
 
-  advanceClocks(time::milliseconds(1), 2);
+  advanceClocks(time::milliseconds(98));
+  BOOST_CHECK_EQUAL(nErrors, 0);
+  BOOST_CHECK_EQUAL(nData, 0);
+  BOOST_CHECK_EQUAL(face.sentData.size(), 0);
 
+  advanceClocks(time::milliseconds(1), 2);
   BOOST_CHECK_EQUAL(nErrors, 1);
   BOOST_CHECK_EQUAL(lastError, static_cast<uint32_t>(SegmentFetcher::INTEREST_TIMEOUT));
   BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
@@ -138,13 +139,13 @@
                         bind(&Fixture::onComplete, this, _1),
                         bind(&Fixture::onError, this, _1));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
 
   face.receive(*makeDataSegment("/hello/world/version0", 0, true));
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
 
   BOOST_CHECK_EQUAL(nErrors, 0);
-  BOOST_CHECK_EQUAL(nDatas, 1);
+  BOOST_CHECK_EQUAL(nData, 1);
 
   BOOST_CHECK_EQUAL(dataSize, 14);
 
@@ -170,7 +171,7 @@
                         bind(&Fixture::onComplete, this, _1),
                         bind(&Fixture::onError, this, _1));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
 
   const uint8_t buffer[] = "Hello, world!";
 
@@ -179,11 +180,11 @@
   data->setContent(buffer, sizeof(buffer));
 
   face.receive(*data);
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
 
   BOOST_CHECK_EQUAL(nErrors, 1);
   BOOST_CHECK_EQUAL(lastError, static_cast<uint32_t>(SegmentFetcher::DATA_HAS_NO_SEGMENT));
-  BOOST_CHECK_EQUAL(nDatas, 0);
+  BOOST_CHECK_EQUAL(nData, 0);
 }
 
 BOOST_FIXTURE_TEST_CASE(SegmentValidationFailure, Fixture)
@@ -194,13 +195,13 @@
                         bind(&Fixture::onComplete, this, _1),
                         bind(&Fixture::onError, this, _1));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
   face.receive(*makeDataSegment("/hello/world/version0", 0, true));
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
 
   BOOST_CHECK_EQUAL(nErrors, 1);
   BOOST_CHECK_EQUAL(lastError, static_cast<uint32_t>(SegmentFetcher::SEGMENT_VALIDATION_FAIL));
-  BOOST_CHECK_EQUAL(nDatas, 0);
+  BOOST_CHECK_EQUAL(nData, 0);
 }
 
 BOOST_FIXTURE_TEST_CASE(Triple, Fixture)
@@ -211,19 +212,19 @@
                         bind(&Fixture::onComplete, this, _1),
                         bind(&Fixture::onError, this, _1));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
   face.receive(*makeDataSegment("/hello/world/version0", 0, false));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
   face.receive(*makeDataSegment("/hello/world/version0", 1, false));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
   face.receive(*makeDataSegment("/hello/world/version0", 2, true));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
 
   BOOST_CHECK_EQUAL(nErrors, 0);
-  BOOST_CHECK_EQUAL(nDatas, 1);
+  BOOST_CHECK_EQUAL(nData, 1);
 
   BOOST_CHECK_EQUAL(dataSize, 42);
 
@@ -260,22 +261,22 @@
                         bind(&Fixture::onComplete, this, _1),
                         bind(&Fixture::onError, this, _1));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
   face.receive(*makeDataSegment("/hello/world/version0", 1, false));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
   face.receive(*makeDataSegment("/hello/world/version0", 0, false));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
   face.receive(*makeDataSegment("/hello/world/version0", 1, false));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
   face.receive(*makeDataSegment("/hello/world/version0", 2, true));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
 
   BOOST_CHECK_EQUAL(nErrors, 0);
-  BOOST_CHECK_EQUAL(nDatas, 1);
+  BOOST_CHECK_EQUAL(nData, 1);
 
   BOOST_CHECK_EQUAL(dataSize, 42);
 
@@ -319,19 +320,19 @@
                         bind(&Fixture::onComplete, this, _1),
                         bind(&Fixture::onError, this, _1));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
 
   for (uint64_t i = 0; i < 400; i++) {
-    advanceClocks(time::milliseconds(1), 10);
+    advanceClocks(time::milliseconds(10));
     face.receive(*makeDataSegment("/hello/world/version0", i, false));
   }
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
   face.receive(*makeDataSegment("/hello/world/version0", 400, true));
 
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
 
   BOOST_CHECK_EQUAL(nErrors, 0);
-  BOOST_CHECK_EQUAL(nDatas, 1);
+  BOOST_CHECK_EQUAL(nData, 1);
 }
 
 BOOST_FIXTURE_TEST_CASE(DuplicateNack, Fixture)
@@ -340,7 +341,7 @@
                         make_shared<ValidatorNull>(),
                         bind(&Fixture::onComplete, this, _1),
                         bind(&Fixture::onError, this, _1));
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
 
   // receive nack for the original interest
   nackLastInterest(lp::NackReason::DUPLICATE);
@@ -360,7 +361,7 @@
                         make_shared<ValidatorNull>(),
                         bind(&Fixture::onComplete, this, _1),
                         bind(&Fixture::onError, this, _1));
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
 
   // receive nack for the original interest
   nackLastInterest(lp::NackReason::CONGESTION);
@@ -385,19 +386,19 @@
                         bind(&Fixture::onComplete, this, _1),
                         bind(&Fixture::onError, this, _1));
 
-  advanceClocks(time::milliseconds(1), 1000);
+  advanceClocks(time::milliseconds(1000));
 
   for (uint64_t segmentNo = 0; segmentNo <= 3; segmentNo++) {
     if (segmentNo == 1) {
       while (nNacks--) {
         nackLastInterest(lp::NackReason::CONGESTION);
-        advanceClocks(time::milliseconds(1), 10);
+        advanceClocks(time::milliseconds(10));
       }
     }
 
     auto data = makeDataSegment(interestName, segmentNo, segmentNo == 3);
     face.receive(*data);
-    advanceClocks(time::milliseconds(1), 10);
+    advanceClocks(time::milliseconds(10));
   }
 
   // Total number of sent interests should be 6: one interest for segment zero and segment one each,
@@ -419,17 +420,18 @@
                         make_shared<ValidatorNull>(),
                         bind(&Fixture::onComplete, this, _1),
                         bind(&Fixture::onError, this, _1));
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(time::milliseconds(10));
   nackLastInterest(lp::NackReason::DUPLICATE);
   face.receive(*makeDataSegment("/hello/world", 0, true));
 
   BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2);
   BOOST_CHECK_EQUAL(face.sentInterests[0].getName(), ndn::Name("ndn:/"));
   BOOST_CHECK_EQUAL(face.sentInterests[1].getName(), ndn::Name("ndn:/"));
-  BOOST_REQUIRE_EQUAL(nDatas, 1);
+  BOOST_REQUIRE_EQUAL(nData, 1);
 }
 
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() // TestSegmentFetcher
+BOOST_AUTO_TEST_SUITE_END() // Util
 
 } // namespace tests
 } // namespace util