Fix logic

Change-Id: I7bfb72e8bb245fab3e9a9d575abc7217bbae86d0
diff --git a/tests/integrated-tests/test-data-fetch-and-publish.cpp.outdated b/tests/integrated-tests/test-data-fetch-and-publish.cpp.outdated
new file mode 100644
index 0000000..583717c
--- /dev/null
+++ b/tests/integrated-tests/test-data-fetch-and-publish.cpp.outdated
@@ -0,0 +1,108 @@
+/* -*- 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 <boost/test/unit_test.hpp>
+#include <boost/test/output_test_stream.hpp>
+#include <map>
+using boost::test_tools::output_test_stream;
+
+#include <boost/make_shared.hpp>
+
+#include "sync-ccnx-wrapper.h"
+#include "sync-app-data-fetch.h"
+#include "sync-app-data-publish.h"
+
+using namespace Sync;
+using namespace std;
+using namespace boost;
+
+class TestStructApp {
+public:
+  map<string, string> data;
+  void set(string str1, string str2) {
+    data.insert(make_pair(str1, str2));
+  }
+
+  void erase(string str1, string str2) {
+    data.erase(str1);
+  }
+
+  string toString(){
+    map<string, string>::iterator it = data.begin();
+    string str = "";
+    for (; it != data.end(); ++it){
+      str += "<";
+      str += it->first;
+      str += "|";
+      str += it->second;
+      str += ">";
+    }
+    return str;
+  }
+
+};
+
+BOOST_AUTO_TEST_CASE (AppDataPublishAndFetchTest)
+{
+  TestStructApp foo;
+  TestStructApp bar;
+
+  string interest = "/april/fool";
+  string seq[5] = {"0", "1", "2", "3", "4" };
+  string str[5] = {"panda", "express", "tastes", "so", "good"};
+
+  for (int i = 0; i < 5; i++) {
+    foo.set(interest + "/" + "0/" + seq[i], str[i]);
+  }
+
+  boost::function<void (string, string)> setFunc =
+    bind(&TestStructApp::set, &bar, _1, _2);
+
+  shared_ptr<CcnxWrapper> handle(new CcnxWrapper());
+
+  AppDataFetch fetcher(handle, setFunc);
+  AppDataPublish publisher(handle);
+
+  for (int i = 1; i <= 5; i++) {
+    publisher.publishData(interest, 0, str[i - 1], 5);
+  }
+
+  BOOST_CHECK_EQUAL(publisher.getNextSeq(interest, 0), 5);
+  BOOST_CHECK_EQUAL(publisher.getRecentData(interest, 0), str[4]);
+
+  fetcher.onUpdate (interest, SeqNo (0,4), SeqNo (0,-1));
+  // give time for ccnd to react
+  sleep(1);
+  BOOST_CHECK_EQUAL(foo.toString(), bar.toString());
+
+
+  boost::function<void (string, string)> eraseFunc =
+    bind(&TestStructApp::erase, &bar, _1, _2);
+  fetcher.setDataCallback(eraseFunc);
+
+  fetcher.onUpdate (interest, SeqNo (0,4), SeqNo (0,-1));
+  // give time for ccnd to react
+  sleep(1);
+  TestStructApp poo;
+
+  BOOST_CHECK_EQUAL(poo.toString(), bar.toString());
+
+}
+*/
diff --git a/tests/integrated-tests/test-logic.cpp b/tests/integrated-tests/test-logic.cpp
new file mode 100644
index 0000000..088b8fb
--- /dev/null
+++ b/tests/integrated-tests/test-logic.cpp
@@ -0,0 +1,307 @@
+/* -*- 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 "boost-test.hpp"
+
+namespace chronosync {
+namespace test {
+
+using std::vector;
+
+class Handler
+{
+public:
+  Handler(ndn::Face& 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);
+  }
+
+  void
+  check(const Name& sessionName, const SeqNo& seqNo)
+  {
+    BOOST_CHECK_EQUAL(map[sessionName], seqNo);
+  }
+
+  Logic logic;
+  std::map<Name, SeqNo> map;
+};
+
+class LogicFixture
+{
+public:
+  LogicFixture()
+    : syncPrefix("/ndn/broadcast/sync")
+    , scheduler(io)
+  {
+    syncPrefix.appendVersion();
+    userPrefix[0] = Name("/user0");
+    userPrefix[1] = Name("/user1");
+    userPrefix[2] = Name("/user2");
+
+    faces[0] = make_shared<ndn::Face>(ref(io));
+    faces[1] = make_shared<ndn::Face>(ref(io));
+    faces[2] = make_shared<ndn::Face>(ref(io));
+  }
+
+  void
+  createHandler(size_t idx)
+  {
+    handler[idx] = make_shared<Handler>(ref(*faces[idx]), syncPrefix, userPrefix[idx]);
+  }
+
+  void
+  updateSeqNo(size_t idx, const SeqNo& seqNo)
+  {
+    handler[idx]->updateSeqNo(seqNo);
+  }
+
+  void
+  checkSeqNo(size_t sIdx, size_t dIdx, const SeqNo& seqNo)
+  {
+    handler[sIdx]->check(handler[dIdx]->logic.getSessionName(), seqNo);
+  }
+
+  void
+  terminate()
+  {
+    io.stop();
+  }
+
+  Name syncPrefix;
+  Name userPrefix[3];
+
+  boost::asio::io_service io;
+  shared_ptr<ndn::Face> faces[3];
+  ndn::Scheduler scheduler;
+  shared_ptr<Handler> handler[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");
+  ndn::Face face;
+  BOOST_REQUIRE_NO_THROW(Logic(face, syncPrefix, userPrefix,
+                               bind(onUpdate, _1)));
+}
+
+BOOST_AUTO_TEST_CASE(TwoBasic)
+{
+  scheduler.scheduleEvent(ndn::time::milliseconds(100),
+                          bind(&LogicFixture::createHandler, this, 0));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(200),
+                          bind(&LogicFixture::createHandler, this, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(300),
+                          bind(&LogicFixture::updateSeqNo, this, 0, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1000),
+                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1100),
+                          bind(&LogicFixture::updateSeqNo, this, 0, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1800),
+                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1900),
+                          bind(&LogicFixture::updateSeqNo, this, 1, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2600),
+                          bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2800),
+                          bind(&LogicFixture::terminate, this));
+
+  io.run();
+}
+
+BOOST_AUTO_TEST_CASE(ThreeBasic)
+{
+  scheduler.scheduleEvent(ndn::time::milliseconds(100),
+                          bind(&LogicFixture::createHandler, this, 0));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(200),
+                          bind(&LogicFixture::createHandler, this, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(300),
+                          bind(&LogicFixture::createHandler, this, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(500),
+                          bind(&LogicFixture::updateSeqNo, this, 0, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1400),
+                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1450),
+                          bind(&LogicFixture::checkSeqNo, this, 2, 0, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1500),
+                          bind(&LogicFixture::updateSeqNo, this, 1, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2400),
+                          bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2450),
+                          bind(&LogicFixture::checkSeqNo, this, 2, 1, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2500),
+                          bind(&LogicFixture::updateSeqNo, this, 2, 4));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(4400),
+                          bind(&LogicFixture::checkSeqNo, this, 0, 2, 4));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(4450),
+                          bind(&LogicFixture::checkSeqNo, this, 1, 2, 4));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(4500),
+                          bind(&LogicFixture::terminate, this));
+
+  io.run();
+}
+
+BOOST_AUTO_TEST_CASE(ResetRecover)
+{
+  scheduler.scheduleEvent(ndn::time::milliseconds(100),
+                          bind(&LogicFixture::createHandler, this, 0));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(200),
+                          bind(&LogicFixture::createHandler, this, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(500),
+                          bind(&LogicFixture::updateSeqNo, this, 0, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1400),
+                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1500),
+                          bind(&LogicFixture::updateSeqNo, this, 1, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2400),
+                          bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2500),
+                          bind(&LogicFixture::createHandler, this, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(3000),
+                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(3050),
+                          bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(3100),
+                          bind(&LogicFixture::updateSeqNo, this, 2, 4));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(4000),
+                          bind(&LogicFixture::checkSeqNo, this, 1, 2, 4));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(4050),
+                          bind(&LogicFixture::checkSeqNo, this, 0, 2, 4));
+
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(4500),
+                          bind(&LogicFixture::terminate, this));
+
+  io.run();
+}
+
+BOOST_AUTO_TEST_CASE(RecoverConflict)
+{
+  scheduler.scheduleEvent(ndn::time::milliseconds(0),
+                          bind(&LogicFixture::createHandler, this, 0));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(50),
+                          bind(&LogicFixture::createHandler, this, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(100),
+                          bind(&LogicFixture::createHandler, this, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(500),
+                          bind(&LogicFixture::updateSeqNo, this, 0, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1400),
+                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1400),
+                          bind(&LogicFixture::checkSeqNo, this, 2, 0, 1));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1500),
+                          bind(&LogicFixture::updateSeqNo, this, 1, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1500),
+                          bind(&LogicFixture::updateSeqNo, this, 2, 4));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2400),
+                          bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2450),
+                          bind(&LogicFixture::checkSeqNo, this, 0, 2, 4));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2500),
+                          bind(&LogicFixture::checkSeqNo, this, 1, 2, 4));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2550),
+                          bind(&LogicFixture::checkSeqNo, this, 2, 1, 2));
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(4500),
+                          bind(&LogicFixture::terminate, this));
+
+  io.run();
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace chronosync
diff --git a/tests/integrated-tests/test-socket.cpp.outdated b/tests/integrated-tests/test-socket.cpp.outdated
new file mode 100644
index 0000000..d04ded9
--- /dev/null
+++ b/tests/integrated-tests/test-socket.cpp.outdated
@@ -0,0 +1,619 @@
+/* -*- 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 <boost/test/unit_test.hpp>
+#include <boost/test/output_test_stream.hpp>
+using boost::test_tools::output_test_stream;
+
+#include <boost/make_shared.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+#include "sync-logging.h"
+#include "sync-socket.h"
+#include "sync-validator.h"
+#include <ndn-cxx/security/validator-null.hpp>
+
+extern "C" {
+#include <unistd.h>
+}
+
+using namespace Sync;
+using namespace std;
+using namespace boost;
+
+INIT_LOGGER ("Test.AppSocket");
+
+#define PRINT
+// std::cout << "Line: " << __LINE__ << std::endl;
+
+class TestSocketApp {
+public:
+  TestSocketApp()
+    : sum(0)
+  {}
+
+  map<ndn::Name, string> data;
+  void set(const ndn::shared_ptr<const ndn::Data>& dataPacket) {
+    // _LOG_FUNCTION (this << ", " << str1);
+    ndn::Name dataName(dataPacket->getName());
+    string str2(reinterpret_cast<const char*>(dataPacket->getContent().value()), dataPacket->getContent().value_size());
+    data.insert(make_pair(dataName, str2));
+    // cout << str1 << ", " << str2 << endl;
+  }
+
+  void set(ndn::Name name, const char * buf, int len) {
+    string str2(buf, len);
+    data.insert(make_pair(name, str2));
+  }
+
+  void setNum(const ndn::shared_ptr<const ndn::Data>& data) {
+    int n = data->getContent().value_size() / 4;
+    uint32_t *numbers = new uint32_t [n];
+    memcpy(numbers, data->getContent().value(), data->getContent().value_size());
+    for (int i = 0; i < n; i++) {
+      sum += numbers[i];
+    }
+    delete numbers;
+
+  }
+
+  void setNum(ndn::Name name, const char * buf, int len) {
+    int n = len / 4;
+    int *numbers = new int [n];
+    memcpy(numbers, buf, len);
+    for (int i = 0; i < n; i++) {
+      sum += numbers[i];
+    }
+    delete numbers;
+  }
+
+  uint32_t sum;
+
+  void fetchAll(const vector<MissingDataInfo> &v, SyncSocket *socket) {
+    int n = v.size();
+
+    PRINT
+
+    for (int i = 0; i < n; i++) {
+      for(SeqNo s = v[i].low; s <= v[i].high; ++s) {
+        //PRINT
+        socket->fetchData(v[i].prefix, s, bind(&TestSocketApp::set, this, _1));
+      }
+    }
+  }
+
+  void fetchNumbers(const vector<MissingDataInfo> &v, SyncSocket *socket) {
+    int n = v.size();
+
+    PRINT
+
+    // std::cout << "In fetchNumbers. size of v is:  " << n << std::endl;
+    for (int i = 0; i < n; i++) {
+      // std::cout << "In fetchNumbers. v[i].low is (" <<v[i].low.getSession() <<", " << v[i].low.getSeq() << ") v[i].high is ("<<v[i].high.getSession() <<", " <<v[i].high.getSeq()<<")" << std::endl;
+      for(SeqNo s = v[i].low; s <= v[i].high; ++s) {
+        PRINT
+        socket->fetchData(v[i].prefix, s, bind(&TestSocketApp::setNum, this, _1));
+      }
+    }
+  }
+
+  void pass(const string &prefix) {
+  }
+
+  string toString(){
+    map<ndn::Name, string>::iterator it = data.begin();
+    string str = "\n";
+    for (; it != data.end(); ++it){
+      str += "<";
+      str += it->first.toUri();
+      str += "|";
+      str += it->second;
+      str += ">";
+      str += "\n";
+    }
+
+    return str;
+  }
+
+};
+
+class TestSet1{
+public:
+  TestSet1(ndn::shared_ptr<boost::asio::io_service> ioService)
+    : m_face1(new ndn::Face(*ioService))
+    , m_face2(new ndn::Face(*ioService))
+    , m_face3(new ndn::Face(*ioService))
+    , m_name1("/irl.cs.ucla.edu/" + boost::lexical_cast<std::string>(ndn::time::toUnixTimestamp(ndn::time::system_clock::now()).count()))
+    , m_name2("/yakshi.org/" + boost::lexical_cast<std::string>(ndn::time::toUnixTimestamp(ndn::time::system_clock::now()).count()))
+    , m_name3("/google.com/" + boost::lexical_cast<std::string>(ndn::time::toUnixTimestamp(ndn::time::system_clock::now()).count()))
+  {
+    m_id1 = m_keyChain.getCertificate(m_keyChain.createIdentity(m_name1));
+    m_id2 = m_keyChain.getCertificate(m_keyChain.createIdentity(m_name2));
+    m_id3 = m_keyChain.getCertificate(m_keyChain.createIdentity(m_name3));
+
+    m_rule = ndn::make_shared<ndn::SecRuleRelative>("^(<>*)<><>$",
+                                                    "^(<>*)<><KEY><ksk-.*><ID-CERT>$",
+                                                    "==", "\\1", "\\1", true);
+  }
+
+  void
+  createSyncSocket1()
+  {
+    _LOG_DEBUG ("s1");
+
+    m_s1 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/let/us/sync",
+                      "/irl.cs.ucla.edu",
+                      0,
+                      false,
+                      "/",
+                      m_face1,
+                      *m_id1,
+                      m_rule,
+                      bind(&TestSocketApp::fetchAll, &m_a1, _1, _2),
+                      bind(&TestSocketApp::pass, &m_a1, _1)));
+
+    m_s1->addParticipant(*m_id2);
+  }
+
+  void
+  createSyncSocket2()
+  {
+    _LOG_DEBUG ("s2");
+
+    m_s2 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/let/us/sync",
+                      "/yakshi.org",
+                      0,
+                      false,
+                      "/",
+                      m_face2,
+                      *m_id2,
+                      m_rule,
+                      bind(&TestSocketApp::fetchAll, &m_a2, _1, _2),
+                      bind(&TestSocketApp::pass, &m_a2, _1)));
+
+    m_s2->addParticipant(*m_id1);
+    m_s2->addParticipant(*m_id3);
+  }
+
+  void
+  createSyncSocket3()
+  {
+    _LOG_DEBUG ("s3");
+
+    m_s3 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/let/us/sync",
+                      "/google.com",
+                      0,
+                      false,
+                      "/",
+                      m_face3,
+                      *m_id3,
+                      m_rule,
+                      bind(&TestSocketApp::fetchAll, &m_a3, _1, _2),
+                      bind(&TestSocketApp::pass, &m_a3, _1)));
+
+    m_s3->addParticipant(*m_id2);
+  }
+
+  void
+  publishSocket1(string data)
+  {
+    _LOG_DEBUG ("s1 publish");
+    m_s1->publishData (reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), 1000);
+  }
+
+  void
+  publishSocket2(string data)
+  {
+    _LOG_DEBUG ("s2 publish");
+    m_s2->publishData (reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), 1000);
+  }
+
+  void
+  publishSocket3(string data)
+  {
+    _LOG_DEBUG ("s3 publish");
+    m_s3->publishData (reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), 1000);
+  }
+
+  void
+  setSocket1(string suffix, string data)
+  {
+    _LOG_DEBUG ("a1 set");
+    ndn::Name name("/irl.cs.ucla.edu");
+    name.append(suffix);
+    m_a1.set (name, data.c_str(), data.size());
+  }
+
+  void
+  setSocket2(string suffix, string data)
+  {
+    _LOG_DEBUG ("a2 set");
+    ndn::Name name("/yakshi.org");
+    name.append(suffix);
+    m_a2.set (name, data.c_str(), data.size());
+  }
+
+  void
+  setSocket3(string suffix, string data)
+  {
+    _LOG_DEBUG ("a3 set");
+    ndn::Name name("/google.com");
+    name.append(suffix);
+    m_a3.set (name, data.c_str(), data.size());
+  }
+
+  void
+  check(int round)
+  {
+    BOOST_CHECK_EQUAL(m_a1.toString(), m_a2.toString());
+    BOOST_CHECK_EQUAL(m_a2.toString(), m_a3.toString());
+  }
+
+  void
+  done(ndn::shared_ptr<boost::asio::io_service> ioService)
+  {
+    m_s1.reset();
+    m_s2.reset();
+    m_s3.reset();
+
+    m_keyChain.deleteIdentity(m_name1);
+    m_keyChain.deleteIdentity(m_name2);
+    m_keyChain.deleteIdentity(m_name3);
+
+    ioService->stop();
+  }
+
+  ndn::KeyChain m_keyChain;
+  ndn::shared_ptr<ndn::SecRuleRelative> m_rule;
+
+  ndn::shared_ptr<ndn::Face> m_face1, m_face2, m_face3;
+  ndn::Name m_name1, m_name2, m_name3;
+  TestSocketApp m_a1, m_a2, m_a3;
+  ndn::shared_ptr<ndn::IdentityCertificate> m_id1, m_id2, m_id3;
+  ndn::shared_ptr<SyncSocket> m_s1, m_s2, m_s3;
+};
+
+class TestSet2{
+public:
+  TestSet2(ndn::shared_ptr<boost::asio::io_service> ioService)
+    : m_face1(new ndn::Face(*ioService))
+    , m_face2(new ndn::Face(*ioService))
+    , m_name1("/xiaonei.com/" + boost::lexical_cast<std::string>(ndn::time::toUnixTimestamp(ndn::time::system_clock::now()).count()))
+    , m_name2("/mitbbs.com/" + boost::lexical_cast<std::string>(ndn::time::toUnixTimestamp(ndn::time::system_clock::now()).count()))
+  {
+    m_id1 = m_keyChain.getCertificate(m_keyChain.createIdentity(m_name1));
+    m_id2 = m_keyChain.getCertificate(m_keyChain.createIdentity(m_name2));
+
+    m_rule = ndn::make_shared<ndn::SecRuleRelative>("^(<>*)<><>$",
+                                                    "^(<>*)<><KEY><ksk-.*><ID-CERT>$",
+                                                    "==", "\\1", "\\1", true);
+  }
+
+  void
+  createSyncSocket1()
+  {
+    _LOG_DEBUG ("s1");
+
+    m_s1 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/this/is/the/prefix",
+                      "/xiaonei.com",
+                      0,
+                      false,
+                      "/",
+                      m_face1,
+                      *m_id1,
+                      m_rule,
+                      bind(&TestSocketApp::fetchNumbers, &m_a1, _1, _2),
+                      bind(&TestSocketApp::pass, &m_a1, _1)));
+
+    m_s1->addParticipant(*m_id2);
+  }
+
+  void
+  createSyncSocket2()
+  {
+    _LOG_DEBUG ("s2");
+
+    m_s2 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/this/is/the/prefix",
+                      "/mitbbs.com",
+                      0,
+                      false,
+                      "/",
+                      m_face2,
+                      *m_id2,
+                      m_rule,
+                      bind(&TestSocketApp::fetchNumbers, &m_a2, _1, _2),
+                      bind(&TestSocketApp::pass, &m_a2, _1)));
+
+    m_s2->addParticipant(*m_id1);
+  }
+
+  void
+  publishSocket1(string data)
+  {
+    _LOG_DEBUG ("s1 publish");
+    m_s1->publishData (reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), 1000);
+  }
+
+  void
+  publishSocket2(string data)
+  {
+    _LOG_DEBUG ("s2 publish");
+    m_s2->publishData (reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), 1000);
+  }
+
+  void
+  setSocket1(const char* ptr, size_t size)
+  {
+    _LOG_DEBUG ("a1 setNum");
+    m_a1.setNum ("/xiaonei.com", ptr, size);
+  }
+
+  void
+  setSocket2(const char* ptr, size_t size)
+  {
+    _LOG_DEBUG ("a2 setNum");
+    m_a2.setNum ("/mitbbs.com", ptr, size);
+  }
+
+  void
+  check(int num)
+  {
+    _LOG_DEBUG ("codnum " << num);
+    _LOG_DEBUG ("a1 sum " << m_a1.sum);
+    _LOG_DEBUG ("a2 sum " << m_a2.sum);
+
+    BOOST_CHECK(m_a1.sum == m_a2.sum && m_a1.sum == num);
+  }
+
+  void
+  done(ndn::shared_ptr<boost::asio::io_service> ioService)
+  {
+    m_s1.reset();
+    m_s2.reset();
+
+    m_keyChain.deleteIdentity(m_name1);
+    m_keyChain.deleteIdentity(m_name2);
+
+    ioService->stop();
+  }
+
+  ndn::KeyChain m_keyChain;
+  ndn::shared_ptr<ndn::SecRuleRelative> m_rule;
+
+  TestSocketApp m_a1, m_a2;
+  ndn::shared_ptr<ndn::IdentityCertificate> m_id1, m_id2;
+  ndn::shared_ptr<ndn::Face> m_face1, m_face2;
+  ndn::Name m_name1, m_name2;
+  ndn::shared_ptr<SyncSocket> m_s1, m_s2;
+};
+
+
+
+class TestSet3{
+public:
+  TestSet3(ndn::shared_ptr<boost::asio::io_service> ioService)
+    : m_face1(new ndn::Face(*ioService))
+    , m_face2(new ndn::Face(*ioService))
+    , m_name1("/xiaonei.com/" + boost::lexical_cast<std::string>(ndn::time::toUnixTimestamp(ndn::time::system_clock::now()).count()))
+    , m_name2("/mitbbs.com/" + boost::lexical_cast<std::string>(ndn::time::toUnixTimestamp(ndn::time::system_clock::now()).count()))
+  {
+    m_id1 = m_keyChain.getCertificate(m_keyChain.createIdentity(m_name1));
+    m_id2 = m_keyChain.getCertificate(m_keyChain.createIdentity(m_name2));
+
+    m_rule = ndn::make_shared<ndn::SecRuleRelative>("^(<>*)<><>$",
+                                                    "^(<>*)<><KEY><ksk-.*><ID-CERT>$",
+                                                    "==", "\\1", "\\1", true);
+  }
+
+  void
+  createSyncSocket1()
+  {
+    _LOG_DEBUG ("s1");
+
+    m_s1 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/this/is/the/prefix",
+                      "/xiaonei.com",
+                      1,
+                      true,
+                      "/abc",
+                      m_face1,
+                      *m_id1,
+                      m_rule,
+                      bind(&TestSocketApp::fetchNumbers, &m_a1, _1, _2),
+                      bind(&TestSocketApp::pass, &m_a1, _1)));
+
+    m_s1->addParticipant(*m_id2);
+  }
+
+  void
+  createSyncSocket2()
+  {
+    _LOG_DEBUG ("s2");
+
+    m_s2 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/this/is/the/prefix",
+                      "/mitbbs.com",
+                      1,
+                      false,
+                      "/",
+                      m_face2,
+                      *m_id2,
+                      m_rule,
+                      bind(&TestSocketApp::fetchNumbers, &m_a2, _1, _2),
+                      bind(&TestSocketApp::pass, &m_a2, _1)));
+
+    m_s2->addParticipant(*m_id1);
+  }
+
+  void
+  publishSocket1(string data)
+  {
+    _LOG_DEBUG ("s1 publish");
+    m_s1->publishData (reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), 1000);
+  }
+
+  void
+  publishSocket2(string data)
+  {
+    _LOG_DEBUG ("s2 publish");
+    m_s2->publishData (reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), 1000);
+  }
+
+  void
+  setSocket1(const char* ptr, size_t size)
+  {
+    _LOG_DEBUG ("a1 setNum");
+    m_a1.setNum ("/xiaonei.com", ptr, size);
+  }
+
+  void
+  setSocket2(const char* ptr, size_t size)
+  {
+    _LOG_DEBUG ("a2 setNum");
+    m_a2.setNum ("/mitbbs.com", ptr, size);
+  }
+
+  void
+  check(int num)
+  {
+    _LOG_DEBUG ("codnum " << num);
+    _LOG_DEBUG ("a1 sum " << m_a1.sum);
+    _LOG_DEBUG ("a2 sum " << m_a2.sum);
+
+    BOOST_CHECK(m_a1.sum == m_a2.sum && m_a1.sum == num);
+  }
+
+  void
+  done(ndn::shared_ptr<boost::asio::io_service> ioService)
+  {
+    m_s1.reset();
+    m_s2.reset();
+
+    m_keyChain.deleteIdentity(m_name1);
+    m_keyChain.deleteIdentity(m_name2);
+
+    ioService->stop();
+  }
+
+  ndn::KeyChain m_keyChain;
+  ndn::shared_ptr<ndn::SecRuleRelative> m_rule;
+
+  TestSocketApp m_a1, m_a2;
+  ndn::shared_ptr<ndn::IdentityCertificate> m_id1, m_id2;
+  ndn::shared_ptr<ndn::Face> m_face1, m_face2;
+  ndn::Name m_name1, m_name2;
+  ndn::shared_ptr<SyncSocket> m_s1, m_s2;
+};
+
+BOOST_AUTO_TEST_CASE (AppSocketTest1)
+{
+  INIT_LOGGERS ();
+
+  ndn::shared_ptr<boost::asio::io_service> ioService = ndn::make_shared<boost::asio::io_service>();
+  ndn::Scheduler scheduler(*ioService);
+  TestSet1 testSet1(ioService);
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(0), ndn::bind(&TestSet1::createSyncSocket1, &testSet1));
+  scheduler.scheduleEvent(ndn::time::milliseconds(50), ndn::bind(&TestSet1::createSyncSocket2, &testSet1));
+  scheduler.scheduleEvent(ndn::time::milliseconds(100), ndn::bind(&TestSet1::createSyncSocket3, &testSet1));
+  string data0 = "Very funny Scotty, now beam down my clothes";
+  scheduler.scheduleEvent(ndn::time::milliseconds(150), ndn::bind(&TestSet1::publishSocket1, &testSet1, data0));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1150), ndn::bind(&TestSet1::setSocket1, &testSet1, "/0/1", data0));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1160), ndn::bind(&TestSet1::check, &testSet1, 1));
+  string data1 = "Yes, give me that ketchup";
+  string data2 = "Don't look conspicuous, it draws fire";
+  scheduler.scheduleEvent(ndn::time::milliseconds(1170), ndn::bind(&TestSet1::publishSocket1, &testSet1, data1));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1180), ndn::bind(&TestSet1::publishSocket1, &testSet1, data2));
+  scheduler.scheduleEvent(ndn::time::milliseconds(2150), ndn::bind(&TestSet1::setSocket1, &testSet1, "/0/2", data1));
+  scheduler.scheduleEvent(ndn::time::milliseconds(2160), ndn::bind(&TestSet1::setSocket1, &testSet1, "/0/3", data2));
+  scheduler.scheduleEvent(ndn::time::milliseconds(2170), ndn::bind(&TestSet1::check, &testSet1, 2));
+  string data3 = "You surf the Internet, I surf the real world";
+  string data4 = "I got a fortune cookie once that said 'You like Chinese food'";
+  string data5 = "Real men wear pink. Why? Because their wives make them";
+  scheduler.scheduleEvent(ndn::time::milliseconds(3180), ndn::bind(&TestSet1::publishSocket3, &testSet1, data3));
+  scheduler.scheduleEvent(ndn::time::milliseconds(3200), ndn::bind(&TestSet1::publishSocket2, &testSet1, data4));
+  scheduler.scheduleEvent(ndn::time::milliseconds(3210), ndn::bind(&TestSet1::publishSocket2, &testSet1, data5));
+  scheduler.scheduleEvent(ndn::time::milliseconds(4710), ndn::bind(&TestSet1::setSocket3, &testSet1, "/0/1", data3));
+  scheduler.scheduleEvent(ndn::time::milliseconds(4720), ndn::bind(&TestSet1::setSocket2, &testSet1, "/0/2", data4));
+  scheduler.scheduleEvent(ndn::time::milliseconds(4730), ndn::bind(&TestSet1::setSocket2, &testSet1, "/0/3", data5));
+  scheduler.scheduleEvent(ndn::time::milliseconds(4800), ndn::bind(&TestSet1::check, &testSet1, 3));
+  // not sure weither this is simultanous data generation from multiple sources
+  _LOG_DEBUG ("Simultaneous publishing");
+  string data6 = "Shakespeare says: 'Prose before hos.'";
+  string data7 = "Pick good people, talent never wears out";
+  scheduler.scheduleEvent(ndn::time::milliseconds(5500), ndn::bind(&TestSet1::publishSocket1, &testSet1, data6));
+  scheduler.scheduleEvent(ndn::time::milliseconds(5500), ndn::bind(&TestSet1::publishSocket2, &testSet1, data7));
+  scheduler.scheduleEvent(ndn::time::milliseconds(6800), ndn::bind(&TestSet1::setSocket1, &testSet1, "/0/4", data6));
+  scheduler.scheduleEvent(ndn::time::milliseconds(6800), ndn::bind(&TestSet1::setSocket2, &testSet1, "/0/4", data7));
+  scheduler.scheduleEvent(ndn::time::milliseconds(6900), ndn::bind(&TestSet1::check, &testSet1, 4));
+  scheduler.scheduleEvent(ndn::time::milliseconds(7000), ndn::bind(&TestSet1::done, &testSet1, ioService));
+
+  ioService->run();
+}
+
+BOOST_AUTO_TEST_CASE (AppSocketTest2)
+{
+  ndn::shared_ptr<boost::asio::io_service> ioService = ndn::make_shared<boost::asio::io_service>();
+  ndn::Scheduler scheduler(*ioService);
+  TestSet2 testSet2(ioService);
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(0), ndn::bind(&TestSet2::createSyncSocket1, &testSet2));
+  scheduler.scheduleEvent(ndn::time::milliseconds(50), ndn::bind(&TestSet2::createSyncSocket2, &testSet2));
+  uint32_t num[5] = {0, 1, 2, 3, 4};
+  string data0((const char *) num, sizeof(num));
+  scheduler.scheduleEvent(ndn::time::milliseconds(100), ndn::bind(&TestSet2::publishSocket1, &testSet2, data0));
+  scheduler.scheduleEvent(ndn::time::milliseconds(150), ndn::bind(&TestSet2::setSocket1, &testSet2, (const char *) num, sizeof (num)));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1000), ndn::bind(&TestSet2::check, &testSet2, 10));
+  uint32_t newNum[5] = {9, 7, 2, 1, 1};
+  string data1((const char *) newNum, sizeof(newNum));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1100), ndn::bind(&TestSet2::publishSocket2, &testSet2, data1));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1150), ndn::bind(&TestSet2::setSocket2, &testSet2, (const char *) newNum, sizeof (newNum)));
+  scheduler.scheduleEvent(ndn::time::milliseconds(2000), ndn::bind(&TestSet2::check, &testSet2, 30));
+  scheduler.scheduleEvent(ndn::time::milliseconds(7000), ndn::bind(&TestSet2::done, &testSet2, ioService));
+
+  ioService->run();
+}
+
+BOOST_AUTO_TEST_CASE (AppSocketTest3)
+{
+  ndn::shared_ptr<boost::asio::io_service> ioService = ndn::make_shared<boost::asio::io_service>();
+  ndn::Scheduler scheduler(*ioService);
+  TestSet3 testSet3(ioService);
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(0), ndn::bind(&TestSet3::createSyncSocket1, &testSet3));
+  scheduler.scheduleEvent(ndn::time::milliseconds(200), ndn::bind(&TestSet3::createSyncSocket2, &testSet3));
+  uint32_t num[5] = {0, 1, 2, 3, 4};
+  string data0((const char *) num, sizeof(num));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1000), ndn::bind(&TestSet3::publishSocket1, &testSet3, data0));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1500), ndn::bind(&TestSet3::setSocket1, &testSet3, (const char *) num, sizeof (num)));
+  scheduler.scheduleEvent(ndn::time::milliseconds(2000), ndn::bind(&TestSet3::check, &testSet3, 10));
+  uint32_t newNum[5] = {9, 7, 2, 1, 1};
+  string data1((const char *) newNum, sizeof(newNum));
+  scheduler.scheduleEvent(ndn::time::milliseconds(3000), ndn::bind(&TestSet3::publishSocket2, &testSet3, data1));
+  scheduler.scheduleEvent(ndn::time::milliseconds(3500), ndn::bind(&TestSet3::setSocket2, &testSet3, (const char *) newNum, sizeof (newNum)));
+  scheduler.scheduleEvent(ndn::time::milliseconds(5000), ndn::bind(&TestSet3::check, &testSet3, 30));
+  scheduler.scheduleEvent(ndn::time::milliseconds(7000), ndn::bind(&TestSet3::done, &testSet3, ioService));
+
+  ioService->run();
+}