070-db.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. // SPDX-FileCopyrightText: 2019-2024 Ivan Baidakou
  3. #include <catch2/catch_all.hpp>
  4. #include "test-utils.h"
  5. #include "diff-builder.h"
  6. #include "model/diff/peer/cluster_update.h"
  7. #include "model/diff/peer/peer_state.h"
  8. #include "test_supervisor.h"
  9. #include "access.h"
  10. #include "model/cluster.h"
  11. #include "db/utils.h"
  12. #include "net/db_actor.h"
  13. #include "access.h"
  14. #include <boost/filesystem.hpp>
  15. using namespace syncspirit;
  16. using namespace syncspirit::db;
  17. using namespace syncspirit::test;
  18. using namespace syncspirit::model;
  19. using namespace syncspirit::net;
  20. namespace fs = boost::filesystem;
  21. namespace {
  22. struct env {};
  23. } // namespace
  24. namespace syncspirit::net {
  25. template <> inline auto &db_actor_t::access<env>() noexcept { return env; }
  26. } // namespace syncspirit::net
  27. namespace {
  28. struct fixture_t {
  29. using msg_t = net::message::load_cluster_response_t;
  30. using msg_ptr_t = r::intrusive_ptr_t<msg_t>;
  31. fixture_t() noexcept : root_path{bfs::unique_path()}, path_quard{root_path} { utils::set_default("trace"); }
  32. virtual supervisor_t::configure_callback_t configure() noexcept {
  33. return [&](r::plugin::plugin_base_t &plugin) {
  34. plugin.template with_casted<r::plugin::starter_plugin_t>(
  35. [&](auto &p) { p.subscribe_actor(r::lambda<msg_t>([&](msg_t &msg) { reply = &msg; })); });
  36. };
  37. }
  38. cluster_ptr_t make_cluster() noexcept {
  39. auto my_id =
  40. device_id_t::from_string("KHQNO2S-5QSILRK-YX4JZZ4-7L77APM-QNVGZJT-EKU7IFI-PNEPBMY-4MXFMQD").value();
  41. my_device = device_t::create(my_id, "my-device").value();
  42. return cluster_ptr_t(new cluster_t(my_device, 1, 1));
  43. }
  44. virtual void run() noexcept {
  45. auto peer_id =
  46. device_id_t::from_string("VUV42CZ-IQD5A37-RPEBPM4-VVQK6E4-6WSKC7B-PVJQHHD-4PZD44V-ENC6WAZ").value();
  47. peer_device = device_t::create(peer_id, "peer-device").value();
  48. cluster = make_cluster();
  49. auto root_path = bfs::unique_path();
  50. bfs::create_directory(root_path);
  51. auto root_path_guard = path_guard_t(root_path);
  52. r::system_context_t ctx;
  53. sup = ctx.create_supervisor<supervisor_t>().timeout(timeout).create_registry().finish();
  54. sup->cluster = cluster;
  55. sup->configure_callback = configure();
  56. sup->start();
  57. sup->do_process();
  58. CHECK(static_cast<r::actor_base_t *>(sup.get())->access<to::state>() == r::state_t::OPERATIONAL);
  59. auto db_config = config::db_config_t{1024 * 1024, 0};
  60. db_actor = sup->create_actor<db_actor_t>()
  61. .cluster(cluster)
  62. .db_dir(root_path.string())
  63. .db_config(db_config)
  64. .timeout(timeout)
  65. .finish();
  66. sup->do_process();
  67. CHECK(static_cast<r::actor_base_t *>(db_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  68. db_addr = db_actor->get_address();
  69. main();
  70. reply.reset();
  71. sup->shutdown();
  72. sup->do_process();
  73. CHECK(static_cast<r::actor_base_t *>(sup.get())->access<to::state>() == r::state_t::SHUT_DOWN);
  74. }
  75. virtual void main() noexcept {}
  76. r::address_ptr_t db_addr;
  77. r::pt::time_duration timeout = r::pt::millisec{10};
  78. cluster_ptr_t cluster;
  79. device_ptr_t peer_device;
  80. device_ptr_t my_device;
  81. r::intrusive_ptr_t<supervisor_t> sup;
  82. r::intrusive_ptr_t<net::db_actor_t> db_actor;
  83. bfs::path root_path;
  84. path_guard_t path_quard;
  85. r::system_context_t ctx;
  86. msg_ptr_t reply;
  87. };
  88. } // namespace
  89. void test_db_migration() {
  90. struct F : fixture_t {
  91. void main() noexcept override {
  92. auto &db_env = db_actor->access<env>();
  93. auto txn_opt = db::make_transaction(db::transaction_type_t::RW, db_env);
  94. REQUIRE(txn_opt);
  95. auto &txn = txn_opt.value();
  96. auto load_opt = db::load(db::prefix::device, txn);
  97. REQUIRE(load_opt);
  98. auto &values = load_opt.value();
  99. REQUIRE(values.size() == 1);
  100. }
  101. };
  102. F().run();
  103. }
  104. void test_loading_empty_db() {
  105. struct F : fixture_t {
  106. void main() noexcept override {
  107. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  108. sup->do_process();
  109. REQUIRE(reply);
  110. auto diff = reply->payload.res.diff;
  111. REQUIRE(diff->apply(*cluster));
  112. auto devices = cluster->get_devices();
  113. REQUIRE(devices.size() == 1);
  114. REQUIRE(devices.by_sha256(cluster->get_device()->device_id().get_sha256()));
  115. }
  116. };
  117. F().run();
  118. }
  119. void test_folder_creation() {
  120. struct F : fixture_t {
  121. void main() noexcept override {
  122. auto folder_id = "1234-5678";
  123. auto builder = diff_builder_t(*cluster);
  124. builder.create_folder(folder_id, "/my/path", "my-label").apply(*sup);
  125. auto folder = cluster->get_folders().by_id(folder_id);
  126. REQUIRE(folder);
  127. REQUIRE(folder->get_folder_infos().by_device(*cluster->get_device()));
  128. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  129. sup->do_process();
  130. REQUIRE(reply);
  131. auto cluster_clone = make_cluster();
  132. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  133. auto folder_clone = cluster_clone->get_folders().by_id(folder->get_id());
  134. REQUIRE(folder_clone);
  135. REQUIRE(folder.get() != folder_clone.get());
  136. REQUIRE(folder_clone->get_label() == "my-label");
  137. REQUIRE(folder_clone->get_path().string() == "/my/path");
  138. REQUIRE(folder_clone->get_folder_infos().size() == 1);
  139. REQUIRE(folder_clone->get_folder_infos().by_device(*cluster->get_device()));
  140. }
  141. };
  142. F().run();
  143. }
  144. void test_peer_updating() {
  145. struct F : fixture_t {
  146. void main() noexcept override {
  147. auto sha256 = peer_device->device_id().get_sha256();
  148. auto builder = diff_builder_t(*cluster);
  149. builder.update_peer(sha256, "some_name", "some-cn", true).apply(*sup);
  150. auto device = cluster->get_devices().by_sha256(sha256);
  151. REQUIRE(device);
  152. CHECK(device->get_name() == "some_name");
  153. CHECK(device->get_cert_name() == "some-cn");
  154. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  155. sup->do_process();
  156. REQUIRE(reply);
  157. auto cluster_clone = make_cluster();
  158. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  159. REQUIRE(cluster_clone->get_devices().size() == 2);
  160. auto device_clone = cluster_clone->get_devices().by_sha256(sha256);
  161. REQUIRE(device_clone);
  162. REQUIRE(device.get() != device_clone.get());
  163. CHECK(device_clone->get_name() == "some_name");
  164. CHECK(device_clone->get_cert_name() == "some-cn");
  165. }
  166. };
  167. F().run();
  168. }
  169. void test_folder_sharing() {
  170. struct F : fixture_t {
  171. void main() noexcept override {
  172. auto sha256 = peer_device->device_id().get_sha256();
  173. auto folder_id = "1234-5678";
  174. auto builder = diff_builder_t(*cluster);
  175. builder.update_peer(sha256)
  176. .apply(*sup)
  177. .create_folder(folder_id, "/my/path")
  178. .configure_cluster(sha256)
  179. .add(sha256, folder_id, 5, 4)
  180. .finish()
  181. .share_folder(sha256, folder_id)
  182. .apply(*sup);
  183. CHECK(static_cast<r::actor_base_t *>(db_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  184. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  185. sup->do_process();
  186. REQUIRE(reply);
  187. auto cluster_clone = make_cluster();
  188. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  189. auto peer_device = cluster_clone->get_devices().by_sha256(sha256);
  190. REQUIRE(peer_device);
  191. auto folder = cluster_clone->get_folders().by_id(folder_id);
  192. REQUIRE(folder);
  193. REQUIRE(folder->get_folder_infos().size() == 2);
  194. auto fi = folder->get_folder_infos().by_device(*peer_device);
  195. REQUIRE(fi);
  196. CHECK(fi->get_index() == 5);
  197. CHECK(fi->get_max_sequence() == 4);
  198. }
  199. };
  200. F().run();
  201. }
  202. void test_cluster_update_and_remove() {
  203. struct F : fixture_t {
  204. void main() noexcept override {
  205. auto sha256 = peer_device->device_id().get_sha256();
  206. auto folder_id = "1234-5678";
  207. auto unknown_folder_id = "5678-999";
  208. auto file = proto::FileInfo();
  209. file.set_name("a.txt");
  210. file.set_size(5ul);
  211. file.set_block_size(5ul);
  212. file.set_sequence(6ul);
  213. auto b = file.add_blocks();
  214. b->set_size(5ul);
  215. b->set_hash(utils::sha256_digest("12345").value());
  216. auto builder = diff_builder_t(*cluster);
  217. builder.update_peer(sha256)
  218. .apply(*sup)
  219. .create_folder(folder_id, "/my/path")
  220. .configure_cluster(sha256)
  221. .add(sha256, folder_id, 5, file.sequence())
  222. .add(sha256, unknown_folder_id, 5, 5)
  223. .finish()
  224. .share_folder(sha256, folder_id)
  225. .apply(*sup)
  226. .make_index(sha256, folder_id)
  227. .add(file)
  228. .finish()
  229. .apply(*sup);
  230. REQUIRE(cluster->get_blocks().size() == 1);
  231. auto block = cluster->get_blocks().get(b->hash());
  232. REQUIRE(block);
  233. auto folder = cluster->get_folders().by_id(folder_id);
  234. auto peer_folder_info = folder->get_folder_infos().by_device(*peer_device);
  235. REQUIRE(peer_folder_info);
  236. CHECK(peer_folder_info->get_max_sequence() == 6ul);
  237. REQUIRE(peer_folder_info->get_file_infos().size() == 1);
  238. auto peer_file = peer_folder_info->get_file_infos().by_name("a.txt");
  239. REQUIRE(peer_file);
  240. auto &unknown_folders = cluster->get_unknown_folders();
  241. CHECK(std::distance(unknown_folders.begin(), unknown_folders.end()) == 1);
  242. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  243. sup->do_process();
  244. REQUIRE(reply);
  245. REQUIRE(!reply->payload.ee);
  246. auto cluster_clone = make_cluster();
  247. {
  248. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  249. REQUIRE(cluster_clone->get_blocks().size() == 1);
  250. CHECK(cluster_clone->get_blocks().get(b->hash()));
  251. auto folder = cluster_clone->get_folders().by_id(folder_id);
  252. auto peer_folder_info = folder->get_folder_infos().by_device(*peer_device);
  253. REQUIRE(peer_folder_info);
  254. REQUIRE(peer_folder_info->get_file_infos().size() == 1);
  255. REQUIRE(peer_folder_info->get_file_infos().by_name("a.txt"));
  256. REQUIRE(!cluster_clone->get_unknown_folders().empty());
  257. }
  258. auto pr_msg = proto::ClusterConfig();
  259. auto pr_f = pr_msg.add_folders();
  260. pr_f->set_id(folder_id);
  261. auto pr_device = pr_f->add_devices();
  262. pr_device->set_id(std::string(peer_device->device_id().get_sha256()));
  263. pr_device->set_max_sequence(1);
  264. pr_device->set_index_id(peer_folder_info->get_index() + 1);
  265. auto diff = diff::peer::cluster_update_t::create(*cluster, *peer_device, pr_msg).value();
  266. sup->send<model::payload::model_update_t>(sup->get_address(), diff, nullptr);
  267. sup->do_process();
  268. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  269. sup->do_process();
  270. REQUIRE(reply);
  271. REQUIRE(!reply->payload.ee);
  272. cluster_clone = make_cluster();
  273. {
  274. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  275. REQUIRE(cluster_clone->get_blocks().size() == 0);
  276. auto &fis = cluster_clone->get_folders().by_id(folder_id)->get_folder_infos();
  277. REQUIRE(fis.size() == 2);
  278. auto folder_info = fis.by_device(*peer_device);
  279. REQUIRE(folder_info);
  280. REQUIRE(fis.by_device(*cluster->get_device()));
  281. REQUIRE(cluster_clone->get_unknown_folders().empty());
  282. }
  283. }
  284. };
  285. F().run();
  286. }
  287. void test_unsharing_folder() {
  288. struct F : fixture_t {
  289. void main() noexcept override {
  290. auto sha256 = peer_device->device_id().get_sha256();
  291. auto folder_id = "1234-5678";
  292. auto file = proto::FileInfo();
  293. file.set_name("a.txt");
  294. file.set_size(5ul);
  295. file.set_block_size(5ul);
  296. file.set_sequence(6ul);
  297. auto b = file.add_blocks();
  298. b->set_size(5ul);
  299. b->set_hash(utils::sha256_digest("12345").value());
  300. auto builder = diff_builder_t(*cluster);
  301. builder.update_peer(sha256)
  302. .apply(*sup)
  303. .create_folder(folder_id, "/my/path")
  304. .configure_cluster(sha256)
  305. .add(sha256, folder_id, 5, file.sequence())
  306. .finish()
  307. .share_folder(sha256, folder_id)
  308. .apply(*sup)
  309. .make_index(sha256, folder_id)
  310. .add(file)
  311. .finish()
  312. .apply(*sup);
  313. REQUIRE(cluster->get_blocks().size() == 1);
  314. auto block = cluster->get_blocks().get(b->hash());
  315. REQUIRE(block);
  316. auto folder = cluster->get_folders().by_id(folder_id);
  317. auto peer_folder_info = folder->get_folder_infos().by_device(*peer_device);
  318. REQUIRE(peer_folder_info);
  319. CHECK(peer_folder_info->get_max_sequence() == 6ul);
  320. REQUIRE(peer_folder_info->get_file_infos().size() == 1);
  321. auto peer_file = peer_folder_info->get_file_infos().by_name("a.txt");
  322. REQUIRE(peer_file);
  323. builder.unshare_folder(*peer_folder_info).apply(*sup);
  324. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  325. sup->do_process();
  326. REQUIRE(reply);
  327. REQUIRE(!reply->payload.ee);
  328. auto cluster_clone = make_cluster();
  329. {
  330. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  331. auto &fis = cluster_clone->get_folders().by_id(folder_id)->get_folder_infos();
  332. REQUIRE(fis.size() == 1);
  333. REQUIRE(!fis.by_device(*peer_device));
  334. REQUIRE(fis.by_device(*cluster->get_device()));
  335. REQUIRE(cluster_clone->get_blocks().size() == 0);
  336. }
  337. }
  338. };
  339. F().run();
  340. }
  341. void test_clone_file() {
  342. struct F : fixture_t {
  343. void main() noexcept override {
  344. auto sha256 = peer_device->device_id().get_sha256();
  345. auto folder_id = "1234-5678";
  346. auto file = proto::FileInfo();
  347. file.set_name("a.txt");
  348. file.set_sequence(6ul);
  349. auto version = file.mutable_version();
  350. auto counter = version->add_counters();
  351. counter->set_id(1);
  352. counter->set_value(peer_device->as_uint());
  353. auto builder = diff_builder_t(*cluster);
  354. builder.update_peer(sha256)
  355. .apply(*sup)
  356. .create_folder(folder_id, "/my/path")
  357. .configure_cluster(sha256)
  358. .add(sha256, folder_id, 5, file.sequence())
  359. .finish()
  360. .share_folder(sha256, folder_id)
  361. .apply(*sup);
  362. auto folder = cluster->get_folders().by_id(folder_id);
  363. auto folder_my = folder->get_folder_infos().by_device(*my_device);
  364. auto folder_peer = folder->get_folder_infos().by_device(*peer_device);
  365. SECTION("file without blocks") {
  366. builder.make_index(sha256, folder_id).add(file).finish().apply(*sup);
  367. auto file_peer = folder_peer->get_file_infos().by_name(file.name());
  368. REQUIRE(file_peer);
  369. builder.clone_file(*file_peer).apply(*sup);
  370. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  371. sup->do_process();
  372. REQUIRE(reply);
  373. REQUIRE(!reply->payload.ee);
  374. auto cluster_clone = make_cluster();
  375. {
  376. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  377. REQUIRE(cluster_clone->get_blocks().size() == 0);
  378. auto &fis = cluster_clone->get_folders().by_id(folder_id)->get_folder_infos();
  379. REQUIRE(fis.size() == 2);
  380. auto folder_info_clone = fis.by_device(*cluster_clone->get_device());
  381. auto file_clone = folder_info_clone->get_file_infos().by_name(file.name());
  382. REQUIRE(file_clone);
  383. REQUIRE(file_clone->get_name() == file.name());
  384. REQUIRE(file_clone->get_blocks().size() == 0);
  385. REQUIRE(file_clone->get_sequence() == 1);
  386. REQUIRE(!file_clone->get_source());
  387. REQUIRE(folder_info_clone->get_max_sequence() == 1);
  388. }
  389. }
  390. SECTION("file with blocks") {
  391. file.set_size(5ul);
  392. file.set_block_size(5ul);
  393. auto b = file.add_blocks();
  394. b->set_size(5ul);
  395. b->set_hash(utils::sha256_digest("12345").value());
  396. builder.make_index(sha256, folder_id).add(file).finish().apply(*sup);
  397. auto folder = cluster->get_folders().by_id(folder_id);
  398. auto folder_my = folder->get_folder_infos().by_device(*my_device);
  399. auto folder_peer = folder->get_folder_infos().by_device(*peer_device);
  400. auto file_peer = folder_peer->get_file_infos().by_name(file.name());
  401. REQUIRE(file_peer);
  402. builder.clone_file(*file_peer).apply(*sup);
  403. REQUIRE(folder_my->get_max_sequence() == 0);
  404. {
  405. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  406. sup->do_process();
  407. REQUIRE(reply);
  408. REQUIRE(!reply->payload.ee);
  409. auto cluster_clone = make_cluster();
  410. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  411. REQUIRE(cluster_clone->get_blocks().size() == 1);
  412. auto &fis = cluster_clone->get_folders().by_id(folder_id)->get_folder_infos();
  413. REQUIRE(fis.size() == 2);
  414. auto folder_info_clone = fis.by_device(*cluster_clone->get_device());
  415. auto file_clone = folder_info_clone->get_file_infos().by_name(file.name());
  416. REQUIRE(file_clone);
  417. REQUIRE(file_clone->get_name() == file.name());
  418. REQUIRE(file_clone->get_blocks().size() == 1);
  419. REQUIRE(file_clone->get_sequence() == 0);
  420. REQUIRE(folder_info_clone->get_max_sequence() == 0);
  421. }
  422. file_peer = folder_peer->get_file_infos().by_name(file.name());
  423. file_peer->mark_local_available(0);
  424. REQUIRE(file_peer->is_locally_available());
  425. auto file_my = folder_my->get_file_infos().by_name(file.name());
  426. builder.finish_file_ack(*file_my).apply(*sup);
  427. {
  428. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  429. sup->do_process();
  430. REQUIRE(reply);
  431. REQUIRE(!reply->payload.ee);
  432. auto cluster_clone = make_cluster();
  433. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  434. REQUIRE(cluster_clone->get_blocks().size() == 1);
  435. auto &fis = cluster_clone->get_folders().by_id(folder_id)->get_folder_infos();
  436. REQUIRE(fis.size() == 2);
  437. auto folder_info_clone = fis.by_device(*cluster_clone->get_device());
  438. auto file_clone = folder_info_clone->get_file_infos().by_name(file.name());
  439. REQUIRE(file_clone);
  440. REQUIRE(file_clone->get_name() == file.name());
  441. REQUIRE(file_clone->get_blocks().size() == 1);
  442. REQUIRE(file_clone->get_blocks().at(0));
  443. REQUIRE(file_clone->get_sequence() == 1);
  444. REQUIRE(folder_info_clone->get_max_sequence() == 1);
  445. }
  446. }
  447. }
  448. };
  449. F().run();
  450. }
  451. void test_local_update() {
  452. struct F : fixture_t {
  453. void main() noexcept override {
  454. auto folder_id = "1234-5678";
  455. auto pr_file = proto::FileInfo();
  456. pr_file.set_name("a.txt");
  457. pr_file.set_size(5ul);
  458. auto hash = utils::sha256_digest("12345").value();
  459. auto pr_block = pr_file.add_blocks();
  460. pr_block->set_weak_hash(12);
  461. pr_block->set_size(5);
  462. pr_block->set_hash(hash);
  463. auto builder = diff_builder_t(*cluster);
  464. builder.create_folder(folder_id, "/my/path").apply(*sup).local_update(folder_id, pr_file).apply(*sup);
  465. SECTION("check saved file with new blocks") {
  466. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  467. sup->do_process();
  468. REQUIRE(reply);
  469. REQUIRE(!reply->payload.ee);
  470. auto cluster_clone = make_cluster();
  471. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  472. auto folder = cluster_clone->get_folders().by_id(folder_id);
  473. auto folder_my = folder->get_folder_infos().by_device(*my_device);
  474. auto file = folder_my->get_file_infos().by_name("a.txt");
  475. REQUIRE(file);
  476. CHECK(cluster_clone->get_blocks().size() == 1);
  477. CHECK(file->get_blocks().size() == 1);
  478. }
  479. pr_file.set_deleted(true);
  480. pr_file.set_size(0);
  481. pr_file.clear_blocks();
  482. builder.local_update(folder_id, pr_file).apply(*sup);
  483. SECTION("check deleted blocks") {
  484. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  485. sup->do_process();
  486. REQUIRE(reply);
  487. REQUIRE(!reply->payload.ee);
  488. auto cluster_clone = make_cluster();
  489. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  490. auto folder = cluster_clone->get_folders().by_id(folder_id);
  491. auto folder_my = folder->get_folder_infos().by_device(*my_device);
  492. auto file = folder_my->get_file_infos().by_name("a.txt");
  493. REQUIRE(file);
  494. CHECK(file->is_deleted());
  495. CHECK(cluster_clone->get_blocks().size() == 0);
  496. CHECK(file->get_blocks().size() == 0);
  497. }
  498. }
  499. };
  500. F().run();
  501. };
  502. void test_peer_going_offline() {
  503. struct F : fixture_t {
  504. void main() noexcept override {
  505. auto sha256 = peer_device->device_id().get_sha256();
  506. auto builder = diff_builder_t(*cluster);
  507. builder.update_peer(sha256).apply(*sup);
  508. db::Device db_peer;
  509. auto peer = cluster->get_devices().by_sha256(sha256);
  510. REQUIRE(db_peer.last_seen() == 0);
  511. peer->update_state(device_state_t::online);
  512. auto diff = diff::cluster_diff_ptr_t(
  513. new model::diff::peer::peer_state_t(*cluster, sha256, sup->get_address(), device_state_t::offline));
  514. sup->send<model::payload::model_update_t>(sup->get_address(), std::move(diff), nullptr);
  515. sup->do_process();
  516. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  517. sup->do_process();
  518. REQUIRE(reply);
  519. auto cluster_clone = make_cluster();
  520. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  521. auto peer_clone = cluster_clone->get_devices().by_sha256(sha256);
  522. db::Device db_peer_clone;
  523. peer_clone->serialize(db_peer_clone);
  524. CHECK((peer->get_last_seen() - peer_clone->get_last_seen()).total_seconds() < 2);
  525. CHECK(db_peer_clone.last_seen() != 0);
  526. }
  527. };
  528. F().run();
  529. };
  530. void test_remove_peer() {
  531. struct F : fixture_t {
  532. void main() noexcept override {
  533. auto sha256 = peer_device->device_id().get_sha256();
  534. auto folder_id = "1234-5678";
  535. auto unknown_folder_id = "5678-999";
  536. auto file = proto::FileInfo();
  537. file.set_name("a.txt");
  538. file.set_size(5ul);
  539. file.set_block_size(5ul);
  540. file.set_sequence(6ul);
  541. auto b = file.add_blocks();
  542. b->set_size(5ul);
  543. b->set_hash(utils::sha256_digest("12345").value());
  544. auto builder = diff_builder_t(*cluster);
  545. builder.update_peer(sha256)
  546. .apply(*sup)
  547. .create_folder(folder_id, "/my/path")
  548. .configure_cluster(sha256)
  549. .add(sha256, folder_id, 5, file.sequence())
  550. .add(sha256, unknown_folder_id, 5, 5)
  551. .finish()
  552. .share_folder(sha256, folder_id)
  553. .apply(*sup)
  554. .make_index(sha256, folder_id)
  555. .add(file)
  556. .finish()
  557. .apply(*sup);
  558. REQUIRE(!cluster->get_unknown_folders().empty());
  559. REQUIRE(cluster->get_blocks().size() == 1);
  560. auto block = cluster->get_blocks().get(b->hash());
  561. REQUIRE(block);
  562. auto folder = cluster->get_folders().by_id(folder_id);
  563. auto peer_folder_info = folder->get_folder_infos().by_device(*peer_device);
  564. REQUIRE(peer_folder_info);
  565. CHECK(peer_folder_info->get_max_sequence() == 6ul);
  566. REQUIRE(peer_folder_info->get_file_infos().size() == 1);
  567. auto peer_file = peer_folder_info->get_file_infos().by_name("a.txt");
  568. REQUIRE(peer_file);
  569. builder.remove_peer(*peer_device).apply(*sup);
  570. sup->request<net::payload::load_cluster_request_t>(db_addr).send(timeout);
  571. sup->do_process();
  572. REQUIRE(reply);
  573. REQUIRE(!reply->payload.ee);
  574. auto cluster_clone = make_cluster();
  575. {
  576. REQUIRE(reply->payload.res.diff->apply(*cluster_clone));
  577. CHECK(cluster_clone->get_unknown_folders().empty());
  578. CHECK(cluster_clone->get_devices().size() == 1);
  579. REQUIRE(cluster_clone->get_blocks().size() == 0);
  580. }
  581. }
  582. };
  583. F().run();
  584. }
  585. int _init() {
  586. REGISTER_TEST_CASE(test_loading_empty_db, "test_loading_empty_db", "[db]");
  587. REGISTER_TEST_CASE(test_folder_creation, "test_folder_creation", "[db]");
  588. REGISTER_TEST_CASE(test_peer_updating, "test_peer_updating", "[db]");
  589. REGISTER_TEST_CASE(test_folder_sharing, "test_folder_sharing", "[db]");
  590. REGISTER_TEST_CASE(test_cluster_update_and_remove, "test_cluster_update_and_remove", "[db]");
  591. REGISTER_TEST_CASE(test_unsharing_folder, "test_unsharing_folder", "[db]");
  592. REGISTER_TEST_CASE(test_clone_file, "test_clone_file", "[db]");
  593. REGISTER_TEST_CASE(test_local_update, "test_local_update", "[db]");
  594. REGISTER_TEST_CASE(test_peer_going_offline, "test_peer_going_offline", "[db]");
  595. REGISTER_TEST_CASE(test_remove_peer, "test_remove_peer", "[db]");
  596. return 1;
  597. }
  598. static int v = _init();