build: Upgrade build system
This commit also disables almost all build targets, as they are broken now
diff --git a/test/unit-tests/test-action-log.cc b/test/unit-tests/test-action-log.cc
new file mode 100644
index 0000000..86eb059
--- /dev/null
+++ b/test/unit-tests/test-action-log.cc
@@ -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/test/unit-tests/test-dispatcher.cc b/test/unit-tests/test-dispatcher.cc
new file mode 100644
index 0000000..b5c023b
--- /dev/null
+++ b/test/unit-tests/test-dispatcher.cc
@@ -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/test/unit-tests/test-event-scheduler.cc b/test/unit-tests/test-event-scheduler.cc
new file mode 100644
index 0000000..0d70abf
--- /dev/null
+++ b/test/unit-tests/test-event-scheduler.cc
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 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 "scheduler.h"
+#include "simple-interval-generator.h"
+#include "one-time-task.h"
+#include "periodic-task.h"
+#include "random-interval-generator.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/make_shared.hpp>
+#include <map>
+#include <unistd.h>
+
+using namespace boost;
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(SchedulerTests)
+
+map<string, int> table;
+
+void func(string str)
+{
+ map<string, int>::iterator it = table.find(str);
+ if (it == table.end())
+ {
+ table.insert(make_pair(str, 1));
+ }
+ else
+ {
+ int count = it->second;
+ count++;
+ table.erase(it);
+ table.insert(make_pair(str, count));
+ }
+}
+
+bool
+matcher(const TaskPtr &task)
+{
+ return task->tag() == "period" || task->tag() == "world";
+}
+
+BOOST_AUTO_TEST_CASE(SchedulerTest)
+{
+ SchedulerPtr scheduler(new Scheduler());
+ IntervalGeneratorPtr generator(new SimpleIntervalGenerator(0.2));
+
+ string tag1 = "hello";
+ string tag2 = "world";
+ string tag3 = "period";
+
+ TaskPtr task1(new OneTimeTask(boost::bind(func, tag1), tag1, scheduler, 0.5));
+ TaskPtr task2(new OneTimeTask(boost::bind(func, tag2), tag2, scheduler, 0.5));
+ TaskPtr task3(new PeriodicTask(boost::bind(func, tag3), tag3, scheduler, generator));
+
+ scheduler->start();
+ scheduler->addTask(task1);
+ scheduler->addTask(task2);
+ scheduler->addTask(task3);
+ BOOST_CHECK_EQUAL(scheduler->size(), 3);
+ usleep(600000);
+ BOOST_CHECK_EQUAL(scheduler->size(), 1);
+ scheduler->addTask(task1);
+ BOOST_CHECK_EQUAL(scheduler->size(), 2);
+ usleep(600000);
+ scheduler->addTask(task1);
+ BOOST_CHECK_EQUAL(scheduler->size(), 2);
+ usleep(400000);
+ scheduler->deleteTask(task1->tag());
+ BOOST_CHECK_EQUAL(scheduler->size(), 1);
+ usleep(200000);
+
+ scheduler->addTask(task1);
+ scheduler->addTask(task2);
+ BOOST_CHECK_EQUAL(scheduler->size(), 3);
+ usleep(100000);
+ scheduler->deleteTask(bind(matcher, _1));
+ BOOST_CHECK_EQUAL(scheduler->size(), 1);
+ usleep(1000000);
+
+ BOOST_CHECK_EQUAL(scheduler->size(), 0);
+ scheduler->addTask(task1);
+ usleep(400000);
+ BOOST_CHECK_EQUAL(scheduler->size(), 1);
+ scheduler->rescheduleTask(task1);
+ usleep(400000);
+ BOOST_CHECK_EQUAL(scheduler->size(), 1);
+ usleep(110000);
+ BOOST_CHECK_EQUAL(scheduler->size(), 0);
+
+
+ int hello = 0, world = 0, period = 0;
+
+ map<string, int>::iterator it;
+ it = table.find(tag1);
+ if (it != table.end())
+ {
+ hello = it->second;
+ }
+ it = table.find(tag2);
+ if (it != table.end())
+ {
+ world = it->second;
+ }
+ it = table.find(tag3);
+ if (it != table.end())
+ {
+ period = it->second;
+ }
+
+ // added five times, canceled once before invoking callback
+ BOOST_CHECK_EQUAL(hello, 4);
+ // added two times, canceled once by matcher before invoking callback
+ BOOST_CHECK_EQUAL(world, 1);
+ // invoked every 0.2 seconds before deleted by matcher
+ BOOST_CHECK_EQUAL(period, static_cast<int>((0.6 + 0.6 + 0.4 + 0.2 + 0.1) / 0.2));
+
+ scheduler->shutdown();
+}
+
+void reschedule();
+SchedulerPtr schd0(new Scheduler());
+int resCount;
+TaskPtr task0(new PeriodicTask(boost::bind(reschedule), "testtest", schd0, boost::make_shared<SimpleIntervalGenerator>(0.5)));
+void reschedule()
+{
+ schd0->rescheduleTask(task0);
+ resCount++;
+}
+
+BOOST_AUTO_TEST_CASE(RescheduleTest)
+{
+ resCount = 0;
+ schd0->start();
+ schd0->addTask(task0);
+ usleep(5100000);
+ BOOST_CHECK_EQUAL(resCount, 10);
+ schd0->shutdown();
+}
+
+BOOST_AUTO_TEST_CASE(GeneratorTest)
+{
+ double interval = 10;
+ double percent = 0.5;
+ int times = 10000;
+ IntervalGeneratorPtr generator(new RandomIntervalGenerator(interval, percent));
+ double sum = 0.0;
+ double min = 2 * interval;
+ double max = -1;
+ for (int i = 0; i < times; i++)
+ {
+ double next = generator->nextInterval();
+ sum += next;
+ if (next > max)
+ {
+ max = next;
+ }
+ if (next < min)
+ {
+ min = next;
+ }
+ }
+
+ BOOST_CHECK( abs(1.0 - (sum / static_cast<double>(times)) / interval) < 0.05);
+ BOOST_CHECK( min > interval * (1 - percent / 2.0));
+ BOOST_CHECK( max < interval * (1 + percent / 2.0));
+ BOOST_CHECK( abs(1.0 - ((max - min) / interval) / percent) < 0.05);
+
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/unit-tests/test-executor.cc b/test/unit-tests/test-executor.cc
new file mode 100644
index 0000000..a13f373
--- /dev/null
+++ b/test/unit-tests/test-executor.cc
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 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 <boost/test/unit_test.hpp>
+#include "executor.h"
+
+#include "logging.h"
+
+INIT_LOGGER ("Test.Executor");
+
+using namespace boost;
+using namespace std;
+
+void timeConsumingJob ()
+{
+ _LOG_DEBUG ("Start sleep");
+ sleep(1);
+ _LOG_DEBUG ("Finish sleep");
+}
+
+BOOST_AUTO_TEST_CASE(TestExecutor)
+{
+ INIT_LOGGERS ();
+
+ {
+ Executor executor (3);
+ executor.start ();
+ Executor::Job job = bind(timeConsumingJob);
+
+ executor.execute(job);
+ executor.execute(job);
+
+ usleep(2000);
+ // both jobs should have been taken care of
+ BOOST_CHECK_EQUAL(executor.jobQueueSize(), 0);
+
+ usleep(500000);
+
+ // add four jobs while only one thread is idle
+ executor.execute(job);
+ executor.execute(job);
+ executor.execute(job);
+ executor.execute(job);
+
+ usleep(1000);
+ // three jobs should remain in queue
+ BOOST_CHECK_EQUAL(executor.jobQueueSize(), 3);
+
+ usleep(500000);
+ // two threads should have finished and
+ // take care of two queued jobs
+ BOOST_CHECK_EQUAL(executor.jobQueueSize(), 1);
+
+ // all jobs should have been fetched
+ usleep(501000);
+ BOOST_CHECK_EQUAL(executor.jobQueueSize(), 0);
+
+ executor.shutdown ();
+ } //separate scope to ensure that destructor is called
+
+
+ sleep(1);
+}
diff --git a/test/unit-tests/test-fetch-manager.cc b/test/unit-tests/test-fetch-manager.cc
new file mode 100644
index 0000000..98c820a
--- /dev/null
+++ b/test/unit-tests/test-fetch-manager.cc
@@ -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/test/unit-tests/test-fetch-task-db.cc b/test/unit-tests/test-fetch-task-db.cc
new file mode 100644
index 0000000..61bec89
--- /dev/null
+++ b/test/unit-tests/test-fetch-task-db.cc
@@ -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/test/unit-tests/test-fs-watcher-delay.cc b/test/unit-tests/test-fs-watcher-delay.cc
new file mode 100644
index 0000000..a44bde1
--- /dev/null
+++ b/test/unit-tests/test-fs-watcher-delay.cc
@@ -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/test/unit-tests/test-fs-watcher.cc b/test/unit-tests/test-fs-watcher.cc
new file mode 100644
index 0000000..d943903
--- /dev/null
+++ b/test/unit-tests/test-fs-watcher.cc
@@ -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/test/unit-tests/test-ndnx-name.cc b/test/unit-tests/test-ndnx-name.cc
new file mode 100644
index 0000000..a876ba4
--- /dev/null
+++ b/test/unit-tests/test-ndnx-name.cc
@@ -0,0 +1,49 @@
+
+#include "ccnx-name.h"
+
+#define BOOST_TEST_MAIN 1
+
+#include <boost/test/unit_test.hpp>
+
+using namespace Ccnx;
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(CcnxNameTests)
+
+BOOST_AUTO_TEST_CASE (CcnxNameTest)
+{
+ Name empty = Name();
+ Name root = Name("/");
+ BOOST_CHECK_EQUAL(empty, root);
+ BOOST_CHECK_EQUAL(empty, "/");
+ BOOST_CHECK_EQUAL(root.size(), 0);
+ empty.appendComp("hello");
+ empty.appendComp("world");
+ BOOST_CHECK_EQUAL(empty.size(), 2);
+ BOOST_CHECK_EQUAL(empty.toString(), "/hello/world");
+ empty = empty + root;
+ BOOST_CHECK_EQUAL(empty.toString(), "/hello/world");
+ BOOST_CHECK_EQUAL(empty.getCompAsString(0), "hello");
+ BOOST_CHECK_EQUAL(empty.getPartialName(1, 1), Name("/world"));
+ Name name("/hello/world");
+ BOOST_CHECK_EQUAL(empty, name);
+ BOOST_CHECK_EQUAL(name, Name("/hello") + Name("/world"));
+
+
+ name.appendComp (1);
+ name.appendComp (255);
+ name.appendComp (256);
+ name.appendComp (1234567890);
+
+ BOOST_CHECK_EQUAL (name.toString (), "/hello/world/%00%01/%00%ff/%00%00%01/%00%d2%02%96I");
+
+ BOOST_CHECK_EQUAL (name.getCompAsInt (5), 1234567890);
+ BOOST_CHECK_EQUAL (name.getCompAsInt (4), 256);
+ BOOST_CHECK_EQUAL (name.getCompAsInt (3), 255);
+ BOOST_CHECK_EQUAL (name.getCompAsInt (2), 1);
+
+ // Charbuf related stuff will be checked in other place
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/unit-tests/test-ndnx-wrapper.cc b/test/unit-tests/test-ndnx-wrapper.cc
new file mode 100644
index 0000000..9989cdb
--- /dev/null
+++ b/test/unit-tests/test-ndnx-wrapper.cc
@@ -0,0 +1,253 @@
+/* -*- 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 "ccnx-closure.h"
+#include "ccnx-name.h"
+#include "ccnx-selectors.h"
+#include "ccnx-pco.h"
+#include <unistd.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/make_shared.hpp>
+
+using namespace Ccnx;
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(TestCcnxWrapper)
+
+CcnxWrapperPtr c1;
+CcnxWrapperPtr c2;
+int g_timeout_counter = 0;
+int g_dataCallback_counter = 0;
+
+void publish1(const Name &name)
+{
+ string content = name.toString();
+ c1->publishData(name, (const unsigned char*)content.c_str(), content.size(), 5);
+}
+
+void publish2(const Name &name)
+{
+ string content = name.toString();
+ c2->publishData(name, (const unsigned char*)content.c_str(), content.size(), 5);
+}
+
+void dataCallback(const Name &name, Ccnx::PcoPtr pco)
+{
+ cout << " in data callback" << endl;
+ BytesPtr content = pco->contentPtr ();
+ string msg(reinterpret_cast<const char *> (head (*content)), content->size());
+ g_dataCallback_counter ++;
+ BOOST_CHECK_EQUAL(name, msg);
+}
+
+void encapCallback(const Name &name, Ccnx::PcoPtr pco)
+{
+ cout << " in encap data callback" << endl;
+ BOOST_CHECK(!c1->verify(pco));
+ cout << "++++++++++++++++++ Outer content couldn't be verified, which is expected." << endl;
+ PcoPtr npco = make_shared<ParsedContentObject> (*(pco->contentPtr()));
+ g_dataCallback_counter ++;
+ BOOST_CHECK(npco);
+ BOOST_CHECK(c1->verify(npco));
+}
+
+void
+timeout(const Name &name, const Closure &closure, Selectors selectors)
+{
+ g_timeout_counter ++;
+}
+
+void
+setup()
+{
+ if (!c1)
+ {
+ c1 = make_shared<CcnxWrapper> ();
+ }
+ if (!c2)
+ {
+ c2 = make_shared<CcnxWrapper> ();
+ }
+}
+
+void
+teardown()
+{
+ if (c1)
+ {
+ c1.reset();
+ }
+ if (c2)
+ {
+ c2.reset();
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE (BlaCcnxWrapperTest)
+{
+ INIT_LOGGERS ();
+
+ setup();
+ Name prefix1("/c1");
+ Name prefix2("/c2");
+
+ c1->setInterestFilter(prefix1, bind(publish1, _1));
+ usleep(100000);
+ c2->setInterestFilter(prefix2, bind(publish2, _1));
+
+ Closure closure (bind(dataCallback, _1, _2), bind(timeout, _1, _2, _3));
+
+ c1->sendInterest(Name("/c2/hi"), closure);
+ usleep(100000);
+ c2->sendInterest(Name("/c1/hi"), closure);
+ sleep(1);
+ BOOST_CHECK_EQUAL(g_dataCallback_counter, 2);
+ // reset
+ g_dataCallback_counter = 0;
+ g_timeout_counter = 0;
+
+ teardown();
+}
+
+BOOST_AUTO_TEST_CASE (CcnxWrapperSelector)
+{
+
+ setup();
+ Closure closure (bind(dataCallback, _1, _2), bind(timeout, _1, _2, _3));
+
+ Selectors selectors;
+ selectors
+ .interestLifetime(1)
+ .childSelector(Selectors::RIGHT);
+
+ string n1 = "/random/01";
+ c1->sendInterest(Name(n1), closure, selectors);
+ sleep(2);
+ c2->publishData(Name(n1), (const unsigned char *)n1.c_str(), n1.size(), 1);
+ 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(), 1);
+ 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;
+
+ teardown();
+
+}
+
+void
+reexpress(const Name &name, const Closure &closure, Selectors selectors)
+{
+ g_timeout_counter ++;
+ c1->sendInterest(name, closure, selectors);
+}
+
+BOOST_AUTO_TEST_CASE (TestTimeout)
+{
+ setup();
+ g_dataCallback_counter = 0;
+ g_timeout_counter = 0;
+ Closure closure (bind(dataCallback, _1, _2), bind(reexpress, _1, _2, _3));
+
+ Selectors selectors;
+ selectors.interestLifetime(1);
+
+ string n1 = "/random/04";
+ c1->sendInterest(Name(n1), closure, selectors);
+ usleep(3500000);
+ c2->publishData(Name(n1), (const unsigned char *)n1.c_str(), n1.size(), 1);
+ usleep(100000);
+ BOOST_CHECK_EQUAL(g_dataCallback_counter, 1);
+ BOOST_CHECK_EQUAL(g_timeout_counter, 3);
+ teardown();
+}
+
+BOOST_AUTO_TEST_CASE (TestUnsigned)
+{
+ setup();
+ string n1 = "/xxxxxx/unsigned/01";
+ Closure closure (bind(dataCallback, _1, _2), bind(timeout, _1, _2, _3));
+
+ g_dataCallback_counter = 0;
+ c1->sendInterest(Name(n1), closure);
+ usleep(100000);
+ c2->publishUnsignedData(Name(n1), (const unsigned char *)n1.c_str(), n1.size(), 1);
+ usleep(100000);
+ BOOST_CHECK_EQUAL(g_dataCallback_counter, 1);
+
+ string n2 = "/xxxxxx/signed/01";
+ Bytes content = c1->createContentObject(Name(n1), (const unsigned char *)n2.c_str(), n2.size(), 1);
+ c1->publishUnsignedData(Name(n2), head(content), content.size(), 1);
+ Closure encapClosure(bind(encapCallback, _1, _2), bind(timeout, _1, _2, _3));
+ c2->sendInterest(Name(n2), encapClosure);
+ usleep(4000000);
+ BOOST_CHECK_EQUAL(g_dataCallback_counter, 2);
+ teardown();
+}
+
+
+ /*
+ BOOST_AUTO_TEST_CASE (CcnxWrapperUnsigningTest)
+ {
+ setup();
+ Bytes data;
+ data.resize(1024);
+ for (int i = 0; i < 1024; i++)
+ {
+ data[i] = 'm';
+ }
+
+ Name name("/unsigningtest");
+
+ posix_time::ptime start = posix_time::second_clock::local_time();
+ for (uint64_t i = 0; i < 100000; i++)
+ {
+ Name n = name;
+ n.appendComp(i);
+ c1->publishUnsignedData(n, data, 10);
+ }
+ posix_time::ptime end = posix_time::second_clock::local_time();
+
+ posix_time::time_duration duration = end - start;
+
+ cout << "Publishing 100000 1K size content objects costs " <<duration.total_milliseconds() << " milliseconds" << endl;
+ cout << "Average time to publish one content object is " << (double) duration.total_milliseconds() / 100000.0 << " milliseconds" << endl;
+ teardown();
+ }
+ */
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/unit-tests/test-object-manager.cc b/test/unit-tests/test-object-manager.cc
new file mode 100644
index 0000000..60f0c58
--- /dev/null
+++ b/test/unit-tests/test-object-manager.cc
@@ -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/test/unit-tests/test-protobuf.cc b/test/unit-tests/test-protobuf.cc
new file mode 100644
index 0000000..d0a7b8e
--- /dev/null
+++ b/test/unit-tests/test-protobuf.cc
@@ -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/test/unit-tests/test-serve-and-fetch.cc b/test/unit-tests/test-serve-and-fetch.cc
new file mode 100644
index 0000000..8e54404
--- /dev/null
+++ b/test/unit-tests/test-serve-and-fetch.cc
@@ -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/test/unit-tests/test-sync-core.cc b/test/unit-tests/test-sync-core.cc
new file mode 100644
index 0000000..04f560a
--- /dev/null
+++ b/test/unit-tests/test-sync-core.cc
@@ -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/test/unit-tests/test-sync-log.cc b/test/unit-tests/test-sync-log.cc
new file mode 100644
index 0000000..8ac36b1
--- /dev/null
+++ b/test/unit-tests/test-sync-log.cc
@@ -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()