add test for dispatcher;
synccore is not working in dispatcher;
additionally, localStateChanged not called somehow;
ccnx ccnLoop throws exception;
diff --git a/ccnx/ccnx-wrapper.h b/ccnx/ccnx-wrapper.h
index c1c9b9b..bdfdd2c 100644
--- a/ccnx/ccnx-wrapper.h
+++ b/ccnx/ccnx-wrapper.h
@@ -39,6 +39,8 @@
 class CcnxWrapper
 {
 public:
+  const static int MAX_FRESHNESS = 2147; // max value for ccnx
+  const static int DEFAULT_FRESHNESS = 60;
   typedef boost::function<void (const Name &)> InterestCallback;
 
   CcnxWrapper();
@@ -54,16 +56,16 @@
   sendInterest (const Name &interest, const Closure &closure, const Selectors &selector = Selectors());
 
   virtual int
-  publishData (const Name &name, const unsigned char *buf, size_t len, int freshness = 2147/* max value for ccnx*/);
+  publishData (const Name &name, const unsigned char *buf, size_t len, int freshness = DEFAULT_FRESHNESS/* max value for ccnx*/);
 
   int
-  publishData (const Name &name, const Bytes &content, int freshness = 2147/* max value for ccnx*/);
+  publishData (const Name &name, const Bytes &content, int freshness = DEFAULT_FRESHNESS/* max value for ccnx*/);
 
   static Name
   getLocalPrefix ();
 
   Bytes
-  createContentObject(const Name &name, const void *buf, size_t len, int freshness = 2147/* max value for ccnx*/);
+  createContentObject(const Name &name, const void *buf, size_t len, int freshness = DEFAULT_FRESHNESS/* max value for ccnx*/);
 
   int
   putToCcnd (const Bytes &contentObject);
diff --git a/src/dispatcher.cc b/src/dispatcher.cc
index babae92..8c93d96 100644
--- a/src/dispatcher.cc
+++ b/src/dispatcher.cc
@@ -38,7 +38,9 @@
                        , const std::string &sharedFolder
                        , const filesystem::path &rootDir
                        , Ccnx::CcnxWrapperPtr ccnx
-                       , int poolSize)
+                       , int poolSize
+                       , bool enablePrefixDiscovery
+                       )
            : m_ccnx(ccnx)
            , m_core(NULL)
            , m_rootDir(rootDir)
@@ -47,6 +49,7 @@
            , m_localUserName(localUserName)
            , m_sharedFolder(sharedFolder)
            , m_server(NULL)
+           , m_enablePrefixDiscovery(enablePrefixDiscovery)
 {
   m_syncLog = make_shared<SyncLog>(m_rootDir, localUserName);
   m_actionLog = make_shared<ActionLog>(m_ccnx, m_rootDir, m_syncLog, sharedFolder,
@@ -65,12 +68,18 @@
   m_actionFetcher = make_shared<FetchManager> (m_ccnx, bind (&SyncLog::LookupLocator, &*m_syncLog, _1), 3);
   m_fileFetcher   = make_shared<FetchManager> (m_ccnx, bind (&SyncLog::LookupLocator, &*m_syncLog, _1), 3);
 
-  Ccnx::CcnxDiscovery::registerCallback (TaggedFunction (bind (&Dispatcher::Did_LocalPrefix_Updated, this, _1), "dispatcher"));
+  if (m_enablePrefixDiscovery)
+  {
+    Ccnx::CcnxDiscovery::registerCallback (TaggedFunction (bind (&Dispatcher::Did_LocalPrefix_Updated, this, _1), "dispatcher"));
+  }
 }
 
 Dispatcher::~Dispatcher()
 {
-  Ccnx::CcnxDiscovery::deregisterCallback (TaggedFunction (bind (&Dispatcher::Did_LocalPrefix_Updated, this, _1), "dispatcher"));
+  if (m_enablePrefixDiscovery)
+  {
+    Ccnx::CcnxDiscovery::deregisterCallback (TaggedFunction (bind (&Dispatcher::Did_LocalPrefix_Updated, this, _1), "dispatcher"));
+  }
 
   if (m_core != NULL)
   {
@@ -109,6 +118,7 @@
 void
 Dispatcher::Did_LocalFile_AddOrModify_Execute (filesystem::path relativeFilePath)
 {
+  _LOG_DEBUG(m_localUserName << " calls LocalFile_AddOrModify_Execute");
   filesystem::path absolutePath = m_rootDir / relativeFilePath;
   if (!filesystem::exists(absolutePath))
     {
diff --git a/src/dispatcher.h b/src/dispatcher.h
index c2309b6..1bea184 100644
--- a/src/dispatcher.h
+++ b/src/dispatcher.h
@@ -50,7 +50,9 @@
              , const std::string &sharedFolder
              , const boost::filesystem::path &rootDir
              , Ccnx::CcnxWrapperPtr ccnx
-             , int poolSize = 2);
+             , int poolSize = 2
+             , bool enablePrefixDiscovery = true
+             );
   ~Dispatcher();
 
   // ----- Callbacks, they only submit the job to executor and immediately return so that event processing thread won't be blocked for too long -------
@@ -63,6 +65,10 @@
   void
   Did_LocalFile_Delete (const boost::filesystem::path &relativeFilepath);
 
+  // for test
+  HashPtr
+  SyncRoot() { return m_core->root(); }
+
 private:
   void
   Did_LocalFile_AddOrModify_Execute (boost::filesystem::path relativeFilepath); // cannot be const & for Execute event!!! otherwise there will be segfault
@@ -156,6 +162,7 @@
 
   std::string m_sharedFolder;
   ContentServer *m_server;
+  bool m_enablePrefixDiscovery;
 
   FetchManagerPtr m_actionFetcher;
   FetchManagerPtr m_fileFetcher;
diff --git a/src/sync-core.cc b/src/sync-core.cc
index a4ddfc6..80daac8 100644
--- a/src/sync-core.cc
+++ b/src/sync-core.cc
@@ -86,6 +86,7 @@
   BytesPtr syncData = serializeMsg (*msg);
 
   m_ccnx->publishData(syncName, *syncData, FRESHNESS);
+  _LOG_DEBUG (m_log->GetLocalName () << " localStateChanged ");
   _LOG_TRACE (m_log->GetLocalName () << " publishes: " << *oldHash);
   _LOG_TRACE (msg);
 
diff --git a/test/test-dispatcher.cc b/test/test-dispatcher.cc
new file mode 100644
index 0000000..6378cb2
--- /dev/null
+++ b/test/test-dispatcher.cc
@@ -0,0 +1,105 @@
+/* -*- 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 "ccnx-wrapper.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 Ccnx;
+using namespace std;
+using namespace boost;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE(DispatcherTest)
+
+
+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(TestDispatcher)
+{
+  fs::path dir1("test-white-house");
+  fs::path dir2("test-black-house");
+
+  string user1 = "/obama";
+  string user2 = "/romney";
+
+  string folder = "who-is-president";
+
+  CcnxWrapperPtr ccnx1 = make_shared<CcnxWrapper>();
+  usleep(1000);
+  CcnxWrapperPtr ccnx2 = make_shared<CcnxWrapper>();
+  usleep(1000);
+
+  cleanDir(dir1);
+  cleanDir(dir2);
+
+  fs::create_directory(dir1);
+  fs::create_directory(dir2);
+
+  Dispatcher d1(user1, folder, dir1, ccnx1, 2, false);
+  usleep(1000);
+  Dispatcher d2(user2, folder, dir2, ccnx2, 2, false);
+
+  sleep(1);
+
+  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());
+  ofs << words;
+  ofs.close();
+
+  d1.Did_LocalFile_AddOrModify(filename);
+
+  sleep(2);
+
+  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()