053-scan_task.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #include "catch.hpp"
  2. #include "test-utils.h"
  3. #include "fs/scan_task.h"
  4. using namespace syncspirit;
  5. using namespace syncspirit::test;
  6. using namespace syncspirit::utils;
  7. using namespace syncspirit::model;
  8. using namespace syncspirit::fs;
  9. TEST_CASE("scan_task", "[fs]") {
  10. utils::set_default("trace");
  11. auto root_path = bfs::unique_path();
  12. bfs::create_directories(root_path);
  13. path_guard_t path_quard{root_path};
  14. config::fs_config_t config{0 , 3600};
  15. auto my_id = device_id_t::from_string("KHQNO2S-5QSILRK-YX4JZZ4-7L77APM-QNVGZJT-EKU7IFI-PNEPBMY-4MXFMQD").value();
  16. auto my_device = device_t::create(my_id, "my-device").value();
  17. auto peer_id = device_id_t::from_string("VUV42CZ-IQD5A37-RPEBPM4-VVQK6E4-6WSKC7B-PVJQHHD-4PZD44V-ENC6WAZ").value();
  18. auto peer_device = device_t::create(peer_id, "peer-device").value();
  19. auto cluster = cluster_ptr_t(new cluster_t(my_device, 1));
  20. cluster->get_devices().put(my_device);
  21. cluster->get_devices().put(peer_device);
  22. auto db_folder = db::Folder();
  23. db_folder.set_id("some-id");
  24. db_folder.set_label("zzz");
  25. db_folder.set_path(root_path.string());
  26. auto folder = folder_t::create(cluster->next_uuid(), db_folder).value();
  27. cluster->get_folders().put(folder);
  28. db::FolderInfo db_folder_info;
  29. db_folder_info.set_index_id(1234);
  30. db_folder_info.set_max_sequence(3);
  31. auto folder_my = folder_info_t::create(cluster->next_uuid(), db_folder_info, my_device, folder).value();
  32. auto folder_peer = folder_info_t::create(cluster->next_uuid(), db_folder_info, peer_device, folder).value();
  33. folder->get_folder_infos().put(folder_my);
  34. folder->get_folder_infos().put(folder_peer);
  35. SECTION("without files") {
  36. SECTION("non-existing dir => err") {
  37. db_folder.set_path("/some/non-existing/path");
  38. folder = folder_t::create(cluster->next_uuid(), db_folder).value();
  39. cluster->get_folders().put(folder);
  40. auto folder_info = folder_info_t::create(cluster->next_uuid(), db_folder_info, my_device, folder).value();
  41. folder->get_folder_infos().put(folder_info);
  42. auto task = scan_task_t(cluster, folder->get_id(), config);
  43. auto r = task.advance();
  44. CHECK(std::get_if<io_errors_t>(&r));
  45. auto errs = std::get_if<io_errors_t>(&r);
  46. REQUIRE(errs->size() == 1);
  47. auto& err = errs->at(0);
  48. CHECK(err.ec);
  49. CHECK(err.path.string() == db_folder.path());
  50. }
  51. SECTION("no dirs, no files") {
  52. auto task = scan_task_t(cluster, folder->get_id(), config);
  53. auto r = task.advance();
  54. CHECK(std::get_if<bool>(&r));
  55. CHECK(*std::get_if<bool>(&r) == true);
  56. r = task.advance();
  57. CHECK(std::get_if<bool>(&r));
  58. CHECK(*std::get_if<bool>(&r) == false);
  59. }
  60. SECTION("some dirs, no files") {
  61. auto task = scan_task_t(cluster, folder->get_id(), config);
  62. auto dir = root_path / "some-dir";
  63. bfs::create_directories(dir);
  64. auto r = task.advance();
  65. CHECK(std::get_if<bool>(&r));
  66. CHECK(*std::get_if<bool>(&r) == true);
  67. r = task.advance();
  68. CHECK(std::get_if<bool>(&r));
  69. CHECK(*std::get_if<bool>(&r) == true);
  70. r = task.advance();
  71. CHECK(std::get_if<bool>(&r));
  72. CHECK(*std::get_if<bool>(&r) == false);
  73. }
  74. SECTION("no dirs, file outside of recorded is ignored") {
  75. auto task = scan_task_t(cluster, folder->get_id(), config);
  76. write_file(root_path / "some-file", "");
  77. auto r = task.advance();
  78. CHECK(std::get_if<bool>(&r));
  79. CHECK(*std::get_if<bool>(&r) == true);
  80. r = task.advance();
  81. CHECK(std::get_if<bool>(&r));
  82. CHECK(*std::get_if<bool>(&r) == false);
  83. }
  84. }
  85. SECTION("files") {
  86. auto modified = std::time_t{1642007468};
  87. auto pr_file = proto::FileInfo{};
  88. pr_file.set_name("a.txt");
  89. pr_file.set_sequence(2);
  90. auto version = pr_file.mutable_version();
  91. auto counter = version->add_counters();
  92. counter->set_id(1);
  93. counter->set_value(peer_device->as_uint());
  94. SECTION("meta is not changed") {
  95. pr_file.set_block_size(5);
  96. pr_file.set_size(5);
  97. pr_file.set_modified_s(modified);
  98. auto path = root_path / "a.txt";
  99. write_file(path, "12345");
  100. bfs::last_write_time(path, modified);
  101. auto file = file_info_t::create(cluster->next_uuid(), pr_file, folder_my).value();
  102. folder_my->get_file_infos().put(file);
  103. auto task = scan_task_t(cluster, folder->get_id(), config);
  104. auto r = task.advance();
  105. CHECK(std::get_if<bool>(&r));
  106. CHECK(*std::get_if<bool>(&r) == true);
  107. r = task.advance();
  108. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  109. auto ref = std::get_if<unchanged_meta_t>(&r);
  110. CHECK(ref->file == file);
  111. r = task.advance();
  112. CHECK(std::get_if<bool>(&r));
  113. CHECK(*std::get_if<bool>(&r) == false);
  114. }
  115. SECTION("meta is changed") {
  116. auto task = scan_task_ptr_t{};
  117. auto file = file_info_ptr_t{};
  118. SECTION("file size differs") {
  119. pr_file.set_block_size(5);
  120. pr_file.set_size(6);
  121. pr_file.set_modified_s(modified);
  122. auto path = root_path / "a.txt";
  123. write_file(path, "12345");
  124. bfs::last_write_time(path, modified);
  125. file = file_info_t::create(cluster->next_uuid(), pr_file, folder_my).value();
  126. folder_my->get_file_infos().put(file);
  127. }
  128. SECTION("modification time differs") {
  129. pr_file.set_block_size(5);
  130. pr_file.set_size(5);
  131. pr_file.set_modified_s(modified + 1);
  132. auto path = root_path / "a.txt";
  133. write_file(path, "12345");
  134. bfs::last_write_time(path, modified);
  135. file = file_info_t::create(cluster->next_uuid(), pr_file, folder_my).value();
  136. folder_my->get_file_infos().put(file);
  137. }
  138. task = new scan_task_t(cluster, folder->get_id(), config);
  139. auto r = task->advance();
  140. CHECK(std::get_if<bool>(&r));
  141. CHECK(*std::get_if<bool>(&r) == true);
  142. r = task->advance();
  143. REQUIRE(std::get_if<changed_meta_t>(&r));
  144. auto ref = std::get_if<changed_meta_t>(&r);
  145. CHECK(ref->file == file);
  146. r = task->advance();
  147. CHECK(std::get_if<bool>(&r));
  148. CHECK(*std::get_if<bool>(&r) == false);
  149. }
  150. SECTION("tmp") {
  151. pr_file.set_block_size(5);
  152. pr_file.set_size(5);
  153. pr_file.set_modified_s(modified);
  154. auto path = root_path / "a.txt.syncspirit-tmp";
  155. SECTION("size match -> ok, will recalc") {
  156. write_file(path, "12345");
  157. auto file_my = file_info_t::create(cluster->next_uuid(), pr_file, folder_my).value();
  158. auto file_peer = file_info_t::create(cluster->next_uuid(), pr_file, folder_peer).value();
  159. folder_my->get_file_infos().put(file_my);
  160. folder_peer->get_file_infos().put(file_peer);
  161. file_my->set_source(file_peer);
  162. auto task = scan_task_t(cluster, folder->get_id(), config);
  163. auto r = task.advance();
  164. CHECK(std::get_if<bool>(&r));
  165. CHECK(*std::get_if<bool>(&r) == true);
  166. r = task.advance();
  167. REQUIRE(std::get_if<incomplete_t>(&r));
  168. auto ref = std::get_if<incomplete_t>(&r);
  169. CHECK(ref->file);
  170. r = task.advance();
  171. CHECK(std::get_if<bool>(&r));
  172. CHECK(*std::get_if<bool>(&r) == false);
  173. }
  174. SECTION("source is missing") {
  175. write_file(path, "12345");
  176. auto file_my = file_info_t::create(cluster->next_uuid(), pr_file, folder_my).value();
  177. folder_my->get_file_infos().put(file_my);
  178. auto task = scan_task_t(cluster, folder->get_id(), config);
  179. auto r = task.advance();
  180. CHECK(std::get_if<bool>(&r));
  181. CHECK(*std::get_if<bool>(&r) == true);
  182. r = task.advance();
  183. CHECK(std::get_if<bool>(&r));
  184. CHECK(*std::get_if<bool>(&r) == true);
  185. r = task.advance();
  186. CHECK(std::get_if<bool>(&r));
  187. CHECK(*std::get_if<bool>(&r) == false);
  188. }
  189. SECTION("size mismatch -> remove & ignore") {
  190. write_file(path, "123456");
  191. auto file_my = file_info_t::create(cluster->next_uuid(), pr_file, folder_my).value();
  192. auto file_peer = file_info_t::create(cluster->next_uuid(), pr_file, folder_peer).value();
  193. folder_my->get_file_infos().put(file_my);
  194. folder_peer->get_file_infos().put(file_peer);
  195. file_my->set_source(file_peer);
  196. auto task = scan_task_t(cluster, folder->get_id(), config);
  197. auto r = task.advance();
  198. CHECK(std::get_if<bool>(&r));
  199. CHECK(*std::get_if<bool>(&r) == true);
  200. r = task.advance();
  201. CHECK(std::get_if<bool>(&r));
  202. CHECK(*std::get_if<bool>(&r) == true);
  203. r = task.advance();
  204. CHECK(std::get_if<bool>(&r));
  205. CHECK(*std::get_if<bool>(&r) == false);
  206. CHECK(!bfs::exists(path));
  207. }
  208. }
  209. SECTION("tmp & non-tmp: both are returned") {
  210. pr_file.set_block_size(5);
  211. pr_file.set_size(5);
  212. pr_file.set_modified_s(modified);
  213. auto file_my = file_info_t::create(cluster->next_uuid(), pr_file, folder_my).value();
  214. counter->set_id(10);
  215. auto file_peer = file_info_t::create(cluster->next_uuid(), pr_file, folder_peer).value();
  216. folder_my->get_file_infos().put(file_my);
  217. folder_peer->get_file_infos().put(file_peer);
  218. file_my->set_source(file_peer);
  219. auto path = root_path / "a.txt";
  220. auto path_tmp = root_path / "a.txt.syncspirit-tmp";
  221. write_file(path, "12345");
  222. write_file(path_tmp, "12345");
  223. bfs::last_write_time(path, modified);
  224. auto task = scan_task_t(cluster, folder->get_id(), config);
  225. auto r = task.advance();
  226. CHECK(std::get_if<bool>(&r));
  227. CHECK(*std::get_if<bool>(&r) == true);
  228. unchanged_meta_t unchanged;
  229. incomplete_t incomplete;
  230. for(int i = 0; i < 2; ++i) {
  231. r = task.advance();
  232. std::visit([&](auto&& it){
  233. using T = std::decay_t<decltype(it)>;
  234. if constexpr (std::is_same_v<T, unchanged_meta_t>) {
  235. unchanged = it;
  236. } else if constexpr (std::is_same_v<T, incomplete_t>) {
  237. incomplete = it;
  238. } else {
  239. REQUIRE((0 && "unexpected result"));
  240. }
  241. }, r);
  242. }
  243. CHECK(unchanged.file == file_my);
  244. CHECK(incomplete.file);
  245. r = task.advance();
  246. CHECK(std::get_if<bool>(&r));
  247. CHECK(*std::get_if<bool>(&r) == false);
  248. }
  249. SECTION("cannot read dir, error") {
  250. pr_file.set_name("some/a.txt");
  251. auto path = root_path / "some" / "a.txt";
  252. auto parent = path.parent_path();
  253. write_file(path, "12345");
  254. bfs::permissions(parent, bfs::perms::no_perms);
  255. auto file = file_info_t::create(cluster->next_uuid(), pr_file, folder_my).value();
  256. folder_my->get_file_infos().put(file);
  257. auto task = scan_task_t(cluster, folder->get_id(), config);
  258. auto r = task.advance();
  259. CHECK(std::get_if<bool>(&r));
  260. CHECK(*std::get_if<bool>(&r) == true);
  261. r = task.advance();
  262. REQUIRE(std::get_if<scan_errors_t>(&r));
  263. auto errs = std::get_if<scan_errors_t>(&r);
  264. REQUIRE(errs);
  265. REQUIRE(errs->size() == 1);
  266. REQUIRE(errs->at(0).path == parent);
  267. REQUIRE(errs->at(0).ec);
  268. r = task.advance();
  269. CHECK(std::get_if<bool>(&r));
  270. CHECK(*std::get_if<bool>(&r) == false);
  271. bfs::permissions(parent, bfs::perms::all_all);
  272. }
  273. }
  274. }