tests[ChronoShare]: Create integrated tests for ChronoShare

Change-Id: If3f2a803b41dedb060971d07d9564e9ec5f77f4b
diff --git a/tests/integrated-tests/chronoshare.cpp b/tests/integrated-tests/chronoshare.cpp
new file mode 100644
index 0000000..415f24d
--- /dev/null
+++ b/tests/integrated-tests/chronoshare.cpp
@@ -0,0 +1,281 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+#define BOOST_TEST_MAIN 1
+#define BOOST_TEST_DYN_LINK 1
+#define BOOST_TEST_MODULE ChronoShare Integrated Tests (ChronoShare)
+
+#include "gui/chronosharegui.hpp"
+#include "test-common.hpp"
+#include "dummy-forwarder.hpp"
+
+#include <boost/make_shared.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/bind.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/lexical_cast.hpp>
+#include <thread>
+#include <chrono>
+
+namespace ndn {
+namespace chronoshare {
+namespace tests {
+
+using namespace std;
+namespace fs = boost::filesystem;
+
+_LOG_INIT(Test.Integrated.ChronoShare);
+
+class ChronoShareFixture : public IdentityManagementFixture
+{
+public:
+  ChronoShareFixture()
+    : forwarder(m_io, m_keyChain)
+    , folder("sharefolder")
+    , dir1(fs::path(fs::path(UNIT_TEST_CONFIG_PATH) / "sharefolder1"))
+    , dir2(fs::path(fs::path(UNIT_TEST_CONFIG_PATH) / "sharefolder2"))
+    , argc(0)
+  {
+
+    if (fs::exists(dir1)) {
+      fs::remove_all(dir1);
+    }
+
+    if (fs::exists(dir2)) {
+      fs::remove_all(dir2);
+    }
+
+    fs::create_directory(dir1);
+    fs::create_directory(dir2);
+  }
+
+  ~ChronoShareFixture()
+  {
+    //delete app;
+    // cleanup
+    if (fs::exists(dir1)) {
+      fs::remove_all(dir1);
+    }
+
+    // cleanup
+    if (fs::exists(dir2)) {
+      fs::remove_all(dir2);
+    }
+  }
+
+  void
+  advanceClocks(std::chrono::seconds delay)
+  {
+    std::chrono::milliseconds step = delay;
+    step /= 50;
+    for (int i = 0; i < 50; ++i) {
+      std::this_thread::sleep_for(step);
+      m_io.poll();
+      m_io.reset();
+    }
+  }
+
+  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()
+  {
+      std::this_thread::sleep_for(std::chrono::seconds(5));
+
+      _LOG_DEBUG("======created files===========");
+      create_file(dir1 / folder / "test.txt", "hello");
+
+      std::this_thread::sleep_for(std::chrono::seconds(10));
+
+
+      BOOST_REQUIRE_MESSAGE(fs::exists(dir2 / folder / "test.txt"), "user1 failed to notify user2 about test.txt");
+      BOOST_CHECK_EQUAL(fs::file_size(dir1 / folder / "test.txt"), fs::file_size(dir2 / folder / "test.txt"));
+
+
+      fs::path subdir1 = dir1 / folder / "sub";
+      fs::path subdir2 = dir2 / folder / "sub";
+      fs::create_directory(subdir1);
+      for (int i = 0; i < 10; i++) {
+        string filename = boost::lexical_cast<string>(i);
+        create_file(subdir1 / filename.c_str(), boost::lexical_cast<string>(i));
+      }
+
+      std::this_thread::sleep_for(std::chrono::seconds(10));
+      for (int i = 0; i < 10; i++) {
+        string filename = boost::lexical_cast<string>(i);
+        BOOST_REQUIRE_MESSAGE(fs::exists(subdir2 / filename), "user1 failed to notify user2 about"<< filename);
+      }
+
+      //=========check copy file to sub directory==========
+      fs::create_directory(dir1 / folder / "sub1");
+      fs::path subsubdir1 = dir1 / folder / "sub1" / "sub2";
+      fs::path subsubdir2 = dir2 / folder / "sub1" / "sub2";
+      fs::copy_directory(subdir1, subsubdir1);
+      for (int i = 0; i < 5; i++) {
+        string filename = boost::lexical_cast<string>(i);
+        fs::copy(subdir1 / filename.c_str(), subsubdir1 / filename.c_str());
+      }
+
+      std::this_thread::sleep_for(std::chrono::seconds(10));
+      // test.txt
+      // sub/0..9
+      // sub1/sub2/0..4
+      for (int i = 0; i < 5; i++) {
+        string filename = boost::lexical_cast<string>(i);
+        BOOST_REQUIRE_MESSAGE(fs::exists(subsubdir2 / filename), "user1 failed to notify user2 about"<< filename);
+      }
+
+      // =============== check remove files =========================
+      for (int i = 0; i < 7; i++) {
+        string filename = boost::lexical_cast<string>(i);
+        fs::remove(subdir1 / filename.c_str());
+      }
+
+      std::this_thread::sleep_for(std::chrono::seconds(10));
+      // test.txt
+      // sub/7..9
+      // sub1/sub2/0..4
+      for (int i = 0; i < 10; i++) {
+        string filename = boost::lexical_cast<string>(i);
+        if (i < 7)
+          BOOST_REQUIRE_MESSAGE(!fs::exists(subdir2 / filename), "user1 failed to notify user2 about"<< filename);
+        else
+          BOOST_REQUIRE_MESSAGE(fs::exists(subdir2 / filename), "user1 failed to notify user2 about"<< filename);
+      }
+
+      // =================== 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_REQUIRE_MESSAGE(fs::exists(subsubdir2 / filename), "user1 failed to notify user2 about"<< filename);
+      }
+      fs::remove_all(subsubdir1);
+
+      std::this_thread::sleep_for(std::chrono::seconds(10));
+      // test.txt
+      // sub/7..9
+      BOOST_REQUIRE_MESSAGE(!fs::exists(subsubdir2), "user1 failed to notify user2 about sub1/sub2");
+
+      // =================== check rename files =======================
+      for (int i = 7; i < 10; i++) {
+        string filename = boost::lexical_cast<string>(i);
+        fs::rename(subdir1 / filename.c_str(), dir1 / folder / filename.c_str());
+      }
+      std::this_thread::sleep_for(std::chrono::seconds(10));
+      // test.txt
+      // 7
+      // 8
+      // 9
+      // sub
+      for (int i = 7; i < 10; i++) {
+        string filename = boost::lexical_cast<string>(i);
+
+        BOOST_REQUIRE_MESSAGE(!fs::exists(subdir2 / filename), "user1 failed to notify user2 about"<< filename);
+        BOOST_REQUIRE_MESSAGE(fs::exists(dir2 / folder / filename), "user1 failed to notify user2 about"<< filename);
+      }
+
+      create_file(dir1 / folder / "add-removal-check.txt", "add-removal-check");
+      std::this_thread::sleep_for(std::chrono::seconds(4));
+      BOOST_REQUIRE_MESSAGE(fs::exists(dir2 / folder / "add-removal-check.txt"),
+                            "user1 failed to notify user2 about add-removal-check.txt");
+
+      fs::remove(dir1 / folder / "add-removal-check.txt");
+      std::this_thread::sleep_for(std::chrono::seconds(4));
+      BOOST_REQUIRE_MESSAGE(!fs::exists(dir2 / folder / "add-removal-check.txt"),
+                            "user1 failed to notify user2 about add-removal-check.txt");
+
+      create_file(dir1 / folder / "add-removal-check.txt", "add-removal-check");
+      std::this_thread::sleep_for(std::chrono::seconds(4));
+      BOOST_REQUIRE_MESSAGE(fs::exists(dir2 / folder / "add-removal-check.txt"),
+                            "user1 failed to notify user2 about add-removal-check.txt");
+
+      fs::remove(dir1 / folder / "add-removal-check.txt");
+      std::this_thread::sleep_for(std::chrono::seconds(4));
+      BOOST_REQUIRE_MESSAGE(!fs::exists(dir2 / folder / "add-removal-check.txt"),
+                            "user1 failed to notify user2 about add-removal-check.txt");
+
+      create_file(dir1 / folder / "add-removal-check.txt", "add-removal-check");
+      std::this_thread::sleep_for(std::chrono::seconds(4));
+      BOOST_REQUIRE_MESSAGE(fs::exists(dir2 / folder / "add-removal-check.txt"),
+                            "user1 failed to notify user2 about add-removal-check.txt");
+
+      fs::remove(dir1 / folder / "add-removal-check.txt");
+      std::this_thread::sleep_for(std::chrono::seconds(4));
+      BOOST_REQUIRE_MESSAGE(!fs::exists(dir2 / folder / "add-removal-check.txt"),
+                            "user1 failed to notify user2 about add-removal-check.txt");
+
+      _LOG_DEBUG("======finish thread===========");
+  }
+
+public:
+  DummyForwarder forwarder;
+  std::string folder;
+  fs::path dir1;
+  fs::path dir2;
+
+  int argc;
+  //TestApp* app;
+};
+
+BOOST_FIXTURE_TEST_SUITE(TestChronoShare, ChronoShareFixture)
+
+BOOST_AUTO_TEST_CASE(Chronoshare)
+{
+  QApplication app(argc, nullptr);
+
+  // do not quit when last window closes
+  app.setQuitOnLastWindowClosed(false);
+  // invoke gui
+  ndn::chronoshare::ChronoShareGui gui1(QString::fromStdString(dir1.generic_string()),
+                                        QString::fromStdString("user1"),
+                                        QString::fromStdString("sharefolder"));
+
+  // invoke gui
+  ndn::chronoshare::ChronoShareGui gui2(QString::fromStdString(dir2.generic_string()),
+                                        QString::fromStdString("user2"),
+                                        QString::fromStdString("sharefolder"));
+
+  QTimer::singleShot(95000, &app, SLOT(quit()));
+
+  _LOG_DEBUG("run thread");
+  std::thread workThread(boost::bind(&ChronoShareFixture::run, this));
+
+  app.exec();
+  workThread.join();
+  _LOG_DEBUG("thread finished");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace chronoshare
+} // namespace ndn