tests: move integrated tests into unit tests

Change-Id: Ifed29e53091ca430582b1c2e7f3514e02d7c8d14
diff --git a/tests/unit-tests/test-logic.cpp b/tests/unit-tests/test-logic.cpp
new file mode 100644
index 0000000..53a6f57
--- /dev/null
+++ b/tests/unit-tests/test-logic.cpp
@@ -0,0 +1,344 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012-2014 University of California, Los Angeles
+ *
+ * This file is part of ChronoSync, synchronization library for distributed realtime
+ * applications for NDN.
+ *
+ * ChronoSync is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * ChronoSync 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * ChronoSync, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "logic.hpp"
+#include "../unit-test-time-fixture.hpp"
+#include <ndn-cxx/util/dummy-client-face.hpp>
+#include "boost-test.hpp"
+
+namespace chronosync {
+namespace test {
+
+using std::vector;
+using ndn::util::DummyClientFace;
+using ndn::util::makeDummyClientFace;
+
+class Handler
+{
+public:
+  Handler(DummyClientFace& face,
+          const Name& syncPrefix,
+          const Name& userPrefix)
+    : logic(face,
+            syncPrefix,
+            userPrefix,
+            bind(&Handler::onUpdate, this, _1))
+  {
+  }
+
+  void
+  onUpdate(const vector<MissingDataInfo>& v)
+  {
+    for (size_t i = 0; i < v.size(); i++) {
+      update(v[i].session, v[i].high, v[i].low);
+    }
+  }
+
+  void
+  update(const Name& p, const SeqNo& high, const SeqNo& low)
+  {
+    map[p] = high;
+  }
+
+  void
+  updateSeqNo(const SeqNo& seqNo)
+  {
+    logic.updateSeqNo(seqNo);
+  }
+
+  Logic logic;
+  std::map<Name, SeqNo> map;
+};
+
+class LogicFixture : public ndn::tests::UnitTestTimeFixture
+{
+public:
+  LogicFixture()
+    : syncPrefix("/ndn/broadcast/sync")
+  {
+    syncPrefix.appendVersion();
+    userPrefix[0] = Name("/user0");
+    userPrefix[1] = Name("/user1");
+    userPrefix[2] = Name("/user2");
+
+    faces[0] = makeDummyClientFace(ref(io), {true, true});
+    faces[1] = makeDummyClientFace(ref(io), {true, true});
+    faces[2] = makeDummyClientFace(ref(io), {true, true});
+
+    for (int i = 0; i < 3; i++) {
+      readInterestOffset[i] = 0;
+      readDataOffset[i] = 0;
+    }
+  }
+
+  void
+  passPacket()
+  {
+    for (int i = 0; i < 3; i++)
+      checkFace(i);
+  }
+
+  void
+  checkFace(int sender)
+  {
+    while (faces[sender]->sentInterests.size() > readInterestOffset[sender]) {
+      for (int i = 0; i < 3; i++) {
+        if (sender != i)
+          faces[i]->receive(faces[sender]->sentInterests[readInterestOffset[sender]]);
+      }
+      readInterestOffset[sender]++;
+    }
+    while (faces[sender]->sentDatas.size() > readDataOffset[sender]) {
+      for (int i = 0; i < 3; i++) {
+        if (sender != i)
+          faces[i]->receive(faces[sender]->sentDatas[readDataOffset[sender]]);
+      }
+      readDataOffset[sender]++;
+    }
+  }
+
+  Name syncPrefix;
+  Name userPrefix[3];
+
+  shared_ptr<DummyClientFace> faces[3];
+  shared_ptr<Handler> handler[3];
+
+  size_t readInterestOffset[3];
+  size_t readDataOffset[3];
+};
+
+BOOST_FIXTURE_TEST_SUITE(LogicTests, LogicFixture)
+
+void
+onUpdate(const vector<MissingDataInfo>& v)
+{
+}
+
+BOOST_AUTO_TEST_CASE(Constructor)
+{
+  Name syncPrefix("/ndn/broadcast/sync");
+  Name userPrefix("/user");
+  shared_ptr<DummyClientFace> face = makeDummyClientFace(ref(io), {true, true});
+  BOOST_REQUIRE_NO_THROW(Logic(ref(*face), syncPrefix, userPrefix,
+                               bind(onUpdate, _1)));
+}
+
+BOOST_AUTO_TEST_CASE(TwoBasic)
+{
+  handler[0] = make_shared<Handler>(ref(*faces[0]), syncPrefix, userPrefix[0]);
+  advanceClocks(ndn::time::milliseconds(10), 10);
+
+  handler[1] = make_shared<Handler>(ref(*faces[1]), syncPrefix, userPrefix[1]);
+  advanceClocks(ndn::time::milliseconds(10), 10);
+
+  handler[0]->updateSeqNo(1);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1);
+  advanceClocks(ndn::time::milliseconds(10), 10);
+
+  handler[0]->updateSeqNo(2);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 2);
+  advanceClocks(ndn::time::milliseconds(10), 10);
+
+  handler[1]->updateSeqNo(2);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 2);
+}
+
+BOOST_AUTO_TEST_CASE(ThreeBasic)
+{
+  handler[0] = make_shared<Handler>(ref(*faces[0]), syncPrefix, userPrefix[0]);
+  advanceClocks(ndn::time::milliseconds(10), 10);
+
+  handler[1] = make_shared<Handler>(ref(*faces[1]), syncPrefix, userPrefix[1]);
+  advanceClocks(ndn::time::milliseconds(10), 10);
+
+  handler[2] = make_shared<Handler>(ref(*faces[2]), syncPrefix, userPrefix[2]);
+  advanceClocks(ndn::time::milliseconds(10), 20);
+
+  handler[0]->updateSeqNo(1);
+
+  for (int i = 0; i < 70; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1);
+  BOOST_CHECK_EQUAL(handler[2]->map[handler[0]->logic.getSessionName()], 1);
+
+  handler[1]->updateSeqNo(2);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 2);
+  BOOST_CHECK_EQUAL(handler[2]->map[handler[1]->logic.getSessionName()], 2);
+
+  handler[2]->updateSeqNo(4);
+
+  for (int i = 0; i < 100; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[0]->map[handler[2]->logic.getSessionName()], 4);
+  BOOST_CHECK_EQUAL(handler[1]->map[handler[2]->logic.getSessionName()], 4);
+}
+
+BOOST_AUTO_TEST_CASE(ResetRecover)
+{
+  handler[0] = make_shared<Handler>(ref(*faces[0]), syncPrefix, userPrefix[0]);
+  advanceClocks(ndn::time::milliseconds(10), 10);
+
+  handler[1] = make_shared<Handler>(ref(*faces[1]), syncPrefix, userPrefix[1]);
+  advanceClocks(ndn::time::milliseconds(10), 30);
+
+  handler[0]->updateSeqNo(1);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1);
+
+  handler[1]->updateSeqNo(2);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 2);
+
+  advanceClocks(ndn::time::milliseconds(10), 10);
+  handler[2] = make_shared<Handler>(ref(*faces[2]), syncPrefix, userPrefix[2]);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1);
+  BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 2);
+
+  handler[2]->updateSeqNo(4);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[1]->map[handler[2]->logic.getSessionName()], 4);
+  BOOST_CHECK_EQUAL(handler[0]->map[handler[2]->logic.getSessionName()], 4);
+}
+
+BOOST_AUTO_TEST_CASE(RecoverConflict)
+{
+  handler[0] = make_shared<Handler>(ref(*faces[0]), syncPrefix, userPrefix[0]);
+  advanceClocks(ndn::time::milliseconds(10), 10);
+
+  handler[1] = make_shared<Handler>(ref(*faces[1]), syncPrefix, userPrefix[1]);
+  advanceClocks(ndn::time::milliseconds(10), 10);
+
+  handler[2] = make_shared<Handler>(ref(*faces[2]), syncPrefix, userPrefix[2]);
+  advanceClocks(ndn::time::milliseconds(10), 30);
+
+  handler[0]->updateSeqNo(1);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1);
+  BOOST_CHECK_EQUAL(handler[2]->map[handler[0]->logic.getSessionName()], 1);
+
+  handler[1]->updateSeqNo(2);
+  handler[2]->updateSeqNo(4);
+
+  for (int i = 0; i < 75; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 2);
+  BOOST_CHECK_EQUAL(handler[0]->map[handler[2]->logic.getSessionName()], 4);
+  BOOST_CHECK_EQUAL(handler[1]->map[handler[2]->logic.getSessionName()], 4);
+  BOOST_CHECK_EQUAL(handler[2]->map[handler[1]->logic.getSessionName()], 2);
+}
+
+BOOST_AUTO_TEST_CASE(MultipleUserUnderOneLogic)
+{
+  handler[0] = make_shared<Handler>(ref(*faces[0]), syncPrefix, userPrefix[0]);
+  advanceClocks(ndn::time::milliseconds(10), 10);
+
+  handler[1] = make_shared<Handler>(ref(*faces[1]), syncPrefix, userPrefix[2]);
+  advanceClocks(ndn::time::milliseconds(10), 10);
+
+  handler[0]->logic.addUserNode(userPrefix[1]);
+
+  for (int i = 0; i < 20; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+
+  handler[0]->updateSeqNo(1);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1);
+
+  handler[0]->logic.updateSeqNo(2, userPrefix[1]);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName(userPrefix[1])], 2);
+
+  handler[1]->updateSeqNo(4);
+
+  for (int i = 0; i < 50; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 4);
+
+  handler[0]->logic.removeUserNode(userPrefix[0]);
+
+  for (int i = 0; i < 100; i++) {
+    advanceClocks(ndn::time::milliseconds(2), 10);
+    passPacket();
+  }
+  BOOST_CHECK_EQUAL(handler[1]->logic.getSessionNames().size(), 2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace chronosync