testfolderwatcher.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * This software is in the public domain, furnished "as is", without technical
  3. * support, and with no warranty, express or implied, as to its usefulness for
  4. * any purpose.
  5. *
  6. */
  7. #include <QtTest>
  8. #include "folderwatcher.h"
  9. #include "common/utility.h"
  10. void touch(const QString &file)
  11. {
  12. #ifdef Q_OS_WIN
  13. OCC::Utility::writeRandomFile(file);
  14. #else
  15. QString cmd;
  16. cmd = QString("touch %1").arg(file);
  17. qDebug() << "Command: " << cmd;
  18. system(cmd.toLocal8Bit());
  19. #endif
  20. }
  21. void mkdir(const QString &file)
  22. {
  23. #ifdef Q_OS_WIN
  24. QDir dir;
  25. dir.mkdir(file);
  26. #else
  27. QString cmd = QString("mkdir %1").arg(file);
  28. qDebug() << "Command: " << cmd;
  29. system(cmd.toLocal8Bit());
  30. #endif
  31. }
  32. void rmdir(const QString &file)
  33. {
  34. #ifdef Q_OS_WIN
  35. QDir dir;
  36. dir.rmdir(file);
  37. #else
  38. QString cmd = QString("rmdir %1").arg(file);
  39. qDebug() << "Command: " << cmd;
  40. system(cmd.toLocal8Bit());
  41. #endif
  42. }
  43. void rm(const QString &file)
  44. {
  45. #ifdef Q_OS_WIN
  46. QFile::remove(file);
  47. #else
  48. QString cmd = QString("rm %1").arg(file);
  49. qDebug() << "Command: " << cmd;
  50. system(cmd.toLocal8Bit());
  51. #endif
  52. }
  53. void mv(const QString &file1, const QString &file2)
  54. {
  55. #ifdef Q_OS_WIN
  56. QFile::rename(file1, file2);
  57. #else
  58. QString cmd = QString("mv %1 %2").arg(file1, file2);
  59. qDebug() << "Command: " << cmd;
  60. system(cmd.toLocal8Bit());
  61. #endif
  62. }
  63. using namespace OCC;
  64. class TestFolderWatcher : public QObject
  65. {
  66. Q_OBJECT
  67. QTemporaryDir _root;
  68. QString _rootPath;
  69. QScopedPointer<FolderWatcher> _watcher;
  70. QScopedPointer<QSignalSpy> _pathChangedSpy;
  71. bool waitForPathChanged(const QString &path)
  72. {
  73. QElapsedTimer t;
  74. t.start();
  75. while (t.elapsed() < 5000) {
  76. // Check if it was already reported as changed by the watcher
  77. for (int i = 0; i < _pathChangedSpy->size(); ++i) {
  78. const auto &args = _pathChangedSpy->at(i);
  79. if (args.first().toString() == path)
  80. return true;
  81. }
  82. // Wait a bit and test again (don't bother checking if we timed out or not)
  83. _pathChangedSpy->wait(200);
  84. }
  85. return false;
  86. }
  87. #ifdef Q_OS_LINUX
  88. #define CHECK_WATCH_COUNT(n) QCOMPARE(_watcher->testLinuxWatchCount(), (n))
  89. #else
  90. #define CHECK_WATCH_COUNT(n) do {} while (false)
  91. #endif
  92. public:
  93. TestFolderWatcher()
  94. {
  95. QDir rootDir(_root.path());
  96. _rootPath = rootDir.canonicalPath();
  97. qDebug() << "creating test directory tree in " << _rootPath;
  98. rootDir.mkpath("a1/b1/c1");
  99. rootDir.mkpath("a1/b1/c2");
  100. rootDir.mkpath("a1/b2/c1");
  101. rootDir.mkpath("a1/b3/c3");
  102. rootDir.mkpath("a2/b3/c3");
  103. Utility::writeRandomFile( _rootPath+"/a1/random.bin");
  104. Utility::writeRandomFile( _rootPath+"/a1/b2/todelete.bin");
  105. Utility::writeRandomFile( _rootPath+"/a2/renamefile");
  106. Utility::writeRandomFile( _rootPath+"/a1/movefile");
  107. _watcher.reset(new FolderWatcher);
  108. _watcher->init(_rootPath);
  109. _pathChangedSpy.reset(new QSignalSpy(_watcher.data(), &FolderWatcher::pathChanged));
  110. }
  111. int countFolders(const QString &path)
  112. {
  113. int n = 0;
  114. const auto entryList = QDir(path).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
  115. for (const auto &sub : entryList) {
  116. n += 1 + countFolders(path + '/' + sub);
  117. }
  118. return n;
  119. }
  120. private slots:
  121. void init()
  122. {
  123. _pathChangedSpy->clear();
  124. CHECK_WATCH_COUNT(countFolders(_rootPath) + 1);
  125. }
  126. void cleanup()
  127. {
  128. CHECK_WATCH_COUNT(countFolders(_rootPath) + 1);
  129. }
  130. void testACreate() { // create a new file
  131. QString file(_rootPath + "/foo.txt");
  132. QString cmd;
  133. cmd = QString("echo \"xyz\" > \"%1\"").arg(file);
  134. qDebug() << "Command: " << cmd;
  135. system(cmd.toLocal8Bit());
  136. QVERIFY(waitForPathChanged(file));
  137. }
  138. void testATouch() { // touch an existing file.
  139. QString file(_rootPath + "/a1/random.bin");
  140. touch(file);
  141. QVERIFY(waitForPathChanged(file));
  142. }
  143. void testMove3LevelDirWithFile() {
  144. QString file(_rootPath + "/a0/b/c/empty.txt");
  145. mkdir(_rootPath + "/a0");
  146. mkdir(_rootPath + "/a0/b");
  147. mkdir(_rootPath + "/a0/b/c");
  148. touch(file);
  149. mv(_rootPath + "/a0", _rootPath + "/a");
  150. QVERIFY(waitForPathChanged(_rootPath + "/a/b/c/empty.txt"));
  151. }
  152. void testCreateADir() {
  153. QString file(_rootPath+"/a1/b1/new_dir");
  154. mkdir(file);
  155. QVERIFY(waitForPathChanged(file));
  156. // Notifications from that new folder arrive too
  157. QString file2(_rootPath + "/a1/b1/new_dir/contained");
  158. touch(file2);
  159. QVERIFY(waitForPathChanged(file2));
  160. }
  161. void testRemoveADir() {
  162. QString file(_rootPath+"/a1/b3/c3");
  163. rmdir(file);
  164. QVERIFY(waitForPathChanged(file));
  165. }
  166. void testRemoveAFile() {
  167. QString file(_rootPath+"/a1/b2/todelete.bin");
  168. QVERIFY(QFile::exists(file));
  169. rm(file);
  170. QVERIFY(!QFile::exists(file));
  171. QVERIFY(waitForPathChanged(file));
  172. }
  173. void testRenameAFile() {
  174. QString file1(_rootPath+"/a2/renamefile");
  175. QString file2(_rootPath+"/a2/renamefile.renamed");
  176. QVERIFY(QFile::exists(file1));
  177. mv(file1, file2);
  178. QVERIFY(QFile::exists(file2));
  179. QVERIFY(waitForPathChanged(file1));
  180. QVERIFY(waitForPathChanged(file2));
  181. }
  182. void testMoveAFile() {
  183. QString old_file(_rootPath+"/a1/movefile");
  184. QString new_file(_rootPath+"/a2/movefile.renamed");
  185. QVERIFY(QFile::exists(old_file));
  186. mv(old_file, new_file);
  187. QVERIFY(QFile::exists(new_file));
  188. QVERIFY(waitForPathChanged(old_file));
  189. QVERIFY(waitForPathChanged(new_file));
  190. }
  191. void testRenameDirectorySameBase() {
  192. QString old_file(_rootPath+"/a1/b1");
  193. QString new_file(_rootPath+"/a1/brename");
  194. QVERIFY(QFile::exists(old_file));
  195. mv(old_file, new_file);
  196. QVERIFY(QFile::exists(new_file));
  197. QVERIFY(waitForPathChanged(old_file));
  198. QVERIFY(waitForPathChanged(new_file));
  199. // Verify that further notifications end up with the correct paths
  200. QString file(_rootPath+"/a1/brename/c1/random.bin");
  201. touch(file);
  202. QVERIFY(waitForPathChanged(file));
  203. QString dir(_rootPath+"/a1/brename/newfolder");
  204. mkdir(dir);
  205. QVERIFY(waitForPathChanged(dir));
  206. }
  207. void testRenameDirectoryDifferentBase() {
  208. QString old_file(_rootPath+"/a1/brename");
  209. QString new_file(_rootPath+"/bren");
  210. QVERIFY(QFile::exists(old_file));
  211. mv(old_file, new_file);
  212. QVERIFY(QFile::exists(new_file));
  213. QVERIFY(waitForPathChanged(old_file));
  214. QVERIFY(waitForPathChanged(new_file));
  215. // Verify that further notifications end up with the correct paths
  216. QString file(_rootPath+"/bren/c1/random.bin");
  217. touch(file);
  218. QVERIFY(waitForPathChanged(file));
  219. QString dir(_rootPath+"/bren/newfolder2");
  220. mkdir(dir);
  221. QVERIFY(waitForPathChanged(dir));
  222. }
  223. };
  224. #ifdef Q_OS_MAC
  225. QTEST_MAIN(TestFolderWatcher)
  226. #else
  227. QTEST_GUILESS_MAIN(TestFolderWatcher)
  228. #endif
  229. #include "testfolderwatcher.moc"