blob: 22b1838d50da9c985047d1aa99af779e9c748b2d [file] [log] [blame]
/* -*- 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.
*/
#include "fs-watcher.hpp"
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <QtGui>
#include <fstream>
#include <set>
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()