075-controller.cpp 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. // SPDX-FileCopyrightText: 2019-2024 Ivan Baidakou
  3. #include "test-utils.h"
  4. #include "access.h"
  5. #include "test_supervisor.h"
  6. #include "model/cluster.h"
  7. #include "diff-builder.h"
  8. #include "hasher/hasher_proxy_actor.h"
  9. #include "hasher/hasher_actor.h"
  10. #include "net/controller_actor.h"
  11. #include "net/names.h"
  12. #include "fs/messages.h"
  13. #include "utils/error_code.h"
  14. #include "proto/bep_support.h"
  15. #include <boost/core/demangle.hpp>
  16. #include <type_traits>
  17. using namespace syncspirit;
  18. using namespace syncspirit::test;
  19. using namespace syncspirit::model;
  20. using namespace syncspirit::net;
  21. using namespace syncspirit::hasher;
  22. namespace {
  23. struct sample_peer_config_t : public r::actor_config_t {
  24. model::device_id_t peer_device_id;
  25. bool auto_share = false;
  26. };
  27. template <typename Actor> struct sample_peer_config_builder_t : r::actor_config_builder_t<Actor> {
  28. using builder_t = typename Actor::template config_builder_t<Actor>;
  29. using parent_t = r::actor_config_builder_t<Actor>;
  30. using parent_t::parent_t;
  31. builder_t &&peer_device_id(const model::device_id_t &value) && noexcept {
  32. parent_t::config.peer_device_id = value;
  33. return std::move(*static_cast<typename parent_t::builder_t *>(this));
  34. }
  35. builder_t &&auto_share(bool value) && noexcept {
  36. parent_t::config.auto_share = value;
  37. return std::move(*static_cast<typename parent_t::builder_t *>(this));
  38. }
  39. };
  40. struct sample_peer_t : r::actor_base_t {
  41. using config_t = sample_peer_config_t;
  42. template <typename Actor> using config_builder_t = sample_peer_config_builder_t<Actor>;
  43. using remote_message_t = r::intrusive_ptr_t<net::message::forwarded_message_t>;
  44. using remote_messages_t = std::list<remote_message_t>;
  45. struct block_response_t {
  46. std::string name;
  47. size_t block_index;
  48. std::string data;
  49. sys::error_code ec;
  50. };
  51. using allowed_index_updates_t = std::unordered_set<std::string>;
  52. using block_responses_t = std::list<block_response_t>;
  53. using block_request_t = r::intrusive_ptr_t<net::message::block_request_t>;
  54. using block_requests_t = std::list<block_request_t>;
  55. using uploaded_blocks_t = std::list<proto::message::Response>;
  56. sample_peer_t(config_t &config)
  57. : r::actor_base_t{config}, peer_device{config.peer_device_id}, auto_share(config.auto_share) {
  58. log = utils::get_logger("test.sample_peer");
  59. }
  60. void configure(r::plugin::plugin_base_t &plugin) noexcept override {
  61. r::actor_base_t::configure(plugin);
  62. plugin.with_casted<r::plugin::address_maker_plugin_t>([&](auto &p) { p.set_identity("sample_peer", false); });
  63. plugin.with_casted<r::plugin::starter_plugin_t>([&](auto &p) {
  64. p.subscribe_actor(&sample_peer_t::on_start_reading);
  65. p.subscribe_actor(&sample_peer_t::on_termination);
  66. p.subscribe_actor(&sample_peer_t::on_transfer);
  67. p.subscribe_actor(&sample_peer_t::on_block_request);
  68. });
  69. }
  70. void shutdown_start() noexcept override {
  71. LOG_TRACE(log, "{}, shutdown_start", identity);
  72. if (controller) {
  73. send<net::payload::termination_t>(controller, shutdown_reason);
  74. }
  75. r::actor_base_t::shutdown_start();
  76. }
  77. void shutdown_finish() noexcept override {
  78. r::actor_base_t::shutdown_finish();
  79. LOG_TRACE(log, "{}, shutdown_finish, blocks requested = {}", identity, blocks_requested);
  80. if (controller) {
  81. send<net::payload::termination_t>(controller, shutdown_reason);
  82. }
  83. }
  84. void on_start_reading(net::message::start_reading_t &msg) noexcept {
  85. LOG_TRACE(log, "{}, on_start_reading", identity);
  86. controller = msg.payload.controller;
  87. reading = msg.payload.start;
  88. }
  89. void on_termination(net::message::termination_signal_t &msg) noexcept {
  90. LOG_TRACE(log, "{}, on_termination", identity);
  91. if (!shutdown_reason) {
  92. auto &ee = msg.payload.ee;
  93. auto reason = ee->message();
  94. LOG_TRACE(log, "{}, on_termination: {}", identity, reason);
  95. do_shutdown(ee);
  96. }
  97. }
  98. void on_transfer(net::message::transfer_data_t &message) noexcept {
  99. auto &data = message.payload.data;
  100. LOG_TRACE(log, "{}, on_transfer, bytes = {}", identity, data.size());
  101. auto buff = boost::asio::buffer(data.data(), data.size());
  102. auto result = proto::parse_bep(buff);
  103. auto orig = std::move(result.value().message);
  104. auto variant = net::payload::forwarded_message_t();
  105. std::visit(
  106. [&](auto &msg) {
  107. using boost::core::demangle;
  108. using T = std::decay_t<decltype(msg)>;
  109. LOG_TRACE(log, "{}, received '{}' message", identity, demangle(typeid(T).name()));
  110. using V = net::payload::forwarded_message_t;
  111. if constexpr (std::is_constructible_v<V, T>) {
  112. variant = std::move(msg);
  113. } else if constexpr (std::is_same_v<T, proto::message::Response>) {
  114. uploaded_blocks.push_back(std::move(msg));
  115. }
  116. },
  117. orig);
  118. auto fwd_msg = new net::message::forwarded_message_t(address, std::move(variant));
  119. messages.emplace_back(fwd_msg);
  120. for (auto &msg : messages) {
  121. auto &p = msg->payload;
  122. if (auto m = std::get_if<proto::message::Index>(&p); m) {
  123. allowed_index_updates.emplace((*m)->folder());
  124. }
  125. if (auto m = std::get_if<proto::message::IndexUpdate>(&p); m) {
  126. auto &folder_id = (*m)->folder();
  127. if ((allowed_index_updates.count(folder_id) == 0) && !auto_share) {
  128. LOG_WARN(log, "{}, IndexUpdate w/o previously recevied index", identity);
  129. std::abort();
  130. }
  131. }
  132. }
  133. }
  134. void process_block_requests() noexcept {
  135. auto condition = [&]() -> bool {
  136. if (block_requests.size() && block_responses.size()) {
  137. auto &req = block_requests.front();
  138. auto &res = block_responses.front();
  139. auto &req_payload = req->payload.request_payload;
  140. if (req_payload.block.block_index() == res.block_index) {
  141. auto &name = res.name;
  142. return name.empty() || name == req_payload.file->get_name();
  143. }
  144. }
  145. return false;
  146. };
  147. while (condition()) {
  148. auto &reply = block_responses.front();
  149. auto &request = *block_requests.front();
  150. log->debug("{}, matched '{}', replying..., ec = {}", identity, reply.name, reply.ec.value());
  151. if (!reply.ec) {
  152. reply_to(request, reply.data);
  153. } else {
  154. reply_with_error(request, make_error(reply.ec));
  155. }
  156. block_responses.pop_front();
  157. block_requests.pop_front();
  158. }
  159. }
  160. void on_block_request(net::message::block_request_t &req) noexcept {
  161. block_requests.push_front(&req);
  162. ++blocks_requested;
  163. log->debug("{}, requesting block # {}", identity,
  164. block_requests.front()->payload.request_payload.block.block_index());
  165. if (block_responses.size()) {
  166. log->debug("{}, top response block # {}", identity, block_responses.front().block_index);
  167. }
  168. process_block_requests();
  169. }
  170. void forward(net::payload::forwarded_message_t payload) noexcept {
  171. send<net::payload::forwarded_message_t>(controller, std::move(payload));
  172. }
  173. static const constexpr size_t next_block = 1000000;
  174. void push_block(std::string_view data, size_t index, std::string name = {}) {
  175. if (index == next_block) {
  176. index = block_responses.size();
  177. }
  178. block_responses.push_back(block_response_t{std::move(name), index, std::string(data), {}});
  179. }
  180. void push_block(sys::error_code ec, size_t index) {
  181. if (index == next_block) {
  182. index = block_responses.size();
  183. }
  184. block_responses.push_back(block_response_t{std::string{}, index, std::string{}, ec});
  185. }
  186. size_t blocks_requested = 0;
  187. bool reading = false;
  188. bool auto_share = false;
  189. remote_messages_t messages;
  190. r::address_ptr_t controller;
  191. model::device_id_t peer_device;
  192. utils::logger_t log;
  193. block_requests_t block_requests;
  194. block_responses_t block_responses;
  195. uploaded_blocks_t uploaded_blocks;
  196. allowed_index_updates_t allowed_index_updates;
  197. };
  198. struct fixture_t {
  199. using peer_ptr_t = r::intrusive_ptr_t<sample_peer_t>;
  200. using target_ptr_t = r::intrusive_ptr_t<net::controller_actor_t>;
  201. using blk_req_t = fs::message::block_request_t;
  202. using blk_req_ptr_t = r::intrusive_ptr_t<blk_req_t>;
  203. using blk_res_t = fs::message::block_response_t;
  204. using blk_res_ptr_t = r::intrusive_ptr_t<blk_res_t>;
  205. using block_requests_t = std::deque<blk_req_ptr_t>;
  206. using block_responses_t = std::deque<r::message_ptr_t>;
  207. fixture_t(bool auto_start_, int64_t max_sequence_, bool auto_share_ = true) noexcept
  208. : auto_start{auto_start_}, max_sequence{max_sequence_}, auto_share{auto_share_} {
  209. utils::set_default("trace");
  210. }
  211. void start_target() noexcept {
  212. peer_actor = sup->create_actor<sample_peer_t>().auto_share(auto_share).timeout(timeout).finish();
  213. target = sup->create_actor<controller_actor_t>()
  214. .peer(peer_device)
  215. .peer_addr(peer_actor->get_address())
  216. .request_pool(1024)
  217. .outgoing_buffer_max(1024'000)
  218. .cluster(cluster)
  219. .sequencer(sup->sequencer)
  220. .timeout(timeout)
  221. .request_timeout(timeout)
  222. .finish();
  223. sup->do_process();
  224. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  225. target_addr = target->get_address();
  226. }
  227. virtual void run() noexcept {
  228. auto peer_id =
  229. device_id_t::from_string("VUV42CZ-IQD5A37-RPEBPM4-VVQK6E4-6WSKC7B-PVJQHHD-4PZD44V-ENC6WAZ").value();
  230. peer_device = device_t::create(peer_id, "peer-device").value();
  231. auto my_id =
  232. device_id_t::from_string("KHQNO2S-5QSILRK-YX4JZZ4-7L77APM-QNVGZJT-EKU7IFI-PNEPBMY-4MXFMQD").value();
  233. my_device = device_t::create(my_id, "my-device").value();
  234. cluster = new cluster_t(my_device, 1);
  235. cluster->get_devices().put(my_device);
  236. cluster->get_devices().put(peer_device);
  237. auto folder_id_1 = "1234-5678";
  238. auto folder_id_2 = "5555";
  239. auto builder = diff_builder_t(*cluster);
  240. auto sha256 = peer_id.get_sha256();
  241. builder.upsert_folder(folder_id_1, "")
  242. .upsert_folder(folder_id_2, "")
  243. .configure_cluster(sha256)
  244. .add(sha256, folder_id_1, 123, max_sequence)
  245. .finish();
  246. REQUIRE(builder.apply());
  247. if (auto_share) {
  248. REQUIRE(builder.share_folder(peer_id.get_sha256(), folder_id_1).apply());
  249. }
  250. r::system_context_t ctx;
  251. sup = ctx.create_supervisor<supervisor_t>().timeout(timeout).create_registry().finish();
  252. sup->cluster = cluster;
  253. sup->configure_callback = [&](r::plugin::plugin_base_t &plugin) {
  254. plugin.template with_casted<r::plugin::registry_plugin_t>(
  255. [&](auto &p) { p.register_name(net::names::fs_actor, sup->get_address()); });
  256. plugin.template with_casted<r::plugin::starter_plugin_t>([&](auto &p) {
  257. p.subscribe_actor(r::lambda<blk_req_t>([&](blk_req_t &msg) {
  258. block_requests.push_back(&msg);
  259. if (block_responses.size()) {
  260. sup->put(block_responses.front());
  261. block_responses.pop_front();
  262. }
  263. }));
  264. });
  265. };
  266. sup->start();
  267. sup->do_process();
  268. CHECK(static_cast<r::actor_base_t *>(sup.get())->access<to::state>() == r::state_t::OPERATIONAL);
  269. sup->create_actor<hasher_actor_t>().index(1).timeout(timeout).finish();
  270. sup->create_actor<hasher::hasher_proxy_actor_t>()
  271. .timeout(timeout)
  272. .hasher_threads(1)
  273. .name(net::names::hasher_proxy)
  274. .finish();
  275. auto &folders = cluster->get_folders();
  276. folder_1 = folders.by_id(folder_id_1);
  277. folder_2 = folders.by_id(folder_id_2);
  278. folder_1_peer = folder_1->get_folder_infos().by_device_id(peer_id.get_sha256());
  279. start_target();
  280. if (auto_start) {
  281. REQUIRE(peer_actor->reading);
  282. REQUIRE(peer_actor->messages.size() == 1);
  283. auto &msg = (*peer_actor->messages.front()).payload;
  284. REQUIRE(std::get_if<proto::message::ClusterConfig>(&msg));
  285. peer_actor->messages.pop_front();
  286. }
  287. main(builder);
  288. sup->shutdown();
  289. sup->do_process();
  290. CHECK(static_cast<r::actor_base_t *>(sup.get())->access<to::state>() == r::state_t::SHUT_DOWN);
  291. }
  292. virtual void main(diff_builder_t &) noexcept {}
  293. bool auto_start;
  294. bool auto_share;
  295. int64_t max_sequence;
  296. peer_ptr_t peer_actor;
  297. target_ptr_t target;
  298. r::address_ptr_t target_addr;
  299. r::pt::time_duration timeout = r::pt::millisec{10};
  300. cluster_ptr_t cluster;
  301. device_ptr_t peer_device;
  302. device_ptr_t my_device;
  303. r::intrusive_ptr_t<supervisor_t> sup;
  304. r::system_context_t ctx;
  305. model::folder_ptr_t folder_1;
  306. model::folder_info_ptr_t folder_1_peer;
  307. model::folder_ptr_t folder_2;
  308. block_requests_t block_requests;
  309. block_responses_t block_responses;
  310. };
  311. } // namespace
  312. void test_startup() {
  313. struct F : fixture_t {
  314. using fixture_t::fixture_t;
  315. void main(diff_builder_t &) noexcept override {
  316. REQUIRE(peer_actor->reading);
  317. REQUIRE(peer_actor->messages.size() == 1);
  318. auto &msg = (*peer_actor->messages.front()).payload;
  319. REQUIRE(std::get_if<proto::message::ClusterConfig>(&msg));
  320. peer_actor->messages.pop_front();
  321. CHECK(peer_actor->messages.empty());
  322. auto cc = proto::ClusterConfig{};
  323. auto payload = proto::message::ClusterConfig(new proto::ClusterConfig(cc));
  324. peer_actor->forward(std::move(payload));
  325. sup->do_process();
  326. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  327. CHECK(peer_actor->messages.empty());
  328. }
  329. };
  330. F(false, 10, false).run();
  331. }
  332. void test_index_receiving() {
  333. struct F : fixture_t {
  334. using fixture_t::fixture_t;
  335. void main(diff_builder_t &) noexcept override {
  336. auto cc = proto::ClusterConfig{};
  337. auto index = proto::Index{};
  338. SECTION("wrong index") {
  339. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  340. index.set_folder("non-existing-folder");
  341. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  342. sup->do_process();
  343. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::SHUT_DOWN);
  344. CHECK(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::SHUT_DOWN);
  345. }
  346. SECTION("index is applied") {
  347. auto folder = cc.add_folders();
  348. folder->set_id(std::string(folder_1->get_id()));
  349. auto d_peer = folder->add_devices();
  350. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  351. REQUIRE(cluster->get_pending_folders().size() == 0);
  352. d_peer->set_max_sequence(10);
  353. d_peer->set_index_id(folder_1_peer->get_index());
  354. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  355. index.set_folder(std::string(folder_1->get_id()));
  356. auto file = index.add_files();
  357. file->set_name("some-dir");
  358. file->set_type(proto::FileInfoType::DIRECTORY);
  359. file->set_sequence(10);
  360. auto v = file->mutable_version();
  361. auto c = v->add_counters();
  362. c->set_id(peer_device->device_id().get_uint());
  363. c->set_value(1);
  364. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  365. sup->do_process();
  366. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  367. CHECK(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  368. auto &folder_infos = folder_1->get_folder_infos();
  369. auto folder_peer = folder_infos.by_device(*peer_device);
  370. REQUIRE(folder_peer);
  371. CHECK(folder_peer->get_max_sequence() == 10ul);
  372. REQUIRE(folder_peer->get_file_infos().size() == 1);
  373. CHECK(folder_peer->get_file_infos().begin()->item->get_name() == file->name());
  374. auto folder_my = folder_infos.by_device(*my_device);
  375. REQUIRE(folder_my);
  376. CHECK(folder_my->get_max_sequence() == 1ul);
  377. REQUIRE(folder_my->get_file_infos().size() == 1);
  378. CHECK(folder_my->get_file_infos().begin()->item->get_name() == file->name());
  379. SECTION("then index update is applied") {
  380. auto index_update = proto::IndexUpdate{};
  381. index_update.set_folder(std::string(folder_1->get_id()));
  382. auto file = index_update.add_files();
  383. file->set_name("some-dir-2");
  384. file->set_type(proto::FileInfoType::DIRECTORY);
  385. file->set_sequence(folder_1_peer->get_max_sequence() + 1);
  386. auto v = file->mutable_version();
  387. auto c = v->add_counters();
  388. c->set_id(peer_device->device_id().get_uint());
  389. c->set_value(1);
  390. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index_update)));
  391. sup->do_process();
  392. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  393. CHECK(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() ==
  394. r::state_t::OPERATIONAL);
  395. CHECK(folder_peer->get_max_sequence() == file->sequence());
  396. REQUIRE(folder_peer->get_file_infos().size() == 2);
  397. CHECK(folder_peer->get_file_infos().by_name("some-dir-2"));
  398. CHECK(folder_my->get_max_sequence() == 2ul);
  399. REQUIRE(folder_my->get_file_infos().size() == 2);
  400. CHECK(folder_my->get_file_infos().by_name("some-dir-2"));
  401. }
  402. }
  403. }
  404. };
  405. F(true, 10).run();
  406. }
  407. void test_index_sending() {
  408. struct F : fixture_t {
  409. using fixture_t::fixture_t;
  410. void main(diff_builder_t &) noexcept override {
  411. proto::FileInfo pr_file_info;
  412. pr_file_info.set_name("link");
  413. pr_file_info.set_type(proto::FileInfoType::SYMLINK);
  414. pr_file_info.set_symlink_target("/some/where");
  415. auto builder = diff_builder_t(*cluster);
  416. builder.local_update(folder_1->get_id(), pr_file_info);
  417. builder.apply(*sup);
  418. auto folder_1_my = folder_1->get_folder_infos().by_device(*my_device);
  419. auto cc = proto::ClusterConfig{};
  420. auto folder = cc.add_folders();
  421. folder->set_id(std::string(folder_1->get_id()));
  422. auto d_peer = folder->add_devices();
  423. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  424. d_peer->set_max_sequence(folder_1_peer->get_max_sequence());
  425. d_peer->set_index_id(folder_1_peer->get_index());
  426. SECTION("peer has outdated by sequence view") {
  427. auto d_my = folder->add_devices();
  428. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  429. d_my->set_max_sequence(folder_1_my->get_max_sequence() - 1);
  430. d_my->set_index_id(folder_1_my->get_index());
  431. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  432. sup->do_process();
  433. auto &queue = peer_actor->messages;
  434. REQUIRE(queue.size() == 1);
  435. auto msg = &(*queue.front()).payload;
  436. auto &my_index_update = *std::get<proto::message::IndexUpdate>(*msg);
  437. REQUIRE(my_index_update.files_size() == 1);
  438. }
  439. SECTION("peer has outdated by index view") {
  440. auto d_my = folder->add_devices();
  441. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  442. d_my->set_max_sequence(folder_1_my->get_max_sequence());
  443. d_my->set_index_id(folder_1_my->get_index() + 5);
  444. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  445. sup->do_process();
  446. auto &queue = peer_actor->messages;
  447. REQUIRE(queue.size() == 2);
  448. auto msg = &(*queue.front()).payload;
  449. auto &my_index = *std::get<proto::message::Index>(*msg);
  450. REQUIRE(my_index.files_size() == 0);
  451. queue.pop_front();
  452. msg = &(*queue.front()).payload;
  453. auto &my_index_update = *std::get<proto::message::IndexUpdate>(*msg);
  454. REQUIRE(my_index_update.files_size() == 1);
  455. }
  456. SECTION("peer has actual view") {
  457. auto d_my = folder->add_devices();
  458. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  459. d_my->set_max_sequence(folder_1_my->get_max_sequence());
  460. d_my->set_index_id(folder_1_my->get_index());
  461. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  462. sup->do_process();
  463. auto &queue = peer_actor->messages;
  464. REQUIRE(queue.size() == 0);
  465. }
  466. }
  467. };
  468. F(true, 10).run();
  469. }
  470. void test_downloading() {
  471. struct F : fixture_t {
  472. using fixture_t::fixture_t;
  473. void main(diff_builder_t &) noexcept override {
  474. auto &folder_infos = folder_1->get_folder_infos();
  475. auto folder_my = folder_infos.by_device(*my_device);
  476. auto cc = proto::ClusterConfig{};
  477. auto folder = cc.add_folders();
  478. folder->set_id(std::string(folder_1->get_id()));
  479. auto d_peer = folder->add_devices();
  480. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  481. d_peer->set_max_sequence(10);
  482. d_peer->set_index_id(folder_1_peer->get_index());
  483. auto d_my = folder->add_devices();
  484. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  485. d_my->set_max_sequence(folder_my->get_max_sequence());
  486. d_my->set_index_id(folder_my->get_index());
  487. SECTION("cluster config & index has a new file => download it") {
  488. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  489. auto index = proto::Index{};
  490. index.set_folder(std::string(folder_1->get_id()));
  491. auto file = index.add_files();
  492. file->set_name("some-file");
  493. file->set_type(proto::FileInfoType::FILE);
  494. file->set_sequence(folder_1_peer->get_max_sequence() + 1);
  495. file->set_block_size(5);
  496. file->set_size(5);
  497. auto version = file->mutable_version();
  498. auto counter = version->add_counters();
  499. counter->set_id(1ul);
  500. counter->set_value(1ul);
  501. auto b1 = file->add_blocks();
  502. b1->set_hash(utils::sha256_digest("12345").value());
  503. b1->set_offset(0);
  504. b1->set_size(5);
  505. auto folder_my = folder_infos.by_device(*my_device);
  506. CHECK(folder_my->get_max_sequence() == 0ul);
  507. CHECK(!folder_my->get_folder()->is_synchronizing());
  508. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  509. sup->do_process();
  510. CHECK(folder_my->get_folder()->is_synchronizing());
  511. peer_actor->push_block("12345", 0);
  512. peer_actor->process_block_requests();
  513. sup->do_process();
  514. CHECK(!folder_my->get_folder()->is_synchronizing());
  515. REQUIRE(folder_my);
  516. CHECK(folder_my->get_max_sequence() == 1ul);
  517. REQUIRE(folder_my->get_file_infos().size() == 1);
  518. auto f = folder_my->get_file_infos().begin()->item;
  519. REQUIRE(f);
  520. CHECK(f->get_name() == file->name());
  521. CHECK(f->get_size() == 5);
  522. CHECK(f->get_blocks().size() == 1);
  523. CHECK(f->is_locally_available());
  524. CHECK(!f->is_locked());
  525. CHECK(peer_actor->blocks_requested == 1);
  526. auto &queue = peer_actor->messages;
  527. REQUIRE(queue.size() > 0);
  528. auto msg = &(*queue.back()).payload;
  529. auto &my_index_update = *std::get<proto::message::IndexUpdate>(*msg);
  530. REQUIRE(my_index_update.files_size() == 1);
  531. SECTION("dont redownload file only if metadata has changed") {
  532. auto index_update = proto::IndexUpdate{};
  533. index_update.set_folder(index.folder());
  534. file->set_sequence(folder_1_peer->get_max_sequence() + 1);
  535. counter->set_value(2ul);
  536. *index_update.add_files() = *file;
  537. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index_update)));
  538. sup->do_process();
  539. CHECK(peer_actor->blocks_requested == 1);
  540. CHECK(folder_my->get_max_sequence() == 2ul);
  541. f = folder_my->get_file_infos().begin()->item;
  542. CHECK(f->is_locally_available());
  543. CHECK(f->get_sequence() == 2ul);
  544. }
  545. }
  546. SECTION("download 2 files") {
  547. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  548. auto index = proto::Index{};
  549. index.set_folder(std::string(folder_1->get_id()));
  550. auto file_1 = index.add_files();
  551. file_1->set_name("file-1");
  552. file_1->set_type(proto::FileInfoType::FILE);
  553. file_1->set_sequence(folder_1_peer->get_max_sequence() + 1);
  554. file_1->set_block_size(5);
  555. file_1->set_size(5);
  556. auto version_1 = file_1->mutable_version();
  557. auto counter_1 = version_1->add_counters();
  558. counter_1->set_id(1ul);
  559. counter_1->set_value(1ul);
  560. auto file_2 = index.add_files();
  561. file_2->set_name("file-2");
  562. file_2->set_type(proto::FileInfoType::FILE);
  563. file_2->set_sequence(folder_1_peer->get_max_sequence() + 2);
  564. file_2->set_block_size(5);
  565. file_2->set_size(5);
  566. auto version_2 = file_2->mutable_version();
  567. auto counter_2 = version_2->add_counters();
  568. counter_2->set_id(1ul);
  569. counter_2->set_value(2ul);
  570. auto b1 = file_1->add_blocks();
  571. b1->set_hash(utils::sha256_digest("12345").value());
  572. b1->set_offset(0);
  573. b1->set_size(5);
  574. SECTION("with different blocks") {
  575. auto b2 = file_2->add_blocks();
  576. b2->set_hash(utils::sha256_digest("67890").value());
  577. b2->set_offset(0);
  578. b2->set_size(5);
  579. auto folder_my = folder_infos.by_device(*my_device);
  580. CHECK(folder_my->get_max_sequence() == 0ul);
  581. CHECK(!folder_my->get_folder()->is_synchronizing());
  582. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  583. peer_actor->push_block("12345", 0, file_1->name());
  584. peer_actor->push_block("67890", 0, file_2->name());
  585. sup->do_process();
  586. CHECK(!folder_my->get_folder()->is_synchronizing());
  587. CHECK(peer_actor->blocks_requested == 2);
  588. REQUIRE(folder_my);
  589. CHECK(folder_my->get_max_sequence() == 2ul);
  590. REQUIRE(folder_my->get_file_infos().size() == 2);
  591. {
  592. auto f = folder_my->get_file_infos().by_name(file_1->name());
  593. REQUIRE(f);
  594. CHECK(f->get_size() == 5);
  595. CHECK(f->get_blocks().size() == 1);
  596. CHECK(f->is_locally_available());
  597. CHECK(!f->is_locked());
  598. }
  599. {
  600. auto f = folder_my->get_file_infos().by_name(file_2->name());
  601. REQUIRE(f);
  602. CHECK(f->get_size() == 5);
  603. CHECK(f->get_blocks().size() == 1);
  604. CHECK(f->is_locally_available());
  605. CHECK(!f->is_locked());
  606. }
  607. }
  608. SECTION("with the same block") {
  609. *file_2->add_blocks() = *b1;
  610. auto folder_my = folder_infos.by_device(*my_device);
  611. CHECK(folder_my->get_max_sequence() == 0ul);
  612. CHECK(!folder_my->get_folder()->is_synchronizing());
  613. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  614. peer_actor->push_block("12345", 0, file_1->name());
  615. sup->do_process();
  616. CHECK(!folder_my->get_folder()->is_synchronizing());
  617. CHECK(peer_actor->blocks_requested == 1);
  618. REQUIRE(folder_my);
  619. CHECK(folder_my->get_max_sequence() == 2ul);
  620. REQUIRE(folder_my->get_file_infos().size() == 2);
  621. {
  622. auto f = folder_my->get_file_infos().by_name(file_1->name());
  623. REQUIRE(f);
  624. CHECK(f->get_size() == 5);
  625. CHECK(f->get_blocks().size() == 1);
  626. CHECK(f->is_locally_available());
  627. CHECK(!f->is_locked());
  628. }
  629. {
  630. auto f = folder_my->get_file_infos().by_name(file_2->name());
  631. REQUIRE(f);
  632. CHECK(f->get_size() == 5);
  633. CHECK(f->get_blocks().size() == 1);
  634. CHECK(f->is_locally_available());
  635. CHECK(!f->is_locked());
  636. }
  637. }
  638. SECTION("with the same blocks") {
  639. auto concurrent_writes = GENERATE(1, 5);
  640. cluster->modify_write_requests(concurrent_writes);
  641. *file_2->add_blocks() = *b1;
  642. *file_2->add_blocks() = *b1;
  643. file_2->set_size(10);
  644. auto folder_my = folder_infos.by_device(*my_device);
  645. CHECK(folder_my->get_max_sequence() == 0ul);
  646. CHECK(!folder_my->get_folder()->is_synchronizing());
  647. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  648. peer_actor->push_block("12345", 0, file_1->name());
  649. sup->do_process();
  650. CHECK(!folder_my->get_folder()->is_synchronizing());
  651. CHECK(peer_actor->blocks_requested == 1);
  652. REQUIRE(folder_my);
  653. CHECK(folder_my->get_max_sequence() == 2ul);
  654. REQUIRE(folder_my->get_file_infos().size() == 2);
  655. {
  656. auto f = folder_my->get_file_infos().by_name(file_1->name());
  657. REQUIRE(f);
  658. CHECK(f->get_size() == 5);
  659. CHECK(f->get_blocks().size() == 1);
  660. CHECK(f->is_locally_available());
  661. CHECK(!f->is_locked());
  662. }
  663. {
  664. auto f = folder_my->get_file_infos().by_name(file_2->name());
  665. REQUIRE(f);
  666. CHECK(f->get_size() == 10);
  667. CHECK(f->get_blocks().size() == 2);
  668. CHECK(f->is_locally_available());
  669. CHECK(!f->is_locked());
  670. }
  671. }
  672. }
  673. SECTION("don't attempt to download a file, which is deleted") {
  674. auto folder_peer = folder_infos.by_device(*peer_device);
  675. auto pr_fi = proto::FileInfo{};
  676. pr_fi.set_name("some-file");
  677. pr_fi.set_type(proto::FileInfoType::FILE);
  678. pr_fi.set_sequence(folder_1_peer->get_max_sequence() + 1);
  679. pr_fi.set_block_size(5);
  680. pr_fi.set_size(5);
  681. auto version = pr_fi.mutable_version();
  682. auto counter = version->add_counters();
  683. counter->set_id(1ul);
  684. counter->set_value(1ul);
  685. auto b1 = pr_fi.add_blocks();
  686. b1->set_hash(utils::sha256_digest("12345").value());
  687. b1->set_offset(0);
  688. b1->set_size(5);
  689. auto b = model::block_info_t::create(*b1).value();
  690. auto uuid = sup->sequencer->next_uuid();
  691. auto file_info = model::file_info_t::create(uuid, pr_fi, folder_peer).value();
  692. file_info->assign_block(b, 0);
  693. REQUIRE(folder_peer->add_strict(file_info));
  694. cluster->get_blocks().put(b);
  695. d_peer->set_max_sequence(folder_1_peer->get_max_sequence() + 1);
  696. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  697. sup->do_process();
  698. auto blocks_requested = peer_actor->blocks_requested;
  699. auto index = proto::IndexUpdate{};
  700. index.set_folder(std::string(folder_1->get_id()));
  701. auto file = index.add_files();
  702. file->set_name("some-file");
  703. file->set_type(proto::FileInfoType::FILE);
  704. file->set_deleted(true);
  705. file->set_sequence(folder_1_peer->get_max_sequence() + 1);
  706. file->set_block_size(0);
  707. file->set_size(0);
  708. auto v = file->mutable_version();
  709. auto c = v->add_counters();
  710. c->set_id(peer_device->device_id().get_uint());
  711. c->set_value(1);
  712. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index)));
  713. sup->do_process();
  714. CHECK(folder_my->get_max_sequence() == 1ul);
  715. REQUIRE(folder_my->get_file_infos().size() == 1);
  716. auto f = folder_my->get_file_infos().begin()->item;
  717. REQUIRE(f);
  718. CHECK(f->get_name() == pr_fi.name());
  719. CHECK(f->get_size() == 0);
  720. CHECK(f->get_blocks().size() == 0);
  721. CHECK(f->is_locally_available());
  722. CHECK(f->is_deleted());
  723. CHECK(!f->is_locked());
  724. CHECK(f->get_sequence() == 1ul);
  725. CHECK(peer_actor->blocks_requested == blocks_requested);
  726. }
  727. SECTION("new file via index_update => download it") {
  728. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  729. auto index = proto::Index{};
  730. index.set_folder(std::string(folder_1->get_id()));
  731. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  732. auto index_update = proto::IndexUpdate{};
  733. index_update.set_folder(std::string(folder_1->get_id()));
  734. auto file = index_update.add_files();
  735. file->set_name("some-file");
  736. file->set_type(proto::FileInfoType::FILE);
  737. file->set_sequence(folder_1_peer->get_max_sequence() + 1);
  738. file->set_block_size(5);
  739. file->set_size(5);
  740. auto version = file->mutable_version();
  741. auto counter = version->add_counters();
  742. counter->set_id(1);
  743. counter->set_value(peer_device->device_id().get_uint());
  744. auto b1 = file->add_blocks();
  745. b1->set_hash(utils::sha256_digest("12345").value());
  746. b1->set_offset(0);
  747. b1->set_size(5);
  748. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index_update)));
  749. peer_actor->push_block("12345", 0);
  750. sup->do_process();
  751. auto folder_my = folder_infos.by_device(*my_device);
  752. CHECK(folder_my->get_max_sequence() == 1);
  753. REQUIRE(folder_my->get_file_infos().size() == 1);
  754. auto f = folder_my->get_file_infos().begin()->item;
  755. REQUIRE(f);
  756. CHECK(f->get_name() == file->name());
  757. CHECK(f->get_size() == 5);
  758. CHECK(f->get_blocks().size() == 1);
  759. CHECK(f->is_locally_available());
  760. CHECK(!f->is_locked());
  761. auto fp = folder_1_peer->get_file_infos().begin()->item;
  762. REQUIRE(fp);
  763. CHECK(!fp->is_locked());
  764. }
  765. SECTION("deleted file, has been restored => download it") {
  766. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  767. sup->do_process();
  768. auto index = proto::Index{};
  769. index.set_folder(std::string(folder_1->get_id()));
  770. auto file_1 = index.add_files();
  771. file_1->set_name("some-file");
  772. file_1->set_type(proto::FileInfoType::FILE);
  773. file_1->set_sequence(folder_1_peer->get_max_sequence() + 1);
  774. file_1->set_deleted(true);
  775. auto v1 = file_1->mutable_version();
  776. auto c1 = v1->add_counters();
  777. c1->set_id(1u);
  778. c1->set_value(1u);
  779. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  780. sup->do_process();
  781. CHECK(!folder_my->get_folder()->is_synchronizing());
  782. auto folder_my = folder_infos.by_device(*my_device);
  783. CHECK(folder_my->get_max_sequence() == 1);
  784. auto index_update = proto::IndexUpdate{};
  785. index_update.set_folder(std::string(folder_1->get_id()));
  786. auto file_2 = index_update.add_files();
  787. file_2->set_name("some-file");
  788. file_2->set_type(proto::FileInfoType::FILE);
  789. file_2->set_sequence(folder_1_peer->get_max_sequence() + 1);
  790. file_2->set_block_size(128 * 1024);
  791. file_2->set_size(5);
  792. auto v2 = file_2->mutable_version();
  793. auto c2 = v2->add_counters();
  794. c2->set_id(1u);
  795. c2->set_value(2u);
  796. auto b1 = file_2->add_blocks();
  797. b1->set_hash(utils::sha256_digest("12345").value());
  798. b1->set_offset(0);
  799. b1->set_size(5);
  800. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index_update)));
  801. peer_actor->push_block("12345", 0);
  802. sup->do_process();
  803. REQUIRE(folder_my->get_file_infos().size() == 1);
  804. auto f = folder_my->get_file_infos().begin()->item;
  805. REQUIRE(f);
  806. CHECK(f->get_name() == file_1->name());
  807. CHECK(f->get_size() == 5);
  808. CHECK(f->get_blocks().size() == 1);
  809. CHECK(f->is_locally_available());
  810. CHECK(!f->is_locked());
  811. CHECK(!f->is_deleted());
  812. }
  813. SECTION("download a file, which has the same blocks locally") {
  814. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  815. sup->do_process();
  816. auto index = proto::Index{};
  817. index.set_folder(std::string(folder_1->get_id()));
  818. auto file_1 = index.add_files();
  819. file_1->set_name("some-file");
  820. file_1->set_type(proto::FileInfoType::FILE);
  821. file_1->set_sequence(folder_1_peer->get_max_sequence() + 1);
  822. auto v1 = file_1->mutable_version();
  823. auto c1 = v1->add_counters();
  824. c1->set_id(1u);
  825. c1->set_value(1u);
  826. file_1->set_block_size(5);
  827. file_1->set_size(10);
  828. auto b1 = file_1->add_blocks();
  829. b1->set_hash(utils::sha256_digest("12345").value());
  830. b1->set_offset(0);
  831. b1->set_size(5);
  832. auto bi_1 = model::block_info_t::create(*b1).value();
  833. auto b2 = file_1->add_blocks();
  834. b2->set_hash(utils::sha256_digest("67890").value());
  835. b2->set_offset(5);
  836. b2->set_size(5);
  837. auto bi_2 = model::block_info_t::create(*b2).value();
  838. auto &blocks = cluster->get_blocks();
  839. blocks.put(bi_1);
  840. blocks.put(bi_2);
  841. auto pr_my = proto::FileInfo{};
  842. pr_my.set_name("some-file.source");
  843. pr_my.set_type(proto::FileInfoType::FILE);
  844. pr_my.set_sequence(2ul);
  845. pr_my.set_block_size(5);
  846. pr_my.set_size(5);
  847. pr_my.mutable_version()->add_counters()->set_id(my_device->device_id().get_uint());
  848. auto uuid = sup->sequencer->next_uuid();
  849. auto file_my = model::file_info_t::create(uuid, pr_my, folder_my).value();
  850. file_my->assign_block(bi_1, 0);
  851. file_my->mark_local_available(0);
  852. REQUIRE(folder_my->add_strict(file_my));
  853. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  854. peer_actor->push_block("67890", 1);
  855. cluster->modify_write_requests(10);
  856. sup->do_process();
  857. REQUIRE(folder_my->get_file_infos().size() == 2);
  858. auto f = folder_my->get_file_infos().by_name(file_1->name());
  859. REQUIRE(f);
  860. CHECK(f->get_name() == file_1->name());
  861. CHECK(f->get_size() == 10);
  862. CHECK(f->get_blocks().size() == 2);
  863. CHECK(f->is_locally_available());
  864. CHECK(!f->is_locked());
  865. }
  866. }
  867. };
  868. F(true, 10).run();
  869. }
  870. void test_downloading_errors() {
  871. struct F : fixture_t {
  872. using fixture_t::fixture_t;
  873. void main(diff_builder_t &) noexcept override {
  874. auto &folder_infos = folder_1->get_folder_infos();
  875. auto folder_my = folder_infos.by_device(*my_device);
  876. auto cc = proto::ClusterConfig{};
  877. auto folder = cc.add_folders();
  878. folder->set_id(std::string(folder_1->get_id()));
  879. auto d_peer = folder->add_devices();
  880. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  881. d_peer->set_max_sequence(folder_1_peer->get_max_sequence() + 1);
  882. d_peer->set_index_id(folder_1_peer->get_index());
  883. auto d_my = folder->add_devices();
  884. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  885. d_my->set_max_sequence(folder_my->get_max_sequence());
  886. d_my->set_index_id(folder_my->get_index());
  887. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  888. auto index = proto::Index{};
  889. index.set_folder(std::string(folder_1->get_id()));
  890. auto file = index.add_files();
  891. file->set_name("some-file");
  892. file->set_type(proto::FileInfoType::FILE);
  893. file->set_sequence(folder_1_peer->get_max_sequence() + 1);
  894. file->set_block_size(5);
  895. file->set_size(5);
  896. auto version = file->mutable_version();
  897. auto counter = version->add_counters();
  898. counter->set_id(1ul);
  899. counter->set_value(1ul);
  900. auto b1 = file->add_blocks();
  901. b1->set_hash(utils::sha256_digest("12345").value());
  902. b1->set_offset(0);
  903. b1->set_size(5);
  904. CHECK(folder_my->get_max_sequence() == 0ul);
  905. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  906. SECTION("general error, ok, do not shutdown") {
  907. auto ec = utils::make_error_code(utils::request_error_code_t::generic);
  908. peer_actor->push_block(ec, 0);
  909. }
  910. SECTION("hash mismatch, do not shutdown") { peer_actor->push_block("zzz", 0); }
  911. sup->do_process();
  912. CHECK(peer_actor->blocks_requested == 1);
  913. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  914. auto folder_peer = folder_infos.by_device(*peer_device);
  915. REQUIRE(folder_peer->get_file_infos().size() == 1);
  916. auto f = folder_peer->get_file_infos().begin()->item;
  917. REQUIRE(f);
  918. CHECK(f->is_unreachable());
  919. CHECK(!f->is_synchronizing());
  920. CHECK(!f->is_locked());
  921. CHECK(!f->local_file());
  922. CHECK(!folder_my->get_folder()->is_synchronizing());
  923. sup->do_process();
  924. }
  925. };
  926. F(true, 10).run();
  927. }
  928. void test_download_from_scratch() {
  929. struct F : fixture_t {
  930. using fixture_t::fixture_t;
  931. void main(diff_builder_t &) noexcept override {
  932. sup->do_process();
  933. peer_actor->messages.clear();
  934. auto builder = diff_builder_t(*cluster);
  935. auto sha256 = peer_device->device_id().get_sha256();
  936. auto cc = proto::ClusterConfig{};
  937. auto folder = cc.add_folders();
  938. folder->set_id(std::string(folder_1->get_id()));
  939. {
  940. auto device = folder->add_devices();
  941. device->set_id(std::string(peer_device->device_id().get_sha256()));
  942. device->set_max_sequence(15);
  943. device->set_index_id(12345);
  944. }
  945. {
  946. auto device = folder->add_devices();
  947. device->set_id(std::string(my_device->device_id().get_sha256()));
  948. device->set_max_sequence(0);
  949. device->set_index_id(0);
  950. }
  951. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  952. sup->do_process();
  953. builder.share_folder(sha256, folder_1->get_id()).apply(*sup);
  954. auto index = proto::Index{};
  955. index.set_folder(std::string(folder_1->get_id()));
  956. auto file = index.add_files();
  957. file->set_name("some-file");
  958. file->set_type(proto::FileInfoType::FILE);
  959. file->set_sequence(154);
  960. file->set_block_size(5);
  961. file->set_size(5);
  962. auto version = file->mutable_version();
  963. auto counter = version->add_counters();
  964. counter->set_id(1ul);
  965. counter->set_value(1ul);
  966. auto b1 = file->add_blocks();
  967. b1->set_hash(utils::sha256_digest("12345").value());
  968. b1->set_offset(0);
  969. b1->set_size(5);
  970. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  971. peer_actor->push_block("12345", 0, file->name());
  972. sup->do_process();
  973. auto folder_my = folder_1->get_folder_infos().by_device(*my_device);
  974. CHECK(folder_my->get_max_sequence() == 1ul);
  975. CHECK(!folder_my->get_folder()->is_synchronizing());
  976. auto f = folder_my->get_file_infos().by_name(file->name());
  977. REQUIRE(f);
  978. CHECK(f->get_size() == 5);
  979. CHECK(f->get_blocks().size() == 1);
  980. CHECK(f->is_locally_available());
  981. CHECK(!f->is_locked());
  982. REQUIRE(peer_actor->messages.size() == 3);
  983. {
  984. auto peer_msg = &peer_actor->messages.front()->payload;
  985. REQUIRE(std::get_if<proto::message::ClusterConfig>(peer_msg));
  986. peer_actor->messages.pop_front();
  987. peer_msg = &peer_actor->messages.front()->payload;
  988. REQUIRE(std::get_if<proto::message::Index>(peer_msg));
  989. peer_actor->messages.pop_front();
  990. peer_msg = &peer_actor->messages.front()->payload;
  991. REQUIRE(std::get_if<proto::message::IndexUpdate>(peer_msg));
  992. }
  993. }
  994. };
  995. F(false, 10, false).run();
  996. }
  997. void test_download_resuming() {
  998. struct F : fixture_t {
  999. using fixture_t::fixture_t;
  1000. void main(diff_builder_t &) noexcept override {
  1001. sup->do_process();
  1002. auto builder = diff_builder_t(*cluster);
  1003. auto sha256 = peer_device->device_id().get_sha256();
  1004. auto cc = proto::ClusterConfig{};
  1005. auto folder = cc.add_folders();
  1006. folder->set_id(std::string(folder_1->get_id()));
  1007. auto d_peer = folder->add_devices();
  1008. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  1009. d_peer->set_max_sequence(15);
  1010. d_peer->set_index_id(12345);
  1011. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  1012. sup->do_process();
  1013. builder.share_folder(sha256, folder_1->get_id()).apply(*sup);
  1014. auto folder_peer = folder_1->get_folder_infos().by_device(*peer_device);
  1015. REQUIRE(folder_peer->get_index() == d_peer->index_id());
  1016. auto index = proto::Index{};
  1017. index.set_folder(std::string(folder_1->get_id()));
  1018. auto file = index.add_files();
  1019. file->set_name("some-file");
  1020. file->set_type(proto::FileInfoType::FILE);
  1021. file->set_sequence(154);
  1022. file->set_block_size(5);
  1023. file->set_size(10);
  1024. auto version = file->mutable_version();
  1025. auto counter = version->add_counters();
  1026. counter->set_id(1ul);
  1027. counter->set_value(1ul);
  1028. auto b1 = file->add_blocks();
  1029. b1->set_hash(utils::sha256_digest("12345").value());
  1030. b1->set_offset(0);
  1031. b1->set_size(5);
  1032. auto b2 = file->add_blocks();
  1033. b2->set_hash(utils::sha256_digest("67890").value());
  1034. b2->set_offset(5);
  1035. b2->set_size(5);
  1036. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  1037. peer_actor->push_block("12345", 0, file->name());
  1038. sup->do_process();
  1039. target->do_shutdown();
  1040. sup->do_process();
  1041. CHECK(!folder_1->is_synchronizing());
  1042. for (auto &it : cluster->get_blocks()) {
  1043. REQUIRE(!it.item->is_locked());
  1044. }
  1045. start_target();
  1046. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  1047. peer_actor->push_block("67890", 1, file->name());
  1048. sup->do_process();
  1049. auto folder_my = folder_1->get_folder_infos().by_device(*my_device);
  1050. CHECK(folder_my->get_max_sequence() == 1ul);
  1051. CHECK(!folder_my->get_folder()->is_synchronizing());
  1052. auto f = folder_my->get_file_infos().by_name(file->name());
  1053. REQUIRE(f);
  1054. CHECK(f->get_size() == 10);
  1055. CHECK(f->get_blocks().size() == 2);
  1056. CHECK(f->is_locally_available());
  1057. CHECK(!f->is_locked());
  1058. }
  1059. };
  1060. F(false, 10, false).run();
  1061. }
  1062. void test_initiate_my_sharing() {
  1063. struct F : fixture_t {
  1064. using fixture_t::fixture_t;
  1065. void main(diff_builder_t &) noexcept override {
  1066. sup->do_process();
  1067. auto cc = proto::ClusterConfig{};
  1068. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  1069. // nothing is shared
  1070. sup->do_process();
  1071. REQUIRE(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1072. REQUIRE(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1073. REQUIRE(peer_actor->messages.size() == 1);
  1074. auto peer_msg = &peer_actor->messages.front()->payload;
  1075. auto peer_cluster_msg = std::get_if<proto::message::ClusterConfig>(peer_msg);
  1076. REQUIRE(peer_cluster_msg);
  1077. REQUIRE(*peer_cluster_msg);
  1078. REQUIRE((*peer_cluster_msg)->folders_size() == 0);
  1079. // share folder_1
  1080. peer_actor->messages.clear();
  1081. auto sha256 = peer_device->device_id().get_sha256();
  1082. diff_builder_t(*cluster).share_folder(sha256, folder_1->get_id()).apply(*sup);
  1083. REQUIRE(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1084. REQUIRE(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1085. REQUIRE(peer_actor->messages.size() == 1);
  1086. {
  1087. auto peer_msg = &peer_actor->messages.front()->payload;
  1088. auto peer_cluster_msg = std::get_if<proto::message::ClusterConfig>(peer_msg);
  1089. REQUIRE((peer_cluster_msg && *peer_cluster_msg));
  1090. auto &msg = *peer_cluster_msg;
  1091. REQUIRE(msg->folders_size() == 1);
  1092. auto f = msg->folders(0);
  1093. REQUIRE(f.devices_size() == 2);
  1094. using f_t = std::remove_reference_t<std::remove_cv_t<decltype(f.devices(0))>>;
  1095. auto f_my = (f_t *){};
  1096. auto f_peer = (f_t *){};
  1097. for (int i = 0; i < f.devices_size(); ++i) {
  1098. auto &d = f.devices(i);
  1099. if (d.id() == my_device->device_id().get_sha256()) {
  1100. f_my = &d;
  1101. } else if (d.id() == peer_device->device_id().get_sha256()) {
  1102. f_peer = &d;
  1103. }
  1104. }
  1105. REQUIRE(f_peer);
  1106. CHECK(!f_peer->index_id());
  1107. CHECK(f_peer->max_sequence() == 0);
  1108. REQUIRE(f_my);
  1109. auto folder_my = folder_1->get_folder_infos().by_device(*my_device);
  1110. CHECK(f_my->index_id() == folder_my->get_index());
  1111. CHECK(f_my->max_sequence() == 0);
  1112. }
  1113. // unshare folder_1
  1114. auto peer_fi = folder_1->get_folder_infos().by_device(*peer_device);
  1115. peer_actor->messages.clear();
  1116. diff_builder_t(*cluster).unshare_folder(*peer_fi).apply(*sup);
  1117. REQUIRE(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1118. REQUIRE(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1119. REQUIRE(peer_actor->messages.size() == 1);
  1120. peer_msg = &peer_actor->messages.front()->payload;
  1121. peer_cluster_msg = std::get_if<proto::message::ClusterConfig>(peer_msg);
  1122. REQUIRE(peer_cluster_msg);
  1123. REQUIRE(*peer_cluster_msg);
  1124. REQUIRE((*peer_cluster_msg)->folders_size() == 0);
  1125. }
  1126. };
  1127. F(false, 10, false).run();
  1128. }
  1129. void test_initiate_peer_sharing() {
  1130. struct F : fixture_t {
  1131. using fixture_t::fixture_t;
  1132. void main(diff_builder_t &) noexcept override {
  1133. sup->do_process();
  1134. auto cc = proto::ClusterConfig{};
  1135. auto folder = cc.add_folders();
  1136. folder->set_id(std::string(folder_1->get_id()));
  1137. {
  1138. auto device = folder->add_devices();
  1139. device->set_id(std::string(peer_device->device_id().get_sha256()));
  1140. device->set_max_sequence(15);
  1141. device->set_index_id(0x12345);
  1142. }
  1143. {
  1144. auto device = folder->add_devices();
  1145. device->set_id(std::string(my_device->device_id().get_sha256()));
  1146. device->set_max_sequence(0);
  1147. device->set_index_id(0x0);
  1148. }
  1149. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  1150. sup->do_process();
  1151. REQUIRE(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1152. REQUIRE(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1153. REQUIRE(peer_actor->messages.size() == 1);
  1154. {
  1155. auto peer_msg = &peer_actor->messages.front()->payload;
  1156. auto peer_cluster_msg = std::get_if<proto::message::ClusterConfig>(peer_msg);
  1157. REQUIRE(peer_cluster_msg);
  1158. REQUIRE(*peer_cluster_msg);
  1159. REQUIRE((*peer_cluster_msg)->folders_size() == 0);
  1160. }
  1161. // share folder_1
  1162. peer_actor->messages.clear();
  1163. auto sha256 = peer_device->device_id().get_sha256();
  1164. diff_builder_t(*cluster).share_folder(sha256, folder_1->get_id()).apply(*sup);
  1165. REQUIRE(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1166. REQUIRE(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1167. REQUIRE(peer_actor->messages.size() == 2);
  1168. {
  1169. auto peer_msg = &peer_actor->messages.front()->payload;
  1170. auto peer_cluster_msg = std::get_if<proto::message::ClusterConfig>(peer_msg);
  1171. REQUIRE((peer_cluster_msg && *peer_cluster_msg));
  1172. auto &msg = *peer_cluster_msg;
  1173. REQUIRE(msg->folders_size() == 1);
  1174. auto f = msg->folders(0);
  1175. REQUIRE(f.devices_size() == 2);
  1176. using f_t = std::remove_reference_t<std::remove_cv_t<decltype(f.devices(0))>>;
  1177. auto f_my = (f_t *){};
  1178. auto f_peer = (f_t *){};
  1179. for (int i = 0; i < f.devices_size(); ++i) {
  1180. auto &d = f.devices(i);
  1181. if (d.id() == my_device->device_id().get_sha256()) {
  1182. f_my = &d;
  1183. } else if (d.id() == peer_device->device_id().get_sha256()) {
  1184. f_peer = &d;
  1185. }
  1186. }
  1187. REQUIRE(f_peer);
  1188. CHECK(f_peer->index_id() == 0x12345);
  1189. CHECK(f_peer->max_sequence() == 0);
  1190. REQUIRE(f_my);
  1191. auto folder_my = folder_1->get_folder_infos().by_device(*my_device);
  1192. CHECK(f_my->index_id() == folder_my->get_index());
  1193. CHECK(f_my->max_sequence() == 0);
  1194. peer_actor->messages.pop_front();
  1195. peer_msg = &peer_actor->messages.front()->payload;
  1196. auto &index_msg = std::get<proto::message::Index>(*peer_msg);
  1197. CHECK(index_msg->folder() == folder_1->get_id());
  1198. CHECK(index_msg->files_size() == 0);
  1199. }
  1200. // unshare folder_1
  1201. auto peer_fi = folder_1->get_folder_infos().by_device(*peer_device);
  1202. peer_actor->messages.clear();
  1203. diff_builder_t(*cluster).unshare_folder(*peer_fi).apply(*sup);
  1204. REQUIRE(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1205. REQUIRE(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  1206. REQUIRE(peer_actor->messages.size() == 1);
  1207. {
  1208. auto peer_msg = &peer_actor->messages.front()->payload;
  1209. auto peer_cluster_msg = std::get_if<proto::message::ClusterConfig>(peer_msg);
  1210. REQUIRE(peer_cluster_msg);
  1211. REQUIRE(*peer_cluster_msg);
  1212. REQUIRE((*peer_cluster_msg)->folders_size() == 0);
  1213. }
  1214. }
  1215. };
  1216. F(false, 10, false).run();
  1217. }
  1218. void test_sending_index_updates() {
  1219. struct F : fixture_t {
  1220. using fixture_t::fixture_t;
  1221. void main(diff_builder_t &) noexcept override {
  1222. auto &folder_infos = folder_1->get_folder_infos();
  1223. auto folder_my = folder_infos.by_device(*my_device);
  1224. auto cc = proto::ClusterConfig{};
  1225. auto folder = cc.add_folders();
  1226. folder->set_id(std::string(folder_1->get_id()));
  1227. auto d_peer = folder->add_devices();
  1228. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  1229. d_peer->set_max_sequence(folder_1_peer->get_max_sequence());
  1230. d_peer->set_index_id(folder_1_peer->get_index());
  1231. auto d_my = folder->add_devices();
  1232. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  1233. d_my->set_max_sequence(folder_my->get_max_sequence());
  1234. d_my->set_index_id(folder_my->get_index());
  1235. auto index = proto::Index{};
  1236. auto folder_id = std::string(folder_1->get_id());
  1237. index.set_folder(folder_id);
  1238. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  1239. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  1240. sup->do_process();
  1241. auto builder = diff_builder_t(*cluster);
  1242. auto pr_file = proto::FileInfo();
  1243. pr_file.set_name("a.txt");
  1244. peer_actor->messages.clear();
  1245. builder.local_update(folder_id, pr_file).apply(*sup);
  1246. REQUIRE(peer_actor->messages.size() == 1);
  1247. auto &msg = peer_actor->messages.front();
  1248. auto &index_update = *std::get<proto::message::IndexUpdate>(msg->payload);
  1249. REQUIRE(index_update.files_size() == 1);
  1250. CHECK(index_update.files(0).name() == "a.txt");
  1251. }
  1252. };
  1253. F(true, 10).run();
  1254. }
  1255. void test_uploading() {
  1256. struct F : fixture_t {
  1257. using fixture_t::fixture_t;
  1258. void main(diff_builder_t &) noexcept override {
  1259. auto &folder_infos = folder_1->get_folder_infos();
  1260. auto folder_my = folder_infos.by_device(*my_device);
  1261. auto cc = proto::ClusterConfig{};
  1262. auto folder = cc.add_folders();
  1263. folder->set_id(std::string(folder_1->get_id()));
  1264. auto d_peer = folder->add_devices();
  1265. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  1266. d_peer->set_max_sequence(folder_1_peer->get_max_sequence());
  1267. d_peer->set_index_id(folder_1_peer->get_index());
  1268. auto d_my = folder->add_devices();
  1269. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  1270. d_my->set_max_sequence(folder_my->get_max_sequence());
  1271. d_my->set_index_id(folder_my->get_index());
  1272. auto pr_fi = proto::FileInfo{};
  1273. pr_fi.set_name("data.bin");
  1274. pr_fi.set_type(proto::FileInfoType::FILE);
  1275. pr_fi.set_sequence(folder_1_peer->get_max_sequence());
  1276. pr_fi.set_block_size(5);
  1277. pr_fi.set_size(5);
  1278. auto version = pr_fi.mutable_version();
  1279. auto counter = version->add_counters();
  1280. counter->set_id(1);
  1281. counter->set_value(my_device->device_id().get_uint());
  1282. auto b1 = pr_fi.add_blocks();
  1283. b1->set_hash(utils::sha256_digest("12345").value());
  1284. b1->set_offset(0);
  1285. b1->set_size(5);
  1286. auto b = model::block_info_t::create(*b1).value();
  1287. auto uuid = sup->sequencer->next_uuid();
  1288. pr_fi.set_sequence(folder_my->get_max_sequence() + 1);
  1289. auto file_info = model::file_info_t::create(uuid, pr_fi, folder_my).value();
  1290. file_info->assign_block(b, 0);
  1291. REQUIRE(folder_my->add_strict(file_info));
  1292. auto req = proto::Request();
  1293. req.set_id(1);
  1294. req.set_folder(std::string(folder_1->get_id()));
  1295. req.set_name("data.bin");
  1296. req.set_offset(0);
  1297. req.set_size(5);
  1298. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  1299. SECTION("upload regular file, no hash") {
  1300. peer_actor->forward(proto::message::Request(new proto::Request(req)));
  1301. auto req_ptr = proto::message::Request(new proto::Request(req));
  1302. auto res = r::make_message<fs::payload::block_response_t>(target->get_address(), std::move(req_ptr),
  1303. sys::error_code{}, std::string("12345"));
  1304. block_responses.push_back(res);
  1305. sup->do_process();
  1306. REQUIRE(block_requests.size() == 1);
  1307. CHECK(block_requests[0]->payload.remote_request->id() == 1);
  1308. CHECK(block_requests[0]->payload.remote_request->name() == "data.bin");
  1309. REQUIRE(peer_actor->uploaded_blocks.size() == 1);
  1310. auto &peer_res = *peer_actor->uploaded_blocks.front();
  1311. CHECK(peer_res.id() == 1);
  1312. CHECK(peer_res.code() == proto::ErrorCode::NO_BEP_ERROR);
  1313. CHECK(peer_res.data() == "12345");
  1314. }
  1315. }
  1316. };
  1317. F(true, 10).run();
  1318. }
  1319. void test_peer_removal() {
  1320. struct F : fixture_t {
  1321. using fixture_t::fixture_t;
  1322. void main(diff_builder_t &builder) noexcept override {
  1323. builder.remove_peer(*peer_device).apply(*sup);
  1324. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::SHUT_DOWN);
  1325. CHECK(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::SHUT_DOWN);
  1326. CHECK(target->get_shutdown_reason()->root()->ec == utils::error_code_t::peer_has_been_removed);
  1327. }
  1328. };
  1329. F(true, 10).run();
  1330. }
  1331. void test_conflicts() {
  1332. struct F : fixture_t {
  1333. using fixture_t::fixture_t;
  1334. void main(diff_builder_t &) noexcept override {
  1335. sup->do_process();
  1336. auto builder = diff_builder_t(*cluster);
  1337. auto sha256 = peer_device->device_id().get_sha256();
  1338. auto cc = proto::ClusterConfig{};
  1339. auto folder = cc.add_folders();
  1340. folder->set_id(std::string(folder_1->get_id()));
  1341. auto d_peer = folder->add_devices();
  1342. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  1343. d_peer->set_max_sequence(15);
  1344. d_peer->set_index_id(12345);
  1345. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  1346. sup->do_process();
  1347. builder.share_folder(sha256, folder_1->get_id()).apply(*sup);
  1348. auto folder_peer = folder_1->get_folder_infos().by_device(*peer_device);
  1349. REQUIRE(folder_peer->get_index() == d_peer->index_id());
  1350. auto index = proto::Index{};
  1351. index.set_folder(std::string(folder_1->get_id()));
  1352. auto file = index.add_files();
  1353. file->set_name("some-file.txt");
  1354. file->set_type(proto::FileInfoType::FILE);
  1355. file->set_sequence(154);
  1356. file->set_block_size(5);
  1357. file->set_size(5);
  1358. auto version = file->mutable_version();
  1359. auto c1 = version->add_counters();
  1360. c1->set_id(1ul);
  1361. c1->set_value(1ul);
  1362. auto b1 = file->add_blocks();
  1363. b1->set_hash(utils::sha256_digest("12345").value());
  1364. b1->set_offset(0);
  1365. b1->set_size(5);
  1366. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  1367. peer_actor->push_block("12345", 0, file->name());
  1368. sup->do_process();
  1369. auto &folder_infos = folder_1->get_folder_infos();
  1370. auto local_folder = folder_infos.by_device(*my_device);
  1371. auto local_file = local_folder->get_file_infos().by_name(file->name());
  1372. auto pr_file = local_file->as_proto(false);
  1373. auto bi_2 = pr_file.mutable_blocks()->Add();
  1374. bi_2->set_hash(utils::sha256_digest("67890").value());
  1375. bi_2->set_size(5);
  1376. pr_file.set_modified_s(1734680000);
  1377. builder.local_update(folder_1->get_id(), pr_file);
  1378. builder.apply(*sup);
  1379. file->clear_blocks();
  1380. file->set_sequence(155);
  1381. c1->set_id(peer_device->device_id().get_uint());
  1382. auto b3 = file->add_blocks();
  1383. b3->set_hash(utils::sha256_digest("12346").value());
  1384. b3->set_offset(0);
  1385. b3->set_size(5);
  1386. auto index_update = proto::IndexUpdate{};
  1387. index_update.set_folder(std::string(folder_1->get_id()));
  1388. SECTION("local win") {
  1389. file->set_modified_s(1734670000);
  1390. c1->set_value(local_file->get_version()->get_best().value() - 1);
  1391. auto local_seq = local_file->get_sequence();
  1392. *index_update.add_files() = *file;
  1393. peer_actor->messages.clear();
  1394. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index_update)));
  1395. sup->do_process();
  1396. REQUIRE(local_folder->get_file_infos().size() == 1);
  1397. auto lf = local_folder->get_file_infos().by_sequence(local_seq);
  1398. REQUIRE(local_seq == lf->get_sequence());
  1399. CHECK(cluster->get_blocks().size() == 2);
  1400. CHECK(peer_actor->messages.size() == 0);
  1401. }
  1402. SECTION("remote win") {
  1403. file->set_modified_s(1734690000);
  1404. c1->set_value(local_file->get_version()->get_best().value() + 1);
  1405. *index_update.add_files() = *file;
  1406. peer_actor->push_block("12346", 0, file->name());
  1407. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index_update)));
  1408. sup->do_process();
  1409. auto local_folder = folder_infos.by_device(*my_device);
  1410. auto local_conflict = local_folder->get_file_infos().by_name(local_file->make_conflicting_name());
  1411. REQUIRE(local_conflict);
  1412. CHECK(local_conflict->get_size() == 5);
  1413. REQUIRE(local_conflict->get_blocks().size() == 1);
  1414. CHECK(local_conflict->get_blocks()[0]->get_hash() == bi_2->hash());
  1415. auto file = local_folder->get_file_infos().by_name(local_file->get_name());
  1416. REQUIRE(file);
  1417. CHECK(file->get_size() == 5);
  1418. REQUIRE(file->get_blocks().size() == 1);
  1419. CHECK(file->get_blocks()[0]->get_hash() == b3->hash());
  1420. CHECK(cluster->get_blocks().size() == 2);
  1421. auto &msg = peer_actor->messages.back();
  1422. auto &index_update_sent = *std::get<proto::message::IndexUpdate>(msg->payload);
  1423. REQUIRE(index_update_sent.files_size() == 2);
  1424. CHECK(index_update_sent.files(0).name() == local_conflict->get_name());
  1425. CHECK(index_update_sent.files(1).name() == file->get_name());
  1426. }
  1427. }
  1428. };
  1429. F(false, 10, false).run();
  1430. }
  1431. int _init() {
  1432. REGISTER_TEST_CASE(test_startup, "test_startup", "[net]");
  1433. REGISTER_TEST_CASE(test_index_receiving, "test_index_receiving", "[net]");
  1434. REGISTER_TEST_CASE(test_index_sending, "test_index_sending", "[net]");
  1435. REGISTER_TEST_CASE(test_downloading, "test_downloading", "[net]");
  1436. REGISTER_TEST_CASE(test_downloading_errors, "test_downloading_errors", "[net]");
  1437. REGISTER_TEST_CASE(test_download_from_scratch, "test_download_from_scratch", "[net]");
  1438. REGISTER_TEST_CASE(test_download_resuming, "test_download_resuming", "[net]");
  1439. REGISTER_TEST_CASE(test_initiate_my_sharing, "test_initiate_my_sharing", "[net]");
  1440. REGISTER_TEST_CASE(test_initiate_peer_sharing, "test_initiate_peer_sharing", "[net]");
  1441. REGISTER_TEST_CASE(test_sending_index_updates, "test_sending_index_updates", "[net]");
  1442. REGISTER_TEST_CASE(test_uploading, "test_uploading", "[net]");
  1443. REGISTER_TEST_CASE(test_peer_removal, "test_peer_removal", "[net]");
  1444. REGISTER_TEST_CASE(test_conflicts, "test_conflicts", "[net]");
  1445. return 1;
  1446. }
  1447. static int v = _init();