blob: 05f9764d658b18d00cc8bda7dc055ed17bb1ae3d [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Lijing Wange0dd63e2015-05-31 16:25:16 -07003 * Copyright (c) 2013-2017, Regents of the University of California.
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08004 *
5 * This file is part of ChronoShare, a decentralized file sharing application over NDN.
6 *
7 * ChronoShare is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
10 *
11 * ChronoShare is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License along with
16 * ChronoShare, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ChronoShare authors and contributors.
19 */
Lijing Wange0dd63e2015-05-31 16:25:16 -070020
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080021#include "fs-watcher.hpp"
Lijing Wange0dd63e2015-05-31 16:25:16 -070022#include "test-common.hpp"
23
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080024#include <boost/bind.hpp>
Zhenkai Zhud1756272013-02-01 17:02:18 -080025#include <boost/filesystem.hpp>
Lijing Wange0dd63e2015-05-31 16:25:16 -070026#include <boost/filesystem/fstream.hpp>
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080027#include <boost/lexical_cast.hpp>
28#include <boost/make_shared.hpp>
Zhenkai Zhud1756272013-02-01 17:02:18 -080029#include <boost/test/unit_test.hpp>
30#include <boost/thread/thread.hpp>
Zhenkai Zhud1756272013-02-01 17:02:18 -080031#include <fstream>
Lijing Wange0dd63e2015-05-31 16:25:16 -070032#include <iostream>
33#include <thread>
Zhenkai Zhud1756272013-02-01 17:02:18 -080034#include <set>
Zhenkai Zhud1756272013-02-01 17:02:18 -080035
Lijing Wange0dd63e2015-05-31 16:25:16 -070036#include "fs-watcher.t.hpp"
37
Zhenkai Zhud1756272013-02-01 17:02:18 -080038using namespace std;
Zhenkai Zhud1756272013-02-01 17:02:18 -080039namespace fs = boost::filesystem;
40
Lijing Wange0dd63e2015-05-31 16:25:16 -070041_LOG_INIT(Test.FSWatcher);
Zhenkai Zhud1756272013-02-01 17:02:18 -080042
Lijing Wange0dd63e2015-05-31 16:25:16 -070043namespace ndn {
44namespace chronoshare {
45namespace tests {
46
47fsWatcherApp::fsWatcherApp(int& argc, char** argv)
48 : QCoreApplication(argc, argv)
Zhenkai Zhud1756272013-02-01 17:02:18 -080049{
Lijing Wange0dd63e2015-05-31 16:25:16 -070050 connect(this, SIGNAL(stopApp()), this, SLOT(quit()), Qt::QueuedConnection);
Zhenkai Zhud1756272013-02-01 17:02:18 -080051}
52
Lijing Wange0dd63e2015-05-31 16:25:16 -070053fsWatcherApp::~fsWatcherApp() = default;
Zhenkai Zhud1756272013-02-01 17:02:18 -080054
Lijing Wange0dd63e2015-05-31 16:25:16 -070055class TestFSWatcherFixture : public IdentityManagementFixture
Zhenkai Zhud1756272013-02-01 17:02:18 -080056{
Lijing Wange0dd63e2015-05-31 16:25:16 -070057public:
58 TestFSWatcherFixture()
59 : dir(fs::path(UNIT_TEST_CONFIG_PATH) / "TestFsWatcher")
60 , argc(0)
61 {
62 if (fs::exists(dir)) {
63 fs::remove_all(dir);
64 }
65
66 fs::create_directory(dir);
Zhenkai Zhud1756272013-02-01 17:02:18 -080067 }
Zhenkai Zhud1756272013-02-01 17:02:18 -080068
Lijing Wange0dd63e2015-05-31 16:25:16 -070069 ~TestFSWatcherFixture(){
70 // cleanup
71 if (fs::exists(dir)) {
72 _LOG_DEBUG("clean all");
73 fs::remove_all(dir);
74 }
75 }
76
77 void
78 advanceClocks(std::chrono::seconds delay)
79 {
80 std::chrono::milliseconds step = delay;
81 step /= 50;
82 for (int i = 0; i < 50; ++i) {
83 std::this_thread::sleep_for(step);
84 m_io.poll();
85 m_io.reset();
86 }
87 }
88
89 void
90 onChange(set<string>& files, const fs::path& file)
91 {
92 _LOG_DEBUG("on change, file: " << file);
93 files.insert(file.string());
94 }
95
96 void
97 onDelete(set<string>& files, const fs::path& file)
98 {
99 _LOG_DEBUG("on delete, file: " << file);
100 files.erase(file.string());
101 }
102
103 void
104 create_file(const fs::path& ph, const std::string& contents)
105 {
106 std::ofstream f(ph.string().c_str());
107 if (!f) {
108 abort();
109 }
110 if (!contents.empty()) {
111 f << contents;
112 }
113 }
114
115 void
116 run()
117 {
118 app = new fsWatcherApp(argc, nullptr);
119 new FsWatcher(m_io, dir.string().c_str(),
120 std::bind(&TestFSWatcherFixture::onChange, this, std::ref(files), _1),
121 std::bind(&TestFSWatcherFixture::onDelete, this, std::ref(files), _1),
122 app);
123 app->exec();
124 }
125
126public:
127 fs::path dir;
128 set<string> files;
129 int argc;
130 fsWatcherApp* app;
131};
132
133BOOST_FIXTURE_TEST_SUITE(TestFsWatcher, TestFSWatcherFixture)
Zhenkai Zhud1756272013-02-01 17:02:18 -0800134
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800135BOOST_AUTO_TEST_CASE(TestFsWatcher)
Zhenkai Zhud1756272013-02-01 17:02:18 -0800136{
Lijing Wange0dd63e2015-05-31 16:25:16 -0700137 std::thread workThread(boost::bind(&TestFSWatcherFixture::run, this));
138 this->advanceClocks(std::chrono::seconds(2));
Zhenkai Zhud1756272013-02-01 17:02:18 -0800139
140 // ============ check create file detection ================
141 create_file(dir / "test.txt", "hello");
Lijing Wange0dd63e2015-05-31 16:25:16 -0700142 this->advanceClocks(std::chrono::seconds(2));
Zhenkai Zhud1756272013-02-01 17:02:18 -0800143 // test.txt
144 BOOST_CHECK_EQUAL(files.size(), 1);
145 BOOST_CHECK(files.find("test.txt") != files.end());
146
147 // =========== check create a bunch of files in sub dir =============
148 fs::path subdir = dir / "sub";
149 fs::create_directory(subdir);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800150 for (int i = 0; i < 10; i++) {
Zhenkai Zhud1756272013-02-01 17:02:18 -0800151 string filename = boost::lexical_cast<string>(i);
152 create_file(subdir / filename.c_str(), boost::lexical_cast<string>(i));
153 }
Lijing Wange0dd63e2015-05-31 16:25:16 -0700154 this->advanceClocks(std::chrono::seconds(2));
Zhenkai Zhud1756272013-02-01 17:02:18 -0800155 // test.txt
156 // sub/0..9
157 BOOST_CHECK_EQUAL(files.size(), 11);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800158 for (int i = 0; i < 10; i++) {
Zhenkai Zhud1756272013-02-01 17:02:18 -0800159 string filename = boost::lexical_cast<string>(i);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800160 BOOST_CHECK(files.find("sub/" + filename) != files.end());
Zhenkai Zhud1756272013-02-01 17:02:18 -0800161 }
162
163 // ============== check copy directory with files to two levels of sub dirs =================
164 fs::create_directory(dir / "sub1");
165 fs::path subdir1 = dir / "sub1" / "sub2";
166 fs::copy_directory(subdir, subdir1);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800167 for (int i = 0; i < 5; i++) {
Zhenkai Zhud1756272013-02-01 17:02:18 -0800168 string filename = boost::lexical_cast<string>(i);
Lijing Wange0dd63e2015-05-31 16:25:16 -0700169 fs::copy(subdir / filename.c_str(), subdir1 / filename.c_str());
Zhenkai Zhud1756272013-02-01 17:02:18 -0800170 }
Lijing Wange0dd63e2015-05-31 16:25:16 -0700171 this->advanceClocks(std::chrono::seconds(2));
Zhenkai Zhud1756272013-02-01 17:02:18 -0800172 // test.txt
173 // sub/0..9
174 // sub1/sub2/0..4
175 BOOST_CHECK_EQUAL(files.size(), 16);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800176 for (int i = 0; i < 5; i++) {
Zhenkai Zhud1756272013-02-01 17:02:18 -0800177 string filename = boost::lexical_cast<string>(i);
178 BOOST_CHECK(files.find("sub1/sub2/" + filename) != files.end());
179 }
180
181 // =============== check remove files =========================
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800182 for (int i = 0; i < 7; i++) {
Zhenkai Zhud1756272013-02-01 17:02:18 -0800183 string filename = boost::lexical_cast<string>(i);
184 fs::remove(subdir / filename.c_str());
185 }
Lijing Wange0dd63e2015-05-31 16:25:16 -0700186 this->advanceClocks(std::chrono::seconds(2));
Zhenkai Zhud1756272013-02-01 17:02:18 -0800187 // test.txt
188 // sub/7..9
189 // sub1/sub2/0..4
190 BOOST_CHECK_EQUAL(files.size(), 9);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800191 for (int i = 0; i < 10; i++) {
Zhenkai Zhud1756272013-02-01 17:02:18 -0800192 string filename = boost::lexical_cast<string>(i);
193 if (i < 7)
194 BOOST_CHECK(files.find("sub/" + filename) == files.end());
195 else
196 BOOST_CHECK(files.find("sub/" + filename) != files.end());
197 }
198
Lijing Wange0dd63e2015-05-31 16:25:16 -0700199 // =================== check remove files again, remove the whole dir this time
200 // ===================
Zhenkai Zhud1756272013-02-01 17:02:18 -0800201 // before remove check
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800202 for (int i = 0; i < 5; i++) {
Zhenkai Zhud1756272013-02-01 17:02:18 -0800203 string filename = boost::lexical_cast<string>(i);
204 BOOST_CHECK(files.find("sub1/sub2/" + filename) != files.end());
205 }
206 fs::remove_all(subdir1);
Lijing Wange0dd63e2015-05-31 16:25:16 -0700207 this->advanceClocks(std::chrono::seconds(2));
Zhenkai Zhud1756272013-02-01 17:02:18 -0800208 BOOST_CHECK_EQUAL(files.size(), 4);
209 // test.txt
210 // sub/7..9
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800211 for (int i = 0; i < 5; i++) {
Zhenkai Zhud1756272013-02-01 17:02:18 -0800212 string filename = boost::lexical_cast<string>(i);
213 BOOST_CHECK(files.find("sub1/sub2/" + filename) == files.end());
214 }
215
216 // =================== check rename files =======================
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800217 for (int i = 7; i < 10; i++) {
Zhenkai Zhud1756272013-02-01 17:02:18 -0800218 string filename = boost::lexical_cast<string>(i);
219 fs::rename(subdir / filename.c_str(), dir / filename.c_str());
220 }
Lijing Wange0dd63e2015-05-31 16:25:16 -0700221 this->advanceClocks(std::chrono::seconds(2));
Zhenkai Zhud1756272013-02-01 17:02:18 -0800222 // test.txt
223 // 7
224 // 8
225 // 9
226 // sub
227 BOOST_CHECK_EQUAL(files.size(), 4);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800228 for (int i = 7; i < 10; i++) {
Zhenkai Zhud1756272013-02-01 17:02:18 -0800229 string filename = boost::lexical_cast<string>(i);
230 BOOST_CHECK(files.find("sub/" + filename) == files.end());
231 BOOST_CHECK(files.find(filename) != files.end());
232 }
233
Alexander Afanasyeva3230632013-02-07 16:24:30 -0800234 create_file(dir / "add-removal-check.txt", "add-removal-check");
Lijing Wange0dd63e2015-05-31 16:25:16 -0700235 this->advanceClocks(std::chrono::seconds(2));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800236 BOOST_CHECK(files.find("add-removal-check.txt") != files.end());
Zhenkai Zhud1756272013-02-01 17:02:18 -0800237
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800238 fs::remove(dir / "add-removal-check.txt");
Lijing Wange0dd63e2015-05-31 16:25:16 -0700239 this->advanceClocks(std::chrono::seconds(2));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800240 BOOST_CHECK(files.find("add-removal-check.txt") == files.end());
Alexander Afanasyeva3230632013-02-07 16:24:30 -0800241
242 create_file(dir / "add-removal-check.txt", "add-removal-check");
Lijing Wange0dd63e2015-05-31 16:25:16 -0700243 this->advanceClocks(std::chrono::seconds(2));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800244 BOOST_CHECK(files.find("add-removal-check.txt") != files.end());
Alexander Afanasyeva3230632013-02-07 16:24:30 -0800245
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800246 fs::remove(dir / "add-removal-check.txt");
Lijing Wange0dd63e2015-05-31 16:25:16 -0700247 this->advanceClocks(std::chrono::seconds(2));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800248 BOOST_CHECK(files.find("add-removal-check.txt") == files.end());
Alexander Afanasyeva3230632013-02-07 16:24:30 -0800249
250 create_file(dir / "add-removal-check.txt", "add-removal-check");
Lijing Wange0dd63e2015-05-31 16:25:16 -0700251 this->advanceClocks(std::chrono::seconds(2));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800252 BOOST_CHECK(files.find("add-removal-check.txt") != files.end());
Alexander Afanasyeva3230632013-02-07 16:24:30 -0800253
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800254 fs::remove(dir / "add-removal-check.txt");
Lijing Wange0dd63e2015-05-31 16:25:16 -0700255 this->advanceClocks(std::chrono::seconds(2));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800256 BOOST_CHECK(files.find("add-removal-check.txt") == files.end());
Alexander Afanasyeva3230632013-02-07 16:24:30 -0800257
Lijing Wange0dd63e2015-05-31 16:25:16 -0700258 emit app->stopApp();
259
260 workThread.join();
Zhenkai Zhud1756272013-02-01 17:02:18 -0800261}
262
263BOOST_AUTO_TEST_SUITE_END()
Lijing Wange0dd63e2015-05-31 16:25:16 -0700264
265} // namespace tests
266} // namespace chronoshare
267} // namespace ndn