Remove legacy code and rename files to new naming convention
diff --git a/tests/main.cpp b/tests/main.cpp
new file mode 100644
index 0000000..4abe5de
--- /dev/null
+++ b/tests/main.cpp
@@ -0,0 +1,25 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016, Regents of the University of California.
+ *
+ * This file is part of ChronoShare, a decentralized file sharing application over NDN.
+ *
+ * ChronoShare 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.
+ *
+ * ChronoShare 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 copies of the GNU General Public License along with
+ * ChronoShare, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ChronoShare authors and contributors.
+ */
+#define BOOST_TEST_MAIN 1
+#define BOOST_TEST_DYN_LINK 1
+#include "test-common.hpp"
+
+
+#include <boost/test/unit_test.hpp>
diff --git a/tests/unit-tests/action-log.t.cpp b/tests/unit-tests/action-log.t.cpp
new file mode 100644
index 0000000..86eb059
--- /dev/null
+++ b/tests/unit-tests/action-log.t.cpp
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *	   Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "logging.h"
+#include "action-log.h"
+
+#include <unistd.h>
+#include <iostream>
+#include <boost/filesystem.hpp>
+#include <boost/make_shared.hpp>
+
+using namespace std;
+using namespace boost;
+using namespace Ndnx;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE(TestActionLog)
+
+BOOST_AUTO_TEST_CASE (ActionLogTest)
+{
+  INIT_LOGGERS ();
+
+  Name localName ("/alex");
+
+  fs::path tmpdir = fs::unique_path (fs::temp_directory_path () / "%%%%-%%%%-%%%%-%%%%");
+  SyncLogPtr syncLog = make_shared<SyncLog> (tmpdir, localName);
+  NdnxWrapperPtr ndnx = make_shared<NdnxWrapper> ();
+
+  ActionLogPtr actionLog = make_shared<ActionLog> (ndnx, tmpdir, syncLog, "top-secret", "test-chronoshare",
+                                                   ActionLog::OnFileAddedOrChangedCallback(), ActionLog::OnFileRemovedCallback ());
+
+// const std::string &filename,
+//                    const Hash &hash,
+//                    time_t wtime,
+//                    int mode,
+//                    int seg_num
+  BOOST_CHECK_EQUAL (syncLog->SeqNo (localName), 0);
+
+  BOOST_CHECK_EQUAL (syncLog->LogSize (), 0);
+  BOOST_CHECK_EQUAL (actionLog->LogSize (), 0);
+
+  actionLog->AddLocalActionUpdate ("file.txt", *Hash::FromString ("2ff304769cdb0125ac039e6fe7575f8576dceffc62618a431715aaf6eea2bf1c"),
+                              time (NULL), 0755, 10);
+
+  BOOST_CHECK_EQUAL (syncLog->SeqNo (localName), 1);
+  BOOST_CHECK_EQUAL (syncLog->LogSize (), 0);
+  BOOST_CHECK_EQUAL (actionLog->LogSize (), 1);
+
+  HashPtr hash = syncLog->RememberStateInStateLog ();
+  BOOST_CHECK_EQUAL (syncLog->LogSize (), 1);
+  BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "3410477233f98d6c3f9a6f8da24494bf5a65e1a7c9f4f66b228128bd4e020558");
+
+  PcoPtr pco = actionLog->LookupActionPco (localName, 0);
+  BOOST_CHECK_EQUAL ((bool)pco, false);
+
+  pco = actionLog->LookupActionPco (localName, 1);
+  BOOST_CHECK_EQUAL ((bool)pco, true);
+
+  BOOST_CHECK_EQUAL (pco->name (), "/alex/test-chronoshare/action/top-secret/%00%01");
+
+  ActionItemPtr action = actionLog->LookupAction (Name ("/alex/test-chronoshare/action/top-secret")(0));
+  BOOST_CHECK_EQUAL ((bool)action, false);
+
+  action = actionLog->LookupAction (Name ("/alex/test-chronoshare/action/top-secret")(1));
+  BOOST_CHECK_EQUAL ((bool)action, true);
+
+  if (action)
+    {
+      BOOST_CHECK_EQUAL (action->version (), 0);
+      BOOST_CHECK_EQUAL (action->action (), 0);
+
+      BOOST_CHECK_EQUAL (action->filename (), "file.txt");
+      BOOST_CHECK_EQUAL (action->seg_num (), 10);
+      BOOST_CHECK_EQUAL (action->file_hash ().size (), 32);
+      BOOST_CHECK_EQUAL (action->mode (), 0755);
+
+      BOOST_CHECK_EQUAL (action->has_parent_device_name (), false);
+      BOOST_CHECK_EQUAL (action->has_parent_seq_no (), false);
+    }
+
+  actionLog->AddLocalActionUpdate ("file.txt", *Hash::FromString ("2ff304769cdb0125ac039e6fe7575f8576dceffc62618a431715aaf6eea2bf1c"),
+                              time (NULL), 0755, 10);
+  BOOST_CHECK_EQUAL (syncLog->SeqNo (localName), 2);
+  BOOST_CHECK_EQUAL (syncLog->LogSize (), 1);
+  BOOST_CHECK_EQUAL (actionLog->LogSize (), 2);
+
+  action = actionLog->LookupAction (Name ("/alex"), 2);
+  BOOST_CHECK_EQUAL ((bool)action, true);
+
+  if (action)
+    {
+      BOOST_CHECK_EQUAL (action->has_parent_device_name (), true);
+      BOOST_CHECK_EQUAL (action->has_parent_seq_no (), true);
+
+      BOOST_CHECK_EQUAL (action->parent_seq_no (), 1);
+      BOOST_CHECK_EQUAL (action->version (), 1);
+    }
+
+  BOOST_CHECK_EQUAL ((bool)actionLog->AddRemoteAction (pco), true);
+  BOOST_CHECK_EQUAL (actionLog->LogSize (), 2);
+
+  // create a real remote action
+  ActionItem item;
+  item.set_action (ActionItem::UPDATE);
+  item.set_filename ("file.txt");
+  item.set_version (2);
+  item.set_timestamp (time (NULL));
+
+  BytesPtr item_msg = serializeMsg (item);
+  Name actionName = Name ("/")(Name("/zhenkai/test"))("test-chronoshare")("action")("top-secret")(1);
+  Bytes actionData = ndnx->createContentObject (actionName, head (*item_msg), item_msg->size ());
+
+  pco = make_shared<ParsedContentObject> (actionData);
+  BOOST_CHECK_EQUAL ((bool)actionLog->AddRemoteAction (pco), true);
+  BOOST_CHECK_EQUAL (actionLog->LogSize (), 3);
+
+  remove_all (tmpdir);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+  // catch (boost::exception &err)
+  //   {
+  //     cout << *boost::get_error_info<errmsg_info_str> (err) << endl;
+  //   }
diff --git a/tests/unit-tests/dispatcher.t.cpp b/tests/unit-tests/dispatcher.t.cpp
new file mode 100644
index 0000000..b5c023b
--- /dev/null
+++ b/tests/unit-tests/dispatcher.t.cpp
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author:  Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *          Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ndnx-wrapper.h"
+#include "logging.h"
+#include "dispatcher.h"
+#include <boost/test/unit_test.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/filesystem.hpp>
+#include <fstream>
+#include <cassert>
+
+using namespace Ndnx;
+using namespace std;
+using namespace boost;
+namespace fs = boost::filesystem;
+
+INIT_LOGGER ("Test.Dispatcher");
+
+BOOST_AUTO_TEST_SUITE(TestDispatcher)
+
+
+void cleanDir(fs::path dir)
+{
+  if (fs::exists(dir))
+  {
+    fs::remove_all(dir);
+  }
+}
+
+void checkRoots(const HashPtr &root1, const HashPtr &root2)
+{
+  BOOST_CHECK_EQUAL(*root1, *root2);
+}
+
+BOOST_AUTO_TEST_CASE(DispatcherTest)
+{
+  INIT_LOGGERS ();
+
+  fs::path dir1("./TestDispatcher/test-white-house");
+  fs::path dir2("./TestDispatcher/test-black-house");
+
+  string user1 = "/obamaa";
+  string user2 = "/romney";
+
+  string folder = "who-is-president";
+
+  NdnxWrapperPtr ndnx1 = make_shared<NdnxWrapper>();
+  usleep(100);
+  NdnxWrapperPtr ndnx2 = make_shared<NdnxWrapper>();
+  usleep(100);
+
+  cleanDir(dir1);
+  cleanDir(dir2);
+
+  Dispatcher d1(user1, folder, dir1, ndnx1, false);
+  usleep(100);
+  Dispatcher d2(user2, folder, dir2, ndnx2, false);
+
+  usleep(14900000);
+
+  _LOG_DEBUG ("checking obama vs romney");
+  checkRoots(d1.SyncRoot(), d2.SyncRoot());
+
+  fs::path filename("a_letter_to_romney.txt");
+  string words = "I'm the new socialist President. You are not!";
+
+  fs::path abf = dir1 / filename;
+
+  ofstream ofs;
+  ofs.open(abf.string().c_str());
+  for (int i = 0; i < 5000; i ++)
+  {
+    ofs << words;
+  }
+  ofs.close();
+
+  d1.Did_LocalFile_AddOrModify(filename);
+
+  sleep(5);
+
+  fs::path ef = dir2 / filename;
+  BOOST_REQUIRE_MESSAGE(fs::exists(ef), user1 << " failed to notify " << user2 << " about " << filename.string());
+  BOOST_CHECK_EQUAL(fs::file_size(abf), fs::file_size(ef));
+  HashPtr fileHash1 = Hash::FromFileContent(abf);
+  HashPtr fileHash2 = Hash::FromFileContent(ef);
+  BOOST_CHECK_EQUAL(*fileHash1, *fileHash2);
+
+  cleanDir(dir1);
+  cleanDir(dir2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/fetch-manager.t.cpp b/tests/unit-tests/fetch-manager.t.cpp
new file mode 100644
index 0000000..98c820a
--- /dev/null
+++ b/tests/unit-tests/fetch-manager.t.cpp
@@ -0,0 +1,280 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *	   Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "fetch-manager.h"
+#include "fetcher.h"
+#include "ndnx-wrapper.h"
+#include <boost/test/unit_test.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/thread/thread.hpp>
+#include "logging.h"
+
+
+INIT_LOGGER ("Test.FetchManager");
+
+using namespace Ndnx;
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(TestFetchManager)
+
+struct FetcherTestData
+{
+  set<uint64_t> recvData;
+  set<uint64_t> recvContent;
+
+  set<Name> differentNames;
+  set<Name> segmentNames;
+
+  bool m_done;
+  bool m_failed;
+
+  FetcherTestData ()
+    : m_done (false)
+    , m_failed (false)
+  {
+  }
+
+  void
+  onData (const Ndnx::Name &deviceName, const Ndnx::Name &basename, uint64_t seqno, Ndnx::PcoPtr pco)
+  {
+    _LOG_TRACE ("onData: " << seqno);
+
+    recvData.insert (seqno);
+    differentNames.insert (basename);
+    Name name = basename;
+    name.appendComp(seqno);
+    segmentNames.insert (name);
+
+    BytesPtr data = pco->contentPtr ();
+
+    if (data->size () == sizeof(int))
+      {
+        recvContent.insert (*reinterpret_cast<const int*> (head(*data)));
+      }
+
+    // cout << "<<< " << basename << ", " << name << ", " << seqno << endl;
+  }
+
+  void
+  finish(const Ndnx::Name &deviceName, const Ndnx::Name &baseName)
+  {
+  }
+
+  void
+  onComplete (Fetcher &fetcher)
+  {
+    m_done = true;
+    // cout << "Done" << endl;
+  }
+
+  void
+  onFail (Fetcher &fetcher)
+  {
+    m_failed = true;
+    // cout << "Failed" << endl;
+  }
+};
+
+void run()
+{
+  NdnxWrapperPtr ndnx = make_shared<NdnxWrapper> ();
+
+  Name baseName ("/base");
+  Name deviceName ("/device");
+
+  for (int i = 0; i < 10; i++)
+    {
+      usleep(100000);
+      ndnx->publishData (Name (baseName)(i), reinterpret_cast<const unsigned char*> (&i), sizeof(int), 30);
+    }
+
+  for (int i = 11; i < 50; i++)
+    {
+      usleep(100000);
+      ndnx->publishData (Name (baseName)(i), reinterpret_cast<const unsigned char*> (&i), sizeof(int), 30);
+    }
+
+}
+
+BOOST_AUTO_TEST_CASE (TestFetcher)
+{
+  INIT_LOGGERS ();
+
+  NdnxWrapperPtr ndnx = make_shared<NdnxWrapper> ();
+
+  Name baseName ("/base");
+  Name deviceName ("/device");
+  /* publish seqnos:  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, <gap 5>, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, <gap 1>, 26 */
+  // this will allow us to test our pipeline of 6
+  for (int i = 0; i < 10; i++)
+    {
+      ndnx->publishData (Name (baseName)(i), reinterpret_cast<const unsigned char*> (&i), sizeof(int), 30);
+    }
+
+  for (int i = 15; i < 25; i++)
+    {
+      ndnx->publishData (Name (baseName)(i), reinterpret_cast<const unsigned char*> (&i), sizeof(int), 30);
+    }
+
+  int oneMore = 26;
+  ndnx->publishData (Name (baseName)(oneMore), reinterpret_cast<const unsigned char*> (&oneMore), sizeof(int), 30);
+
+  FetcherTestData data;
+  ExecutorPtr executor = make_shared<Executor>(1);
+  executor->start ();
+
+  Fetcher fetcher (ndnx,
+                   executor,
+                   bind (&FetcherTestData::onData, &data, _1, _2, _3, _4),
+                   bind (&FetcherTestData::finish, &data, _1, _2),
+                   bind (&FetcherTestData::onComplete, &data, _1),
+                   bind (&FetcherTestData::onFail, &data, _1),
+                   deviceName, Name ("/base"), 0, 26,
+                   boost::posix_time::seconds (5)); // this time is not precise
+
+  BOOST_CHECK_EQUAL (fetcher.IsActive (), false);
+  fetcher.RestartPipeline ();
+  BOOST_CHECK_EQUAL (fetcher.IsActive (), true);
+
+  usleep(7000000);
+  BOOST_CHECK_EQUAL (data.m_failed, true);
+  BOOST_CHECK_EQUAL (data.differentNames.size (), 1);
+  BOOST_CHECK_EQUAL (data.segmentNames.size (), 20);
+  BOOST_CHECK_EQUAL (data.recvData.size (), 20);
+  BOOST_CHECK_EQUAL (data.recvContent.size (), 20);
+
+  {
+    ostringstream recvData;
+    for (set<uint64_t>::iterator i = data.recvData.begin (); i != data.recvData.end (); i++)
+      recvData << *i << ", ";
+
+    ostringstream recvContent;
+    for (set<uint64_t>::iterator i = data.recvContent.begin (); i != data.recvContent.end (); i++)
+      recvContent << *i << ", ";
+
+    BOOST_CHECK_EQUAL (recvData.str (), "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, ");
+    BOOST_CHECK_EQUAL (recvData.str (), recvContent.str ());
+  }
+
+  BOOST_CHECK_EQUAL (fetcher.IsActive (), false);
+  fetcher.RestartPipeline ();
+  BOOST_CHECK_EQUAL (fetcher.IsActive (), true);
+
+  usleep(7000000);
+  BOOST_CHECK_EQUAL (data.m_failed, true);
+
+  // publishing missing pieces
+  for (int i = 0; i < 27; i++)
+    {
+      ndnx->publishData (Name (baseName)(i), reinterpret_cast<const unsigned char*> (&i), sizeof(int), 1);
+    }
+  BOOST_CHECK_EQUAL (fetcher.IsActive (), false);
+  fetcher.RestartPipeline ();
+  BOOST_CHECK_EQUAL (fetcher.IsActive (), true);
+
+  usleep(1000000);
+  BOOST_CHECK_EQUAL (data.m_done, true);
+
+  {
+    ostringstream recvData;
+    for (set<uint64_t>::iterator i = data.recvData.begin (); i != data.recvData.end (); i++)
+      recvData << *i << ", ";
+
+    ostringstream recvContent;
+    for (set<uint64_t>::iterator i = data.recvContent.begin (); i != data.recvContent.end (); i++)
+      recvContent << *i << ", ";
+
+    BOOST_CHECK_EQUAL (recvData.str (), "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, ");
+    BOOST_CHECK_EQUAL (recvData.str (), recvContent.str ());
+  }
+
+  executor->shutdown ();
+}
+
+
+BOOST_AUTO_TEST_CASE (TestFetcher2)
+{
+  INIT_LOGGERS ();
+
+  NdnxWrapperPtr ndnx = make_shared<NdnxWrapper> ();
+
+  Name baseName ("/base");
+  Name deviceName ("/device");
+
+  thread publishThread(run);
+
+  FetcherTestData data;
+  ExecutorPtr executor = make_shared<Executor>(1);
+  executor->start ();
+
+  Fetcher fetcher (ndnx,
+                   executor,
+                   bind (&FetcherTestData::onData, &data, _1, _2, _3, _4),
+                   bind (&FetcherTestData::finish, &data, _1, _2),
+                   bind (&FetcherTestData::onComplete, &data, _1),
+                   bind (&FetcherTestData::onFail, &data, _1),
+                   deviceName, baseName, 0, 49,
+                   boost::posix_time::seconds (5)); // this time is not precise
+
+  BOOST_CHECK_EQUAL (fetcher.IsActive (), false);
+  fetcher.RestartPipeline ();
+  BOOST_CHECK_EQUAL (fetcher.IsActive (), true);
+
+  usleep(20000000);
+  BOOST_CHECK_EQUAL (data.m_failed, true);
+
+  executor->shutdown ();
+}
+
+
+
+// BOOST_AUTO_TEST_CASE (NdnxWrapperSelector)
+// {
+
+//   Closure closure (bind(dataCallback, _1, _2), bind(timeout, _1));
+
+//   Selectors selectors;
+//   selectors.interestLifetime(1);
+
+//   string n1 = "/random/01";
+//   c1->sendInterest(Name(n1), closure, selectors);
+//   sleep(2);
+//   c2->publishData(Name(n1), (const unsigned char *)n1.c_str(), n1.size(), 4);
+//   usleep(100000);
+//   BOOST_CHECK_EQUAL(g_timeout_counter, 1);
+//   BOOST_CHECK_EQUAL(g_dataCallback_counter, 0);
+
+//   string n2 = "/random/02";
+//   selectors.interestLifetime(2);
+//   c1->sendInterest(Name(n2), closure, selectors);
+//   sleep(1);
+//   c2->publishData(Name(n2), (const unsigned char *)n2.c_str(), n2.size(), 4);
+//   usleep(100000);
+//   BOOST_CHECK_EQUAL(g_timeout_counter, 1);
+//   BOOST_CHECK_EQUAL(g_dataCallback_counter, 1);
+
+//   // reset
+//   g_dataCallback_counter = 0;
+//   g_timeout_counter = 0;
+// }
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/fetch-task-db.t.cpp b/tests/unit-tests/fetch-task-db.t.cpp
new file mode 100644
index 0000000..61bec89
--- /dev/null
+++ b/tests/unit-tests/fetch-task-db.t.cpp
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *	   Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "logging.h"
+#include "fetch-task-db.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+#include <boost/test/unit_test.hpp>
+#include <unistd.h>
+#include <boost/make_shared.hpp>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <utility>
+
+INIT_LOGGER ("Test.FetchTaskDb");
+
+using namespace Ndnx;
+using namespace std;
+using namespace boost;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE(TestFetchTaskDb)
+
+class Checker
+{
+public:
+  Checker(const Name &deviceName, const Name &baseName, uint64_t minSeqNo, uint64_t maxSeqNo, int priority)
+        : m_deviceName(deviceName), m_baseName(baseName), m_minSeqNo(minSeqNo), m_maxSeqNo(maxSeqNo), m_priority(priority)
+  {}
+
+  Checker(const Checker &other)
+        : m_deviceName(other.m_deviceName), m_baseName(other.m_baseName), m_minSeqNo(other.m_minSeqNo), m_maxSeqNo(other.m_maxSeqNo), m_priority(other.m_priority)
+  {}
+
+  bool
+  operator==(const Checker &other) { return m_deviceName == other.m_deviceName && m_baseName == other.m_baseName && m_minSeqNo == other.m_minSeqNo && m_maxSeqNo == other.m_maxSeqNo && m_priority == other.m_priority; }
+
+  void show()
+  {
+    cout << m_deviceName  <<", " << m_baseName << ", " << m_minSeqNo << ", " << m_maxSeqNo << ", " << m_priority << endl;
+  }
+
+  Name m_deviceName;
+  Name m_baseName;
+  uint64_t m_minSeqNo;
+  uint64_t m_maxSeqNo;
+  int m_priority;
+};
+
+map<Name, Checker> checkers;
+int g_counter = 0;
+
+void
+getChecker(const Name &deviceName, const Name &baseName, uint64_t minSeqNo, uint64_t maxSeqNo, int priority)
+{
+  Checker checker(deviceName, baseName, minSeqNo, maxSeqNo, priority);
+  g_counter ++;
+  if (checkers.find(checker.m_deviceName + checker.m_baseName) != checkers.end())
+  {
+    BOOST_FAIL("duplicated checkers");
+  }
+  checkers.insert(make_pair(checker.m_deviceName + checker.m_baseName, checker));
+}
+
+BOOST_AUTO_TEST_CASE (FetchTaskDbTest)
+{
+  INIT_LOGGERS ();
+  fs::path folder("TaskDbTest");
+  fs::create_directories(folder / ".chronoshare");
+
+  FetchTaskDbPtr db = make_shared<FetchTaskDb>(folder, "test");
+
+  map<Name, Checker> m1;
+  g_counter = 0;
+
+  checkers.clear();
+
+  Name deviceNamePrefix("/device");
+  Name baseNamePrefix("/device/base");
+
+  // add 10 tasks
+  for (uint64_t i = 0; i < 10; i++)
+  {
+    Name d = deviceNamePrefix;
+    Name b = baseNamePrefix;
+    Checker c(d.appendComp(i), b.appendComp(i), i, 11, 1);
+    m1.insert(make_pair(d + b, c));
+    db->addTask(c.m_deviceName, c.m_baseName, c.m_minSeqNo, c.m_maxSeqNo, c.m_priority);
+  }
+
+  // delete the latter 5
+  for (uint64_t i = 5; i < 10; i++)
+  {
+    Name d = deviceNamePrefix;
+    Name b = baseNamePrefix;
+    d.appendComp(i);
+    b.appendComp(i);
+    db->deleteTask(d, b);
+  }
+
+  // add back 3 to 7, 3 and 4 should not be added twice
+
+  for (uint64_t i = 3; i < 8; i++)
+  {
+    Name d = deviceNamePrefix;
+    Name b = baseNamePrefix;
+    Checker c(d.appendComp(i), b.appendComp(i), i, 11, 1);
+    db->addTask(c.m_deviceName, c.m_baseName, c.m_minSeqNo, c.m_maxSeqNo, c.m_priority);
+  }
+
+  db->foreachTask(bind(getChecker, _1, _2, _3, _4, _5));
+
+  BOOST_CHECK_EQUAL(g_counter, 8);
+
+  map<Name, Checker>::iterator it = checkers.begin();
+  while (it != checkers.end())
+  {
+    map<Name, Checker>::iterator mt = m1.find(it->first);
+    if (mt == m1.end())
+    {
+      BOOST_FAIL("unknown task found");
+    }
+    else
+    {
+      Checker c1 = it->second;
+      Checker c2 = mt->second;
+      BOOST_CHECK(c1 == c2);
+      if (! (c1 == c2))
+      {
+        cout << "C1: " << endl;
+        c1.show();
+        cout << "C2: " << endl;
+        c2.show();
+      }
+    }
+    ++it;
+  }
+  fs::remove_all(folder);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/fs-watcher-delay.t.cpp b/tests/unit-tests/fs-watcher-delay.t.cpp
new file mode 100644
index 0000000..a44bde1
--- /dev/null
+++ b/tests/unit-tests/fs-watcher-delay.t.cpp
@@ -0,0 +1,83 @@
+#include "fs-watcher.h"
+#include <boost/make_shared.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <fstream>
+#include <set>
+#include <QtGui>
+#include <iostream>
+
+using namespace std;
+using namespace boost;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE(TestFsWatcherDelay)
+
+void
+onChange(const fs::path &file)
+{
+  cerr << "onChange called" << endl;
+}
+
+void
+onDelete(const fs::path &file)
+{
+  cerr << "onDelete called" << endl;
+}
+
+void run(fs::path dir, FsWatcher::LocalFile_Change_Callback c, FsWatcher::LocalFile_Change_Callback d)
+{
+  int x = 0;
+  QCoreApplication app (x, 0);
+  FsWatcher watcher (dir.string().c_str(), c, d);
+  app.exec();
+  sleep(100);
+}
+
+void SlowWrite(fs::path & file)
+{
+  fs::ofstream off(file, std::ios::out);
+
+  for (int i = 0; i < 10; i++){
+    off << i  << endl;
+    usleep(200000);
+  }
+}
+
+BOOST_AUTO_TEST_CASE (TestFsWatcherDelay)
+{
+  fs::path dir = fs::absolute(fs::path("TestFsWatcher"));
+  if (fs::exists(dir))
+  {
+    fs::remove_all(dir);
+  }
+
+  fs::create_directory(dir);
+
+  FsWatcher::LocalFile_Change_Callback fileChange = boost::bind(onChange, _1);
+  FsWatcher::LocalFile_Change_Callback fileDelete = boost::bind(onDelete, _1);
+
+  fs::path file = dir / "test.text";
+
+  thread watcherThread(run, dir, fileChange, fileDelete);
+
+  thread writeThread(SlowWrite, file);
+
+
+
+  usleep(10000000);
+
+  // cleanup
+  if (fs::exists(dir))
+  {
+    fs::remove_all(dir);
+  }
+
+  usleep(1000000);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/fs-watcher.t.cpp b/tests/unit-tests/fs-watcher.t.cpp
new file mode 100644
index 0000000..d943903
--- /dev/null
+++ b/tests/unit-tests/fs-watcher.t.cpp
@@ -0,0 +1,209 @@
+#include "fs-watcher.h"
+#include <boost/make_shared.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+#include <fstream>
+#include <set>
+#include <QtGui>
+#include <iostream>
+
+using namespace std;
+using namespace boost;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE(TestFsWatcher)
+
+void
+onChange(set<string> &files, const fs::path &file)
+{
+  cerr << "onChange called" << endl;
+  files.insert(file.string());
+}
+
+void
+onDelete(set<string> &files, const fs::path &file)
+{
+  files.erase(file.string());
+}
+
+void create_file( const fs::path & ph, const std::string & contents )
+{
+  std::ofstream f( ph.string().c_str() );
+  if ( !f )
+  {
+    abort();
+  }
+  if ( !contents.empty() )
+  {
+    f << contents;
+  }
+}
+
+void run(fs::path dir, FsWatcher::LocalFile_Change_Callback c, FsWatcher::LocalFile_Change_Callback d)
+{
+  int x = 0;
+  QCoreApplication app (x, 0);
+  FsWatcher watcher (dir.string().c_str(), c, d);
+  app.exec();
+  sleep(100);
+}
+
+BOOST_AUTO_TEST_CASE (TestFsWatcher)
+{
+  fs::path dir = fs::absolute(fs::path("TestFsWatcher"));
+  if (fs::exists(dir))
+  {
+    fs::remove_all(dir);
+  }
+
+  fs::create_directory(dir);
+
+  set<string> files;
+
+  FsWatcher::LocalFile_Change_Callback fileChange = boost::bind(onChange,ref(files), _1);
+  FsWatcher::LocalFile_Change_Callback fileDelete = boost::bind(onDelete, ref(files), _1);
+
+  thread workThread(run, dir, fileChange, fileDelete);
+  //FsWatcher watcher (dir.string().c_str(), fileChange, fileDelete);
+
+  // ============ check create file detection ================
+  create_file(dir / "test.txt", "hello");
+  // have to at least wait 0.5 seconds
+  usleep(1000000);
+  // test.txt
+  BOOST_CHECK_EQUAL(files.size(), 1);
+  BOOST_CHECK(files.find("test.txt") != files.end());
+
+  // =========== check create a bunch of files in sub dir =============
+  fs::path subdir = dir / "sub";
+  fs::create_directory(subdir);
+  for (int i = 0; i < 10; i++)
+  {
+    string filename = boost::lexical_cast<string>(i);
+    create_file(subdir / filename.c_str(), boost::lexical_cast<string>(i));
+  }
+  // have to at least wait 0.5 * 2 seconds
+  usleep(1100000);
+  // test.txt
+  // sub/0..9
+  BOOST_CHECK_EQUAL(files.size(), 11);
+  for (int i = 0; i < 10; i++)
+  {
+    string filename = boost::lexical_cast<string>(i);
+    BOOST_CHECK(files.find("sub/" +filename) != files.end());
+  }
+
+  // ============== check copy directory with files to two levels of sub dirs =================
+  fs::create_directory(dir / "sub1");
+  fs::path subdir1 = dir / "sub1" / "sub2";
+  fs::copy_directory(subdir, subdir1);
+  for (int i = 0; i < 5; i++)
+  {
+    string filename = boost::lexical_cast<string>(i);
+    fs::copy_file(subdir / filename.c_str(), subdir1 / filename.c_str());
+  }
+  // have to at least wait 0.5 * 2 seconds
+  usleep(1100000);
+  // test.txt
+  // sub/0..9
+  // sub1/sub2/0..4
+  BOOST_CHECK_EQUAL(files.size(), 16);
+  for (int i = 0; i < 5; i++)
+  {
+    string filename = boost::lexical_cast<string>(i);
+    BOOST_CHECK(files.find("sub1/sub2/" + filename) != files.end());
+  }
+
+  // =============== check remove files =========================
+  for (int i = 0; i < 7; i++)
+  {
+    string filename = boost::lexical_cast<string>(i);
+    fs::remove(subdir / filename.c_str());
+  }
+  usleep(1100000);
+  // test.txt
+  // sub/7..9
+  // sub1/sub2/0..4
+  BOOST_CHECK_EQUAL(files.size(), 9);
+  for (int i = 0; i < 10; i++)
+  {
+    string filename = boost::lexical_cast<string>(i);
+    if (i < 7)
+      BOOST_CHECK(files.find("sub/" + filename) == files.end());
+    else
+      BOOST_CHECK(files.find("sub/" + filename) != files.end());
+  }
+
+  // =================== check remove files again, remove the whole dir this time ===================
+  // before remove check
+  for (int i = 0; i < 5; i++)
+  {
+    string filename = boost::lexical_cast<string>(i);
+    BOOST_CHECK(files.find("sub1/sub2/" + filename) != files.end());
+  }
+  fs::remove_all(subdir1);
+  usleep(1100000);
+  BOOST_CHECK_EQUAL(files.size(), 4);
+  // test.txt
+  // sub/7..9
+  for (int i = 0; i < 5; i++)
+  {
+    string filename = boost::lexical_cast<string>(i);
+    BOOST_CHECK(files.find("sub1/sub2/" + filename) == files.end());
+  }
+
+  // =================== check rename files =======================
+  for (int i = 7; i < 10; i++)
+  {
+    string filename = boost::lexical_cast<string>(i);
+    fs::rename(subdir / filename.c_str(), dir / filename.c_str());
+  }
+  usleep(1100000);
+  // test.txt
+  // 7
+  // 8
+  // 9
+  // sub
+  BOOST_CHECK_EQUAL(files.size(), 4);
+  for (int i = 7; i < 10; i++)
+  {
+    string filename = boost::lexical_cast<string>(i);
+    BOOST_CHECK(files.find("sub/" + filename) == files.end());
+    BOOST_CHECK(files.find(filename) != files.end());
+  }
+
+  create_file(dir / "add-removal-check.txt", "add-removal-check");
+  usleep(1200000);
+  BOOST_CHECK (files.find("add-removal-check.txt") != files.end());
+
+  fs::remove (dir / "add-removal-check.txt");
+  usleep(1200000);
+  BOOST_CHECK (files.find("add-removal-check.txt") == files.end());
+
+  create_file(dir / "add-removal-check.txt", "add-removal-check");
+  usleep(1200000);
+  BOOST_CHECK (files.find("add-removal-check.txt") != files.end());
+
+  fs::remove (dir / "add-removal-check.txt");
+  usleep(1200000);
+  BOOST_CHECK (files.find("add-removal-check.txt") == files.end());
+
+  create_file(dir / "add-removal-check.txt", "add-removal-check");
+  usleep(1200000);
+  BOOST_CHECK (files.find("add-removal-check.txt") != files.end());
+
+  fs::remove (dir / "add-removal-check.txt");
+  usleep(1200000);
+  BOOST_CHECK (files.find("add-removal-check.txt") == files.end());
+
+  // cleanup
+  if (fs::exists(dir))
+  {
+    fs::remove_all(dir);
+  }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/object-manager.t.cpp b/tests/unit-tests/object-manager.t.cpp
new file mode 100644
index 0000000..60f0c58
--- /dev/null
+++ b/tests/unit-tests/object-manager.t.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *	   Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "logging.h"
+#include "object-manager.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include <boost/test/unit_test.hpp>
+#include <unistd.h>
+#include <boost/make_shared.hpp>
+#include <iostream>
+#include <iterator>
+
+INIT_LOGGER ("Test.ObjectManager");
+
+using namespace Ndnx;
+using namespace std;
+using namespace boost;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE(TestObjectManager)
+
+BOOST_AUTO_TEST_CASE (ObjectManagerTest)
+{
+  INIT_LOGGERS ();
+
+  fs::path tmpdir = fs::unique_path (fs::temp_directory_path () / "%%%%-%%%%-%%%%-%%%%");
+  _LOG_DEBUG ("tmpdir: " << tmpdir);
+  Name deviceName ("/device");
+
+  NdnxWrapperPtr ndnx = make_shared<NdnxWrapper> ();
+  ObjectManager manager (ndnx, tmpdir, "test-chronoshare");
+
+  tuple<HashPtr,int> hash_semgents = manager.localFileToObjects (fs::path("test") / "test-object-manager.cc", deviceName);
+
+  BOOST_CHECK_EQUAL (hash_semgents.get<1> (), 3);
+
+  bool ok = manager.objectsToLocalFile (deviceName, *hash_semgents.get<0> (), tmpdir / "test.cc");
+  BOOST_CHECK_EQUAL (ok, true);
+
+  {
+    fs::ifstream origFile (fs::path("test") / "test-object-manager.cc");
+    fs::ifstream newFile (tmpdir / "test.cc");
+
+    istream_iterator<char> eof,
+      origFileI (origFile),
+      newFileI (newFile);
+
+    BOOST_CHECK_EQUAL_COLLECTIONS (origFileI, eof, newFileI, eof);
+  }
+
+  remove_all (tmpdir);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/protobuf.t.cpp b/tests/unit-tests/protobuf.t.cpp
new file mode 100644
index 0000000..d0a7b8e
--- /dev/null
+++ b/tests/unit-tests/protobuf.t.cpp
@@ -0,0 +1,47 @@
+#include "ndnx-common.h"
+#include "sync-core.h"
+#include <boost/make_shared.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/iostreams/filter/gzip.hpp>
+#include <boost/iostreams/filtering_stream.hpp>
+#include <boost/iostreams/device/back_inserter.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/make_shared.hpp>
+
+using namespace Ndnx;
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(ProtobufTests)
+
+
+BOOST_AUTO_TEST_CASE (TestGzipProtobuf)
+{
+  SyncStateMsgPtr msg = make_shared<SyncStateMsg>();
+
+  SyncState *state = msg->add_state();
+  state->set_type(SyncState::UPDATE);
+  state->set_seq(100);
+  char x[100] = {'a'};
+  state->set_locator(&x[0], sizeof(x));
+  state->set_name(&x[0], sizeof(x));
+
+  BytesPtr bb = serializeMsg<SyncStateMsg>(*msg);
+
+  BytesPtr cb = serializeGZipMsg<SyncStateMsg>(*msg);
+  BOOST_CHECK(cb->size() < bb->size());
+  cout << cb->size() <<", " << bb->size() << endl;
+
+  SyncStateMsgPtr msg1 = deserializeGZipMsg<SyncStateMsg>(*cb);
+
+  BOOST_REQUIRE(msg1->state_size() == 1);
+
+  SyncState state1 = msg1->state(0);
+  BOOST_CHECK_EQUAL(state->seq(), state1.seq());
+  BOOST_CHECK_EQUAL(state->type(), state1.type());
+  string sx(x, 100);
+  BOOST_CHECK_EQUAL(sx, state1.name());
+  BOOST_CHECK_EQUAL(sx, state1.locator());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/serve-and-fetch.t.cpp b/tests/unit-tests/serve-and-fetch.t.cpp
new file mode 100644
index 0000000..8e54404
--- /dev/null
+++ b/tests/unit-tests/serve-and-fetch.t.cpp
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *	   Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "fetch-manager.h"
+#include "ndnx-wrapper.h"
+#include "ndnx-common.h"
+#include "scheduler.h"
+#include "object-db.h"
+#include "object-manager.h"
+#include "content-server.h"
+#include <boost/test/unit_test.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/thread_time.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <stdio.h>
+#include <ctime>
+
+#include "logging.h"
+
+INIT_LOGGER("Test.ServerAndFetch");
+
+using namespace Ndnx;
+using namespace std;
+using namespace boost;
+using namespace boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE(TestServeAndFetch)
+
+path root("test-server-and-fetch");
+path filePath = root / "random-file";
+unsigned char magic = 'm';
+int repeat = 1024 * 400;
+mutex mut;
+condition_variable cond;
+bool finished;
+int ack;
+
+void setup()
+{
+  if (exists(root))
+  {
+    remove_all(root);
+  }
+
+  create_directory(root);
+
+  // create file
+  FILE *fp = fopen(filePath.string().c_str(), "w");
+  for (int i = 0; i < repeat; i++)
+  {
+    fwrite(&magic, 1, sizeof(magic), fp);
+  }
+  fclose(fp);
+
+  ack = 0;
+  finished = false;
+}
+
+void teardown()
+{
+  if (exists(root))
+  {
+    remove_all(root);
+  }
+
+  ack = 0;
+  finished = false;
+}
+
+Name
+simpleMap(const Name &deviceName)
+{
+  return Name("/local");
+}
+
+void
+segmentCallback(const Name &deviceName, const Name &baseName, uint64_t seq, PcoPtr pco)
+{
+  ack++;
+  Bytes co = pco->content();
+  int size = co.size();
+  for (int i = 0; i < size; i++)
+  {
+    BOOST_CHECK_EQUAL(co[i], magic);
+  }
+}
+
+void
+finishCallback(Name &deviceName, Name &baseName)
+{
+  BOOST_CHECK_EQUAL(ack, repeat / 1024);
+  unique_lock<mutex> lock(mut);
+  finished = true;
+  cond.notify_one();
+}
+
+BOOST_AUTO_TEST_CASE (TestServeAndFetch)
+{
+  INIT_LOGGERS ();
+
+  _LOG_DEBUG ("Setting up test environment ...");
+  setup();
+
+  NdnxWrapperPtr ndnx_serve = make_shared<NdnxWrapper>();
+  usleep(1000);
+  NdnxWrapperPtr ndnx_fetch = make_shared<NdnxWrapper>();
+
+  Name deviceName("/test/device");
+  Name localPrefix("/local");
+  Name broadcastPrefix("/broadcast");
+
+  const string APPNAME = "test-chronoshare";
+
+  time_t start = time(NULL);
+  _LOG_DEBUG ("At time " << start << ", publish local file to database, this is extremely slow ...");
+  // publish file to db
+  ObjectManager om(ndnx_serve, root, APPNAME);
+  tuple<HashPtr, size_t> pub = om.localFileToObjects(filePath, deviceName);
+  time_t end = time(NULL);
+  _LOG_DEBUG ("At time " << end <<", publish finally finished, used " << end - start << " seconds ...");
+
+  ActionLogPtr dummyLog;
+  ContentServer server(ndnx_serve, dummyLog, root, deviceName, "pentagon's secrets", APPNAME, 5);
+  server.registerPrefix(localPrefix);
+  server.registerPrefix(broadcastPrefix);
+
+  FetchManager fm(ndnx_fetch, bind(simpleMap, _1), Name("/local/broadcast"));
+  HashPtr hash = pub.get<0> ();
+  Name baseName = Name ("/")(deviceName)(APPNAME)("file")(hash->GetHash(), hash->GetHashBytes());
+
+  fm.Enqueue(deviceName, baseName, bind(segmentCallback, _1, _2, _3, _4), bind(finishCallback, _1, _2), 0, pub.get<1>() - 1);
+
+  unique_lock<mutex> lock(mut);
+  system_time timeout = get_system_time() + posix_time::milliseconds(5000);
+  while (!finished)
+    {
+      if (!cond.timed_wait(lock, timeout))
+        {
+          BOOST_FAIL ("Fetching has not finished after 5 seconds");
+          break;
+        }
+    }
+  ndnx_fetch->shutdown ();
+  ndnx_serve->shutdown ();
+
+  _LOG_DEBUG ("Finish");
+  usleep(100000);
+
+  teardown();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/sync-core.t.cpp b/tests/unit-tests/sync-core.t.cpp
new file mode 100644
index 0000000..04f560a
--- /dev/null
+++ b/tests/unit-tests/sync-core.t.cpp
@@ -0,0 +1,115 @@
+#include "sync-core.h"
+#include "logging.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/make_shared.hpp>
+
+using namespace std;
+using namespace Ndnx;
+using namespace boost;
+using namespace boost::filesystem;
+
+INIT_LOGGER("Test.SyncCore");
+
+BOOST_AUTO_TEST_SUITE(SyncCoreTests)
+
+void callback(const SyncStateMsgPtr &msg)
+{
+  BOOST_CHECK(msg->state_size() > 0);
+  int size = msg->state_size();
+  int index = 0;
+  while (index < size)
+  {
+    SyncState state = msg->state(index);
+    BOOST_CHECK(state.has_old_seq());
+    BOOST_CHECK(state.old_seq() >= 0);
+    if (state.seq() != 0)
+    {
+      BOOST_CHECK(state.old_seq() != state.seq());
+    }
+    index++;
+  }
+}
+
+void checkRoots(const HashPtr &root1, const HashPtr &root2)
+{
+  BOOST_CHECK_EQUAL(*root1, *root2);
+}
+
+BOOST_AUTO_TEST_CASE(SyncCoreTest)
+{
+  INIT_LOGGERS();
+
+  string dir = "./SyncCoreTest";
+  // clean the test dir
+  path d(dir);
+  if (exists(d))
+  {
+    remove_all(d);
+  }
+
+  string dir1 = "./SyncCoreTest/1";
+  string dir2 = "./SyncCoreTest/2";
+  Name user1("/joker");
+  Name loc1("/gotham1");
+  Name user2("/darkknight");
+  Name loc2("/gotham2");
+  Name syncPrefix("/broadcast/darkknight");
+  NdnxWrapperPtr c1(new NdnxWrapper());
+  NdnxWrapperPtr c2(new NdnxWrapper());
+  SyncLogPtr log1(new SyncLog(dir1, user1.toString()));
+  SyncLogPtr log2(new SyncLog(dir2, user2.toString()));
+
+  SyncCore *core1 = new SyncCore(log1, user1, loc1, syncPrefix, bind(callback, _1), c1);
+  usleep(10000);
+  SyncCore *core2 = new SyncCore(log2, user2, loc2, syncPrefix, bind(callback, _1), c2);
+
+  sleep(1);
+  checkRoots(core1->root(), core2->root());
+
+  // _LOG_TRACE ("\n\n\n\n\n\n----------\n");
+
+  core1->updateLocalState(1);
+  usleep(100000);
+  checkRoots(core1->root(), core2->root());
+  BOOST_CHECK_EQUAL(core2->seq(user1), 1);
+  BOOST_CHECK_EQUAL(log2->LookupLocator (user1), loc1);
+
+  core1->updateLocalState(5);
+  usleep(100000);
+  checkRoots(core1->root(), core2->root());
+  BOOST_CHECK_EQUAL(core2->seq(user1), 5);
+  BOOST_CHECK_EQUAL(log2->LookupLocator (user1), loc1);
+
+  core2->updateLocalState(10);
+  usleep(100000);
+  checkRoots(core1->root(), core2->root());
+  BOOST_CHECK_EQUAL(core1->seq(user2), 10);
+  BOOST_CHECK_EQUAL(log1->LookupLocator (user2), loc2);
+
+  // simple simultaneous data generation
+  // _LOG_TRACE ("\n\n\n\n\n\n----------Simultaneous\n");
+  _LOG_TRACE ("Simultaneous");
+
+  core1->updateLocalState(11);
+  usleep(100);
+  core2->updateLocalState(15);
+  usleep(2000000);
+  checkRoots(core1->root(), core2->root());
+  BOOST_CHECK_EQUAL(core1->seq(user2), 15);
+  BOOST_CHECK_EQUAL(core2->seq(user1), 11);
+
+  BOOST_CHECK_EQUAL(log1->LookupLocator (user1), loc1);
+  BOOST_CHECK_EQUAL(log1->LookupLocator (user2), loc2);
+  BOOST_CHECK_EQUAL(log2->LookupLocator (user1), loc1);
+  BOOST_CHECK_EQUAL(log2->LookupLocator (user2), loc2);
+
+  // clean the test dir
+  if (exists(d))
+  {
+    remove_all(d);
+  }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/sync-log.t.cpp b/tests/unit-tests/sync-log.t.cpp
new file mode 100644
index 0000000..8ac36b1
--- /dev/null
+++ b/tests/unit-tests/sync-log.t.cpp
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *	   Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "logging.h"
+#include <unistd.h>
+#include "action-log.h"
+#include <iostream>
+#include <ndnx-name.h>
+#include <boost/filesystem.hpp>
+
+using namespace std;
+using namespace boost;
+using namespace Ndnx;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE(TestSyncLog)
+
+
+BOOST_AUTO_TEST_CASE (BasicDatabaseTest)
+{
+  INIT_LOGGERS ();
+
+  fs::path tmpdir = fs::unique_path (fs::temp_directory_path () / "%%%%-%%%%-%%%%-%%%%");
+  SyncLog db (tmpdir, Name ("/alex"));
+
+  HashPtr hash = db.RememberStateInStateLog ();
+  // should be empty
+  BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "7a6f2c1eefd539560d2dc3e5542868a79810d0867db15d9b87e41ec105899405");
+
+  db.UpdateDeviceSeqNo (Name ("/alex"), 1);
+  hash = db.RememberStateInStateLog ();
+
+  BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "3410477233f98d6c3f9a6f8da24494bf5a65e1a7c9f4f66b228128bd4e020558");
+
+  db.UpdateDeviceSeqNo (Name ("/alex"), 2);
+  hash = db.RememberStateInStateLog ();
+  BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "2ff304769cdb0125ac039e6fe7575f8576dceffc62618a431715aaf6eea2bf1c");
+
+  db.UpdateDeviceSeqNo (Name ("/alex"), 2);
+  hash = db.RememberStateInStateLog ();
+  BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "2ff304769cdb0125ac039e6fe7575f8576dceffc62618a431715aaf6eea2bf1c");
+
+  db.UpdateDeviceSeqNo (Name ("/alex"), 1);
+  hash = db.RememberStateInStateLog ();
+  BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "2ff304769cdb0125ac039e6fe7575f8576dceffc62618a431715aaf6eea2bf1c");
+
+  db.UpdateLocator(Name ("/alex"), Name("/hawaii"));
+
+  BOOST_CHECK_EQUAL(db.LookupLocator(Name ("/alex")), Name ("/hawaii"));
+
+  SyncStateMsgPtr msg = db.FindStateDifferences ("00", "95284d3132a7a88b85c5141ca63efa68b7a7daf37315def69e296a0c24692833");
+  BOOST_CHECK_EQUAL (msg->state_size(), 0);
+
+  msg = db.FindStateDifferences ("00", "2ff304769cdb0125ac039e6fe7575f8576dceffc62618a431715aaf6eea2bf1c");
+  BOOST_CHECK_EQUAL (msg->state_size(), 1);
+  BOOST_CHECK_EQUAL (msg->state (0).type (), SyncState::UPDATE);
+  BOOST_CHECK_EQUAL (msg->state (0).seq (), 2);
+
+  msg = db.FindStateDifferences ("2ff304769cdb0125ac039e6fe7575f8576dceffc62618a431715aaf6eea2bf1c", "00");
+  BOOST_CHECK_EQUAL (msg->state_size(), 1);
+  BOOST_CHECK_EQUAL (msg->state (0).type (), SyncState::DELETE);
+
+  msg = db.FindStateDifferences ("7a6f2c1eefd539560d2dc3e5542868a79810d0867db15d9b87e41ec105899405",
+                                 "2ff304769cdb0125ac039e6fe7575f8576dceffc62618a431715aaf6eea2bf1c");
+  BOOST_CHECK_EQUAL (msg->state_size(), 1);
+  BOOST_CHECK_EQUAL (msg->state (0).type (), SyncState::UPDATE);
+  BOOST_CHECK_EQUAL (msg->state (0).seq (), 2);
+
+  msg = db.FindStateDifferences ("2ff304769cdb0125ac039e6fe7575f8576dceffc62618a431715aaf6eea2bf1c",
+                                 "7a6f2c1eefd539560d2dc3e5542868a79810d0867db15d9b87e41ec105899405");
+  BOOST_CHECK_EQUAL (msg->state_size(), 1);
+  BOOST_CHECK_EQUAL (msg->state (0).type (), SyncState::UPDATE);
+  BOOST_CHECK_EQUAL (msg->state (0).seq (), 0);
+
+  db.UpdateDeviceSeqNo (Name ("/bob"), 1);
+  hash = db.RememberStateInStateLog ();
+  BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "5df5affc07120335089525e82ec9fda60c6dccd7addb667106fb79de80610519");
+
+  msg = db.FindStateDifferences ("00", "5df5affc07120335089525e82ec9fda60c6dccd7addb667106fb79de80610519");
+  BOOST_CHECK_EQUAL (msg->state_size(), 2);
+  BOOST_CHECK_EQUAL (msg->state (0).type (), SyncState::UPDATE);
+  BOOST_CHECK_EQUAL (msg->state (0).seq (), 2);
+
+  BOOST_CHECK_EQUAL (msg->state (1).type (), SyncState::UPDATE);
+  BOOST_CHECK_EQUAL (msg->state (1).seq (), 1);
+
+  remove_all (tmpdir);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/wscript b/tests/wscript
new file mode 100644
index 0000000..4de283c
--- /dev/null
+++ b/tests/wscript
@@ -0,0 +1,25 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+top = '..'
+
+from waflib import Logs
+
+def build(bld):
+    Logs.error("Unit tests are temporary disabled")
+    return
+
+    bld(features='cxx',
+        target='unit-tests-main',
+        name='unit-tests-main',
+        source='main.cpp',
+        use='BOOST',
+        defines=['BOOST_TEST_MODULE=CHRONOSHARE Unit Test'])
+
+    unit_tests = bld.program(
+            target='../unit-tests',
+            features='cxx cxxprogram',
+            source=bld.path.ant_glob(['**/*.cpp'], excl=['main.cpp']),
+            use='unit-tests-main',
+            install_path=None,
+            defines='UNIT_TEST_CONFIG_PATH=\"%s/tmp-files/\"' % (bld.bldnode)
+          )