075-controller.cpp 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117
  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. using namespace syncspirit;
  17. using namespace syncspirit::test;
  18. using namespace syncspirit::model;
  19. using namespace syncspirit::net;
  20. using namespace syncspirit::hasher;
  21. namespace {
  22. struct sample_peer_config_t : public r::actor_config_t {
  23. model::device_id_t peer_device_id;
  24. };
  25. template <typename Actor> struct sample_peer_config_builder_t : r::actor_config_builder_t<Actor> {
  26. using builder_t = typename Actor::template config_builder_t<Actor>;
  27. using parent_t = r::actor_config_builder_t<Actor>;
  28. using parent_t::parent_t;
  29. builder_t &&peer_device_id(const model::device_id_t &value) && noexcept {
  30. parent_t::config.peer_device_id = value;
  31. return std::move(*static_cast<typename parent_t::builder_t *>(this));
  32. }
  33. };
  34. struct sample_peer_t : r::actor_base_t {
  35. using config_t = sample_peer_config_t;
  36. template <typename Actor> using config_builder_t = sample_peer_config_builder_t<Actor>;
  37. using remote_message_t = r::intrusive_ptr_t<net::message::forwarded_message_t>;
  38. using remote_messages_t = std::list<remote_message_t>;
  39. struct block_response_t {
  40. size_t block_index;
  41. std::string data;
  42. sys::error_code ec;
  43. };
  44. using block_responses_t = std::list<block_response_t>;
  45. using block_request_t = r::intrusive_ptr_t<net::message::block_request_t>;
  46. using block_requests_t = std::list<block_request_t>;
  47. using uploaded_blocks_t = std::list<proto::message::Response>;
  48. sample_peer_t(config_t &config) : r::actor_base_t{config}, peer_device{config.peer_device_id} {
  49. log = utils::get_logger("test.sample_peer");
  50. }
  51. void configure(r::plugin::plugin_base_t &plugin) noexcept override {
  52. r::actor_base_t::configure(plugin);
  53. plugin.with_casted<r::plugin::address_maker_plugin_t>([&](auto &p) { p.set_identity("sample_peer", false); });
  54. plugin.with_casted<r::plugin::starter_plugin_t>([&](auto &p) {
  55. p.subscribe_actor(&sample_peer_t::on_start_reading);
  56. p.subscribe_actor(&sample_peer_t::on_termination);
  57. p.subscribe_actor(&sample_peer_t::on_transfer);
  58. p.subscribe_actor(&sample_peer_t::on_block_request);
  59. });
  60. }
  61. void shutdown_start() noexcept override {
  62. LOG_TRACE(log, "{}, shutdown_start", identity);
  63. if (controller) {
  64. send<net::payload::termination_t>(controller, shutdown_reason);
  65. }
  66. r::actor_base_t::shutdown_start();
  67. }
  68. void shutdown_finish() noexcept override {
  69. r::actor_base_t::shutdown_finish();
  70. LOG_TRACE(log, "{}, shutdown_finish, blocks requested = {}", identity, blocks_requested);
  71. if (controller) {
  72. send<net::payload::termination_t>(controller, shutdown_reason);
  73. }
  74. }
  75. void on_start_reading(net::message::start_reading_t &msg) noexcept {
  76. LOG_TRACE(log, "{}, on_start_reading", identity);
  77. controller = msg.payload.controller;
  78. reading = msg.payload.start;
  79. }
  80. void on_termination(net::message::termination_signal_t &msg) noexcept {
  81. LOG_TRACE(log, "{}, on_termination", identity);
  82. if (!shutdown_reason) {
  83. auto &ee = msg.payload.ee;
  84. auto reason = ee->message();
  85. LOG_TRACE(log, "{}, on_termination: {}", identity, reason);
  86. do_shutdown(ee);
  87. }
  88. }
  89. void on_transfer(net::message::transfer_data_t &message) noexcept {
  90. auto &data = message.payload.data;
  91. LOG_TRACE(log, "{}, on_transfer, bytes = {}", identity, data.size());
  92. auto buff = boost::asio::buffer(data.data(), data.size());
  93. auto result = proto::parse_bep(buff);
  94. auto orig = std::move(result.value().message);
  95. auto variant = net::payload::forwarded_message_t();
  96. std::visit(
  97. [&](auto &msg) {
  98. using boost::core::demangle;
  99. using T = std::decay_t<decltype(msg)>;
  100. LOG_TRACE(log, "{}, received '{}' message", identity, demangle(typeid(T).name()));
  101. using V = net::payload::forwarded_message_t;
  102. if constexpr (std::is_constructible_v<V, T>) {
  103. variant = std::move(msg);
  104. } else if constexpr (std::is_same_v<T, proto::message::Response>) {
  105. uploaded_blocks.push_back(std::move(msg));
  106. }
  107. },
  108. orig);
  109. auto fwd_msg = new net::message::forwarded_message_t(address, std::move(variant));
  110. messages.emplace_back(fwd_msg);
  111. }
  112. void on_block_request(net::message::block_request_t &req) noexcept {
  113. block_requests.push_front(&req);
  114. ++blocks_requested;
  115. log->debug("{}, requesting block # {}", identity,
  116. block_requests.front()->payload.request_payload.block.block_index());
  117. if (block_responses.size()) {
  118. log->debug("{}, top response block # {}", identity, block_responses.front().block_index);
  119. }
  120. auto condition = [&]() -> bool {
  121. return block_requests.size() && block_responses.size() &&
  122. block_requests.front()->payload.request_payload.block.block_index() ==
  123. block_responses.front().block_index;
  124. };
  125. while (condition()) {
  126. auto &reply = block_responses.front();
  127. auto &request = *block_requests.front();
  128. log->debug("{}, matched, replying..., ec = {}", identity, reply.ec.value());
  129. if (!reply.ec) {
  130. reply_to(request, reply.data);
  131. } else {
  132. reply_with_error(request, make_error(reply.ec));
  133. }
  134. block_responses.pop_front();
  135. block_requests.pop_front();
  136. }
  137. }
  138. void forward(net::payload::forwarded_message_t payload) noexcept {
  139. send<net::payload::forwarded_message_t>(controller, std::move(payload));
  140. }
  141. static const constexpr size_t next_block = 1000000;
  142. void push_block(std::string_view data, size_t index) {
  143. if (index == next_block) {
  144. index = block_responses.size();
  145. }
  146. block_responses.push_back(block_response_t{index, std::string(data)});
  147. }
  148. void push_block(sys::error_code ec, size_t index) {
  149. if (index == next_block) {
  150. index = block_responses.size();
  151. }
  152. block_responses.push_back(block_response_t{index, std::string{}, ec});
  153. }
  154. size_t blocks_requested = 0;
  155. bool reading = false;
  156. remote_messages_t messages;
  157. r::address_ptr_t controller;
  158. model::device_id_t peer_device;
  159. utils::logger_t log;
  160. block_requests_t block_requests;
  161. block_responses_t block_responses;
  162. uploaded_blocks_t uploaded_blocks;
  163. };
  164. struct fixture_t {
  165. using peer_ptr_t = r::intrusive_ptr_t<sample_peer_t>;
  166. using target_ptr_t = r::intrusive_ptr_t<net::controller_actor_t>;
  167. using blk_req_t = fs::message::block_request_t;
  168. using blk_req_ptr_t = r::intrusive_ptr_t<blk_req_t>;
  169. using blk_res_t = fs::message::block_response_t;
  170. using blk_res_ptr_t = r::intrusive_ptr_t<blk_res_t>;
  171. using block_requests_t = std::deque<blk_req_ptr_t>;
  172. using block_responses_t = std::deque<r::message_ptr_t>;
  173. fixture_t(bool auto_start_, int64_t max_sequence_, bool auto_share_ = true) noexcept
  174. : auto_start{auto_start_}, max_sequence{max_sequence_}, auto_share{auto_share_} {
  175. utils::set_default("trace");
  176. }
  177. virtual void run() noexcept {
  178. auto peer_id =
  179. device_id_t::from_string("VUV42CZ-IQD5A37-RPEBPM4-VVQK6E4-6WSKC7B-PVJQHHD-4PZD44V-ENC6WAZ").value();
  180. peer_device = device_t::create(peer_id, "peer-device").value();
  181. auto my_id =
  182. device_id_t::from_string("KHQNO2S-5QSILRK-YX4JZZ4-7L77APM-QNVGZJT-EKU7IFI-PNEPBMY-4MXFMQD").value();
  183. my_device = device_t::create(my_id, "my-device").value();
  184. cluster = new cluster_t(my_device, 1, 1);
  185. cluster->get_devices().put(my_device);
  186. cluster->get_devices().put(peer_device);
  187. auto folder_id_1 = "1234-5678";
  188. auto folder_id_2 = "5555";
  189. auto builder = diff_builder_t(*cluster);
  190. auto sha256 = peer_id.get_sha256();
  191. builder.create_folder(folder_id_1, "")
  192. .create_folder(folder_id_2, "")
  193. .configure_cluster(sha256)
  194. .add(sha256, folder_id_1, 123, max_sequence)
  195. .finish();
  196. if (auto_share) {
  197. builder.share_folder(peer_id.get_sha256(), folder_id_1);
  198. }
  199. r::system_context_t ctx;
  200. sup = ctx.create_supervisor<supervisor_t>().timeout(timeout).create_registry().finish();
  201. sup->cluster = cluster;
  202. sup->configure_callback = [&](r::plugin::plugin_base_t &plugin) {
  203. plugin.template with_casted<r::plugin::registry_plugin_t>(
  204. [&](auto &p) { p.register_name(net::names::fs_actor, sup->get_address()); });
  205. plugin.template with_casted<r::plugin::starter_plugin_t>([&](auto &p) {
  206. p.subscribe_actor(r::lambda<blk_req_t>([&](blk_req_t &msg) {
  207. block_requests.push_back(&msg);
  208. if (block_responses.size()) {
  209. sup->put(block_responses.front());
  210. block_responses.pop_front();
  211. }
  212. }));
  213. });
  214. };
  215. sup->start();
  216. sup->do_process();
  217. CHECK(static_cast<r::actor_base_t *>(sup.get())->access<to::state>() == r::state_t::OPERATIONAL);
  218. sup->create_actor<hasher_actor_t>().index(1).timeout(timeout).finish();
  219. sup->create_actor<hasher::hasher_proxy_actor_t>()
  220. .timeout(timeout)
  221. .hasher_threads(1)
  222. .name(net::names::hasher_proxy)
  223. .finish();
  224. peer_actor = sup->create_actor<sample_peer_t>().timeout(timeout).finish();
  225. builder.apply(*sup);
  226. auto &folders = cluster->get_folders();
  227. folder_1 = folders.by_id(folder_id_1);
  228. folder_2 = folders.by_id(folder_id_2);
  229. folder_1_peer = folder_1->get_folder_infos().by_device_id(peer_id.get_sha256());
  230. target = sup->create_actor<controller_actor_t>()
  231. .peer(peer_device)
  232. .peer_addr(peer_actor->get_address())
  233. .request_pool(1024)
  234. .outgoing_buffer_max(1024'000)
  235. .cluster(cluster)
  236. .timeout(timeout)
  237. .request_timeout(timeout)
  238. .finish();
  239. sup->do_process();
  240. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  241. target_addr = target->get_address();
  242. if (auto_start) {
  243. REQUIRE(peer_actor->reading);
  244. REQUIRE(peer_actor->messages.size() == 1);
  245. auto &msg = (*peer_actor->messages.front()).payload;
  246. REQUIRE(std::get_if<proto::message::ClusterConfig>(&msg));
  247. peer_actor->messages.pop_front();
  248. }
  249. main(builder);
  250. sup->shutdown();
  251. sup->do_process();
  252. CHECK(static_cast<r::actor_base_t *>(sup.get())->access<to::state>() == r::state_t::SHUT_DOWN);
  253. }
  254. virtual void main(diff_builder_t &) noexcept {}
  255. bool auto_start;
  256. bool auto_share;
  257. int64_t max_sequence;
  258. peer_ptr_t peer_actor;
  259. target_ptr_t target;
  260. r::address_ptr_t target_addr;
  261. r::pt::time_duration timeout = r::pt::millisec{10};
  262. cluster_ptr_t cluster;
  263. device_ptr_t peer_device;
  264. device_ptr_t my_device;
  265. r::intrusive_ptr_t<supervisor_t> sup;
  266. r::system_context_t ctx;
  267. model::folder_ptr_t folder_1;
  268. model::folder_info_ptr_t folder_1_peer;
  269. model::folder_ptr_t folder_2;
  270. block_requests_t block_requests;
  271. block_responses_t block_responses;
  272. };
  273. } // namespace
  274. void test_startup() {
  275. struct F : fixture_t {
  276. using fixture_t::fixture_t;
  277. void main(diff_builder_t &) noexcept override {
  278. REQUIRE(peer_actor->reading);
  279. REQUIRE(peer_actor->messages.size() == 1);
  280. auto &msg = (*peer_actor->messages.front()).payload;
  281. REQUIRE(std::get_if<proto::message::ClusterConfig>(&msg));
  282. peer_actor->messages.pop_front();
  283. CHECK(peer_actor->messages.empty());
  284. auto cc = proto::ClusterConfig{};
  285. auto payload = proto::message::ClusterConfig(new proto::ClusterConfig(cc));
  286. peer_actor->forward(std::move(payload));
  287. sup->do_process();
  288. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  289. CHECK(peer_actor->messages.empty());
  290. }
  291. };
  292. F(false, 10).run();
  293. }
  294. void test_index_receiving() {
  295. struct F : fixture_t {
  296. using fixture_t::fixture_t;
  297. void main(diff_builder_t &) noexcept override {
  298. auto cc = proto::ClusterConfig{};
  299. auto index = proto::Index{};
  300. SECTION("wrong index") {
  301. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  302. index.set_folder("non-existing-folder");
  303. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  304. sup->do_process();
  305. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::SHUT_DOWN);
  306. CHECK(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::SHUT_DOWN);
  307. }
  308. SECTION("index is applied") {
  309. auto folder = cc.add_folders();
  310. folder->set_id(std::string(folder_1->get_id()));
  311. auto d_peer = folder->add_devices();
  312. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  313. REQUIRE(cluster->get_unknown_folders().size() == 0);
  314. d_peer->set_max_sequence(folder_1_peer->get_max_sequence());
  315. d_peer->set_index_id(folder_1_peer->get_index());
  316. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  317. index.set_folder(std::string(folder_1->get_id()));
  318. auto file = index.add_files();
  319. file->set_name("some-dir");
  320. file->set_type(proto::FileInfoType::DIRECTORY);
  321. file->set_sequence(folder_1_peer->get_max_sequence());
  322. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  323. sup->do_process();
  324. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  325. CHECK(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  326. auto &folder_infos = folder_1->get_folder_infos();
  327. auto folder_peer = folder_infos.by_device(*peer_device);
  328. REQUIRE(folder_peer);
  329. CHECK(folder_peer->get_max_sequence() == 10ul);
  330. REQUIRE(folder_peer->get_file_infos().size() == 1);
  331. CHECK(folder_peer->get_file_infos().begin()->item->get_name() == file->name());
  332. auto folder_my = folder_infos.by_device(*my_device);
  333. REQUIRE(folder_my);
  334. CHECK(folder_my->get_max_sequence() == 1ul);
  335. REQUIRE(folder_my->get_file_infos().size() == 1);
  336. CHECK(folder_my->get_file_infos().begin()->item->get_name() == file->name());
  337. SECTION("then index update is applied") {
  338. auto index_update = proto::IndexUpdate{};
  339. index_update.set_folder(std::string(folder_1->get_id()));
  340. auto file = index_update.add_files();
  341. file->set_name("some-dir-2");
  342. file->set_type(proto::FileInfoType::DIRECTORY);
  343. file->set_sequence(folder_1_peer->get_max_sequence() + 1);
  344. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index_update)));
  345. sup->do_process();
  346. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  347. CHECK(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() ==
  348. r::state_t::OPERATIONAL);
  349. CHECK(folder_peer->get_max_sequence() == file->sequence());
  350. REQUIRE(folder_peer->get_file_infos().size() == 2);
  351. CHECK(folder_peer->get_file_infos().by_name("some-dir-2"));
  352. CHECK(folder_my->get_max_sequence() == 2ul);
  353. REQUIRE(folder_my->get_file_infos().size() == 2);
  354. CHECK(folder_my->get_file_infos().by_name("some-dir-2"));
  355. }
  356. }
  357. }
  358. };
  359. F(true, 10).run();
  360. }
  361. void test_index_sending() {
  362. struct F : fixture_t {
  363. using fixture_t::fixture_t;
  364. void main(diff_builder_t &) noexcept override {
  365. proto::FileInfo pr_file_info;
  366. pr_file_info.set_name("link");
  367. pr_file_info.set_type(proto::FileInfoType::SYMLINK);
  368. pr_file_info.set_symlink_target("/some/where");
  369. auto builder = diff_builder_t(*cluster);
  370. builder.local_update(folder_1->get_id(), pr_file_info);
  371. builder.apply(*sup);
  372. auto folder_1_my = folder_1->get_folder_infos().by_device(*my_device);
  373. auto cc = proto::ClusterConfig{};
  374. auto folder = cc.add_folders();
  375. folder->set_id(std::string(folder_1->get_id()));
  376. auto d_peer = folder->add_devices();
  377. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  378. d_peer->set_max_sequence(folder_1_peer->get_max_sequence());
  379. d_peer->set_index_id(folder_1_peer->get_index());
  380. SECTION("peer has outdated by sequence view") {
  381. auto d_my = folder->add_devices();
  382. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  383. d_my->set_max_sequence(folder_1_my->get_max_sequence() - 1);
  384. d_my->set_index_id(folder_1_my->get_index());
  385. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  386. sup->do_process();
  387. auto &queue = peer_actor->messages;
  388. REQUIRE(queue.size() == 2);
  389. auto msg = &(*queue.front()).payload;
  390. auto &my_index = *std::get<proto::message::Index>(*msg);
  391. REQUIRE(my_index.files_size() == 0);
  392. queue.pop_front();
  393. msg = &(*queue.front()).payload;
  394. auto &my_index_update = *std::get<proto::message::IndexUpdate>(*msg);
  395. REQUIRE(my_index_update.files_size() == 1);
  396. }
  397. SECTION("peer has outdated by index view") {
  398. auto d_my = folder->add_devices();
  399. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  400. d_my->set_max_sequence(folder_1_my->get_max_sequence());
  401. d_my->set_index_id(folder_1_my->get_index() + 5);
  402. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  403. sup->do_process();
  404. auto &queue = peer_actor->messages;
  405. REQUIRE(queue.size() == 2);
  406. auto msg = &(*queue.front()).payload;
  407. auto &my_index = *std::get<proto::message::Index>(*msg);
  408. REQUIRE(my_index.files_size() == 0);
  409. queue.pop_front();
  410. msg = &(*queue.front()).payload;
  411. auto &my_index_update = *std::get<proto::message::IndexUpdate>(*msg);
  412. REQUIRE(my_index_update.files_size() == 1);
  413. }
  414. SECTION("peer has actual view") {
  415. auto d_my = folder->add_devices();
  416. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  417. d_my->set_max_sequence(folder_1_my->get_max_sequence());
  418. d_my->set_index_id(folder_1_my->get_index());
  419. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  420. sup->do_process();
  421. auto &queue = peer_actor->messages;
  422. REQUIRE(queue.size() == 0);
  423. }
  424. }
  425. };
  426. F(true, 10).run();
  427. }
  428. void test_downloading() {
  429. struct F : fixture_t {
  430. using fixture_t::fixture_t;
  431. void main(diff_builder_t &) noexcept override {
  432. auto &folder_infos = folder_1->get_folder_infos();
  433. auto folder_my = folder_infos.by_device(*my_device);
  434. auto cc = proto::ClusterConfig{};
  435. auto folder = cc.add_folders();
  436. folder->set_id(std::string(folder_1->get_id()));
  437. auto d_peer = folder->add_devices();
  438. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  439. d_peer->set_max_sequence(folder_1_peer->get_max_sequence());
  440. d_peer->set_index_id(folder_1_peer->get_index());
  441. auto d_my = folder->add_devices();
  442. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  443. d_my->set_max_sequence(folder_my->get_max_sequence());
  444. d_my->set_index_id(folder_my->get_index());
  445. SECTION("cluster config & index has a new file => download it") {
  446. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  447. auto index = proto::Index{};
  448. index.set_folder(std::string(folder_1->get_id()));
  449. auto file = index.add_files();
  450. file->set_name("some-file");
  451. file->set_type(proto::FileInfoType::FILE);
  452. file->set_sequence(folder_1_peer->get_max_sequence());
  453. file->set_block_size(5);
  454. file->set_size(5);
  455. auto version = file->mutable_version();
  456. auto counter = version->add_counters();
  457. counter->set_id(1ul);
  458. counter->set_value(1ul);
  459. auto b1 = file->add_blocks();
  460. b1->set_hash(utils::sha256_digest("12345").value());
  461. b1->set_offset(0);
  462. b1->set_size(5);
  463. auto folder_my = folder_infos.by_device(*my_device);
  464. CHECK(folder_my->get_max_sequence() == 0ul);
  465. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  466. peer_actor->push_block("12345", 0);
  467. sup->do_process();
  468. REQUIRE(folder_my);
  469. CHECK(folder_my->get_max_sequence() == 1ul);
  470. REQUIRE(folder_my->get_file_infos().size() == 1);
  471. auto f = folder_my->get_file_infos().begin()->item;
  472. REQUIRE(f);
  473. CHECK(f->get_name() == file->name());
  474. CHECK(f->get_size() == 5);
  475. CHECK(f->get_blocks().size() == 1);
  476. CHECK(f->is_locally_available());
  477. CHECK(!f->is_locked());
  478. CHECK(peer_actor->blocks_requested == 1);
  479. auto &queue = peer_actor->messages;
  480. REQUIRE(queue.size() > 0);
  481. auto msg = &(*queue.front()).payload;
  482. auto &my_index = *std::get<proto::message::Index>(*msg);
  483. REQUIRE(my_index.files_size() == 0);
  484. queue.pop_front();
  485. msg = &(*queue.back()).payload;
  486. auto &my_index_update = *std::get<proto::message::IndexUpdate>(*msg);
  487. REQUIRE(my_index_update.files_size() == 1);
  488. SECTION("dont redownload file only if metadata has changed") {
  489. auto index_update = proto::IndexUpdate{};
  490. index_update.set_folder(index.folder());
  491. file->set_sequence(folder_1_peer->get_max_sequence() + 1);
  492. counter->set_value(2ul);
  493. *index_update.add_files() = *file;
  494. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index_update)));
  495. sup->do_process();
  496. CHECK(peer_actor->blocks_requested == 1);
  497. CHECK(folder_my->get_max_sequence() == 2ul);
  498. f = folder_my->get_file_infos().begin()->item;
  499. CHECK(f->is_locally_available());
  500. CHECK(f->get_sequence() == 2ul);
  501. }
  502. }
  503. SECTION("cluster config is the same, but there are non-downloaded files") {
  504. auto folder_peer = folder_infos.by_device(*peer_device);
  505. auto pr_fi = proto::FileInfo{};
  506. pr_fi.set_name("some-file");
  507. pr_fi.set_type(proto::FileInfoType::FILE);
  508. pr_fi.set_sequence(folder_1_peer->get_max_sequence());
  509. pr_fi.set_block_size(5);
  510. pr_fi.set_size(5);
  511. auto version = pr_fi.mutable_version();
  512. auto counter = version->add_counters();
  513. counter->set_id(1);
  514. counter->set_value(peer_device->as_uint());
  515. auto b1 = pr_fi.add_blocks();
  516. b1->set_hash(utils::sha256_digest("12345").value());
  517. b1->set_offset(0);
  518. b1->set_size(5);
  519. auto b = model::block_info_t::create(*b1).value();
  520. auto file_info = model::file_info_t::create(cluster->next_uuid(), pr_fi, folder_peer).value();
  521. file_info->assign_block(b, 0);
  522. folder_peer->add(file_info, true);
  523. d_peer->set_max_sequence(folder_peer->get_max_sequence());
  524. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  525. peer_actor->push_block("12345", 0);
  526. sup->do_process();
  527. CHECK(folder_my->get_max_sequence() == 1ul);
  528. REQUIRE(folder_my->get_file_infos().size() == 1);
  529. auto f = folder_my->get_file_infos().begin()->item;
  530. REQUIRE(f);
  531. CHECK(f->get_name() == pr_fi.name());
  532. CHECK(f->get_size() == 5);
  533. CHECK(f->get_blocks().size() == 1);
  534. CHECK(f->is_locally_available());
  535. CHECK(!f->is_locked());
  536. }
  537. SECTION("don't attempt to download a file, which is deleted") {
  538. auto folder_peer = folder_infos.by_device(*peer_device);
  539. auto pr_fi = proto::FileInfo{};
  540. pr_fi.set_name("some-file");
  541. pr_fi.set_type(proto::FileInfoType::FILE);
  542. pr_fi.set_sequence(folder_1_peer->get_max_sequence());
  543. pr_fi.set_block_size(5);
  544. pr_fi.set_size(5);
  545. auto b1 = pr_fi.add_blocks();
  546. b1->set_hash(utils::sha256_digest("12345").value());
  547. b1->set_offset(0);
  548. b1->set_size(5);
  549. auto b = model::block_info_t::create(*b1).value();
  550. auto file_info = model::file_info_t::create(cluster->next_uuid(), pr_fi, folder_peer).value();
  551. file_info->assign_block(b, 0);
  552. folder_peer->add(file_info, true);
  553. d_peer->set_max_sequence(folder_1_peer->get_max_sequence() + 1);
  554. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  555. sup->do_process();
  556. auto index = proto::IndexUpdate{};
  557. index.set_folder(std::string(folder_1->get_id()));
  558. auto file = index.add_files();
  559. file->set_name("some-file");
  560. file->set_type(proto::FileInfoType::FILE);
  561. file->set_deleted(true);
  562. file->set_sequence(folder_1_peer->get_max_sequence() + 1);
  563. file->set_block_size(0);
  564. file->set_size(0);
  565. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index)));
  566. sup->do_process();
  567. CHECK(folder_my->get_max_sequence() == 1ul);
  568. REQUIRE(folder_my->get_file_infos().size() == 1);
  569. auto f = folder_my->get_file_infos().begin()->item;
  570. REQUIRE(f);
  571. CHECK(f->get_name() == pr_fi.name());
  572. CHECK(f->get_size() == 0);
  573. CHECK(f->get_blocks().size() == 0);
  574. CHECK(f->is_locally_available());
  575. CHECK(f->is_deleted());
  576. CHECK(!f->is_locked());
  577. CHECK(f->get_sequence() == 1ul);
  578. CHECK(peer_actor->blocks_requested == 0);
  579. }
  580. SECTION("new file via index_update => download it") {
  581. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  582. auto index = proto::Index{};
  583. index.set_folder(std::string(folder_1->get_id()));
  584. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  585. auto index_update = proto::IndexUpdate{};
  586. index_update.set_folder(std::string(folder_1->get_id()));
  587. auto file = index_update.add_files();
  588. file->set_name("some-file");
  589. file->set_type(proto::FileInfoType::FILE);
  590. file->set_sequence(folder_1_peer->get_max_sequence() + 1);
  591. file->set_block_size(5);
  592. file->set_size(5);
  593. auto version = file->mutable_version();
  594. auto counter = version->add_counters();
  595. counter->set_id(1);
  596. counter->set_value(peer_device->as_uint());
  597. auto b1 = file->add_blocks();
  598. b1->set_hash(utils::sha256_digest("12345").value());
  599. b1->set_offset(0);
  600. b1->set_size(5);
  601. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index_update)));
  602. peer_actor->push_block("12345", 0);
  603. sup->do_process();
  604. auto folder_my = folder_infos.by_device(*my_device);
  605. CHECK(folder_my->get_max_sequence() == 1);
  606. REQUIRE(folder_my->get_file_infos().size() == 1);
  607. auto f = folder_my->get_file_infos().begin()->item;
  608. REQUIRE(f);
  609. CHECK(f->get_name() == file->name());
  610. CHECK(f->get_size() == 5);
  611. CHECK(f->get_blocks().size() == 1);
  612. CHECK(f->is_locally_available());
  613. CHECK(!f->is_locked());
  614. auto fp = folder_1_peer->get_file_infos().begin()->item;
  615. REQUIRE(fp);
  616. CHECK(!fp->is_locked());
  617. }
  618. SECTION("deleted file, has been restored => download it") {
  619. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  620. sup->do_process();
  621. auto index = proto::Index{};
  622. index.set_folder(std::string(folder_1->get_id()));
  623. auto file_1 = index.add_files();
  624. file_1->set_name("some-file");
  625. file_1->set_type(proto::FileInfoType::FILE);
  626. file_1->set_sequence(folder_1_peer->get_max_sequence());
  627. file_1->set_deleted(true);
  628. auto v1 = file_1->mutable_version();
  629. auto c1 = v1->add_counters();
  630. c1->set_id(1u);
  631. c1->set_value(1u);
  632. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  633. sup->do_process();
  634. auto folder_my = folder_infos.by_device(*my_device);
  635. CHECK(folder_my->get_max_sequence() == 1ul);
  636. auto index_update = proto::IndexUpdate{};
  637. index_update.set_folder(std::string(folder_1->get_id()));
  638. auto file_2 = index_update.add_files();
  639. file_2->set_name("some-file");
  640. file_2->set_type(proto::FileInfoType::FILE);
  641. file_2->set_sequence(folder_1_peer->get_max_sequence() + 1);
  642. file_2->set_block_size(128 * 1024);
  643. file_2->set_size(5);
  644. auto v2 = file_2->mutable_version();
  645. auto c2 = v2->add_counters();
  646. c2->set_id(1u);
  647. c2->set_value(2u);
  648. auto b1 = file_2->add_blocks();
  649. b1->set_hash(utils::sha256_digest("12345").value());
  650. b1->set_offset(0);
  651. b1->set_size(5);
  652. peer_actor->forward(proto::message::IndexUpdate(new proto::IndexUpdate(index_update)));
  653. peer_actor->push_block("12345", 0);
  654. sup->do_process();
  655. REQUIRE(folder_my->get_file_infos().size() == 1);
  656. auto f = folder_my->get_file_infos().begin()->item;
  657. REQUIRE(f);
  658. CHECK(f->get_name() == file_1->name());
  659. CHECK(f->get_size() == 5);
  660. CHECK(f->get_blocks().size() == 1);
  661. CHECK(f->is_locally_available());
  662. CHECK(!f->is_locked());
  663. }
  664. SECTION("download a file, which has the same blocks locally") {
  665. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  666. sup->do_process();
  667. auto index = proto::Index{};
  668. index.set_folder(std::string(folder_1->get_id()));
  669. auto file_1 = index.add_files();
  670. file_1->set_name("some-file");
  671. file_1->set_type(proto::FileInfoType::FILE);
  672. file_1->set_sequence(folder_1_peer->get_max_sequence());
  673. auto v1 = file_1->mutable_version();
  674. auto c1 = v1->add_counters();
  675. c1->set_id(1u);
  676. c1->set_value(1u);
  677. file_1->set_block_size(5);
  678. file_1->set_size(10);
  679. auto b1 = file_1->add_blocks();
  680. b1->set_hash(utils::sha256_digest("12345").value());
  681. b1->set_offset(0);
  682. b1->set_size(5);
  683. auto bi_1 = model::block_info_t::create(*b1).value();
  684. auto b2 = file_1->add_blocks();
  685. b2->set_hash(utils::sha256_digest("67890").value());
  686. b2->set_offset(5);
  687. b2->set_size(5);
  688. auto bi_2 = model::block_info_t::create(*b2).value();
  689. auto &blocks = cluster->get_blocks();
  690. blocks.put(bi_1);
  691. blocks.put(bi_2);
  692. auto pr_my = proto::FileInfo{};
  693. pr_my.set_name("some-file.source");
  694. pr_my.set_type(proto::FileInfoType::FILE);
  695. pr_my.set_sequence(2ul);
  696. pr_my.set_block_size(5);
  697. pr_my.set_size(5);
  698. auto file_my = model::file_info_t::create(cluster->next_uuid(), pr_my, folder_my).value();
  699. file_my->assign_block(bi_1, 0);
  700. file_my->mark_local_available(0);
  701. folder_my->add(file_my, true);
  702. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  703. peer_actor->push_block("67890", 1);
  704. cluster->modify_write_requests(10);
  705. sup->do_process();
  706. REQUIRE(folder_my->get_file_infos().size() == 2);
  707. auto f = folder_my->get_file_infos().by_name(file_1->name());
  708. REQUIRE(f);
  709. CHECK(f->get_name() == file_1->name());
  710. CHECK(f->get_size() == 10);
  711. CHECK(f->get_blocks().size() == 2);
  712. CHECK(f->is_locally_available());
  713. CHECK(!f->is_locked());
  714. }
  715. }
  716. };
  717. F(true, 10).run();
  718. }
  719. void test_downloading_errors() {
  720. struct F : fixture_t {
  721. using fixture_t::fixture_t;
  722. void main(diff_builder_t &) noexcept override {
  723. auto &folder_infos = folder_1->get_folder_infos();
  724. auto folder_my = folder_infos.by_device(*my_device);
  725. auto cc = proto::ClusterConfig{};
  726. auto folder = cc.add_folders();
  727. folder->set_id(std::string(folder_1->get_id()));
  728. auto d_peer = folder->add_devices();
  729. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  730. d_peer->set_max_sequence(folder_1_peer->get_max_sequence());
  731. d_peer->set_index_id(folder_1_peer->get_index());
  732. auto d_my = folder->add_devices();
  733. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  734. d_my->set_max_sequence(folder_my->get_max_sequence());
  735. d_my->set_index_id(folder_my->get_index());
  736. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  737. auto index = proto::Index{};
  738. index.set_folder(std::string(folder_1->get_id()));
  739. auto file = index.add_files();
  740. file->set_name("some-file");
  741. file->set_type(proto::FileInfoType::FILE);
  742. file->set_sequence(folder_1_peer->get_max_sequence());
  743. file->set_block_size(5);
  744. file->set_size(5);
  745. auto version = file->mutable_version();
  746. auto counter = version->add_counters();
  747. counter->set_id(1ul);
  748. counter->set_value(1ul);
  749. auto b1 = file->add_blocks();
  750. b1->set_hash(utils::sha256_digest("12345").value());
  751. b1->set_offset(0);
  752. b1->set_size(5);
  753. CHECK(folder_my->get_max_sequence() == 0ul);
  754. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  755. SECTION("general error, ok, do not shutdown") {
  756. auto ec = utils::make_error_code(utils::request_error_code_t::generic);
  757. peer_actor->push_block(ec, 0);
  758. }
  759. SECTION("hash mismatch, do not shutdown") { peer_actor->push_block("zzz", 0); }
  760. sup->do_process();
  761. CHECK(peer_actor->blocks_requested == 1);
  762. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  763. auto folder_peer = folder_infos.by_device(*peer_device);
  764. REQUIRE(folder_peer->get_file_infos().size() == 1);
  765. auto f = folder_peer->get_file_infos().begin()->item;
  766. REQUIRE(f);
  767. CHECK(f->is_unreachable());
  768. CHECK(!f->is_locally_locked());
  769. CHECK(!f->is_locked());
  770. auto lf = f->local_file();
  771. CHECK(!lf->is_locally_locked());
  772. CHECK(!lf->is_locked());
  773. sup->do_process();
  774. }
  775. };
  776. F(true, 10).run();
  777. }
  778. void test_my_sharing() {
  779. struct F : fixture_t {
  780. using fixture_t::fixture_t;
  781. void main(diff_builder_t &) noexcept override {
  782. sup->do_process();
  783. auto cc = proto::ClusterConfig{};
  784. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  785. // nothing is shared
  786. sup->do_process();
  787. REQUIRE(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  788. REQUIRE(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  789. REQUIRE(peer_actor->messages.size() == 1);
  790. auto peer_msg = &peer_actor->messages.front()->payload;
  791. auto peer_cluster_msg = std::get_if<proto::message::ClusterConfig>(peer_msg);
  792. REQUIRE(peer_cluster_msg);
  793. REQUIRE(*peer_cluster_msg);
  794. REQUIRE((*peer_cluster_msg)->folders_size() == 0);
  795. // share folder_1
  796. peer_actor->messages.clear();
  797. auto sha256 = peer_device->device_id().get_sha256();
  798. diff_builder_t(*cluster).share_folder(sha256, folder_1->get_id()).apply(*sup);
  799. REQUIRE(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  800. REQUIRE(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  801. REQUIRE(peer_actor->messages.size() == 1);
  802. peer_msg = &peer_actor->messages.front()->payload;
  803. peer_cluster_msg = std::get_if<proto::message::ClusterConfig>(peer_msg);
  804. REQUIRE(peer_cluster_msg);
  805. REQUIRE(*peer_cluster_msg);
  806. REQUIRE((*peer_cluster_msg)->folders_size() == 1);
  807. // unshare folder_1
  808. auto peer_fi = folder_1->get_folder_infos().by_device(*peer_device);
  809. peer_actor->messages.clear();
  810. diff_builder_t(*cluster).unshare_folder(*peer_fi).apply(*sup);
  811. REQUIRE(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::OPERATIONAL);
  812. REQUIRE(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::OPERATIONAL);
  813. REQUIRE(peer_actor->messages.size() == 1);
  814. peer_msg = &peer_actor->messages.front()->payload;
  815. peer_cluster_msg = std::get_if<proto::message::ClusterConfig>(peer_msg);
  816. REQUIRE(peer_cluster_msg);
  817. REQUIRE(*peer_cluster_msg);
  818. REQUIRE((*peer_cluster_msg)->folders_size() == 0);
  819. }
  820. };
  821. F(false, 10, false).run();
  822. }
  823. void test_sending_index_updates() {
  824. struct F : fixture_t {
  825. using fixture_t::fixture_t;
  826. void main(diff_builder_t &) noexcept override {
  827. auto &folder_infos = folder_1->get_folder_infos();
  828. auto folder_my = folder_infos.by_device(*my_device);
  829. auto cc = proto::ClusterConfig{};
  830. auto folder = cc.add_folders();
  831. folder->set_id(std::string(folder_1->get_id()));
  832. auto d_peer = folder->add_devices();
  833. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  834. d_peer->set_max_sequence(folder_1_peer->get_max_sequence());
  835. d_peer->set_index_id(folder_1_peer->get_index());
  836. auto d_my = folder->add_devices();
  837. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  838. d_my->set_max_sequence(folder_my->get_max_sequence());
  839. d_my->set_index_id(folder_my->get_index());
  840. auto index = proto::Index{};
  841. auto folder_id = std::string(folder_1->get_id());
  842. index.set_folder(folder_id);
  843. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  844. peer_actor->forward(proto::message::Index(new proto::Index(index)));
  845. sup->do_process();
  846. auto builder = diff_builder_t(*cluster);
  847. auto pr_file = proto::FileInfo();
  848. pr_file.set_name("a.txt");
  849. peer_actor->messages.clear();
  850. builder.local_update(folder_id, pr_file).apply(*sup);
  851. REQUIRE(peer_actor->messages.size() == 1);
  852. auto &msg = peer_actor->messages.front();
  853. auto &index_update = *std::get<proto::message::IndexUpdate>(msg->payload);
  854. REQUIRE(index_update.files_size() == 1);
  855. CHECK(index_update.files(0).name() == "a.txt");
  856. }
  857. };
  858. F(true, 10).run();
  859. }
  860. void test_uploading() {
  861. struct F : fixture_t {
  862. using fixture_t::fixture_t;
  863. void main(diff_builder_t &) noexcept override {
  864. auto &folder_infos = folder_1->get_folder_infos();
  865. auto folder_my = folder_infos.by_device(*my_device);
  866. auto cc = proto::ClusterConfig{};
  867. auto folder = cc.add_folders();
  868. folder->set_id(std::string(folder_1->get_id()));
  869. auto d_peer = folder->add_devices();
  870. d_peer->set_id(std::string(peer_device->device_id().get_sha256()));
  871. d_peer->set_max_sequence(folder_1_peer->get_max_sequence());
  872. d_peer->set_index_id(folder_1_peer->get_index());
  873. auto d_my = folder->add_devices();
  874. d_my->set_id(std::string(my_device->device_id().get_sha256()));
  875. d_my->set_max_sequence(folder_my->get_max_sequence());
  876. d_my->set_index_id(folder_my->get_index());
  877. auto pr_fi = proto::FileInfo{};
  878. pr_fi.set_name("data.bin");
  879. pr_fi.set_type(proto::FileInfoType::FILE);
  880. pr_fi.set_sequence(folder_1_peer->get_max_sequence());
  881. pr_fi.set_block_size(5);
  882. pr_fi.set_size(5);
  883. auto version = pr_fi.mutable_version();
  884. auto counter = version->add_counters();
  885. counter->set_id(1);
  886. counter->set_value(my_device->as_uint());
  887. auto b1 = pr_fi.add_blocks();
  888. b1->set_hash(utils::sha256_digest("12345").value());
  889. b1->set_offset(0);
  890. b1->set_size(5);
  891. auto b = model::block_info_t::create(*b1).value();
  892. auto file_info = model::file_info_t::create(cluster->next_uuid(), pr_fi, folder_my).value();
  893. file_info->assign_block(b, 0);
  894. folder_my->add(file_info, true);
  895. auto req = proto::Request();
  896. req.set_id(1);
  897. req.set_folder(std::string(folder_1->get_id()));
  898. req.set_name("data.bin");
  899. req.set_offset(0);
  900. req.set_size(5);
  901. peer_actor->forward(proto::message::ClusterConfig(new proto::ClusterConfig(cc)));
  902. SECTION("upload regular file, no hash") {
  903. peer_actor->forward(proto::message::Request(new proto::Request(req)));
  904. auto req_ptr = proto::message::Request(new proto::Request(req));
  905. auto res = r::make_message<fs::payload::block_response_t>(target->get_address(), std::move(req_ptr),
  906. sys::error_code{}, std::string("12345"));
  907. block_responses.push_back(res);
  908. sup->do_process();
  909. REQUIRE(block_requests.size() == 1);
  910. CHECK(block_requests[0]->payload.remote_request->id() == 1);
  911. CHECK(block_requests[0]->payload.remote_request->name() == "data.bin");
  912. REQUIRE(peer_actor->uploaded_blocks.size() == 1);
  913. auto &peer_res = *peer_actor->uploaded_blocks.front();
  914. CHECK(peer_res.id() == 1);
  915. CHECK(peer_res.code() == proto::ErrorCode::NO_BEP_ERROR);
  916. CHECK(peer_res.data() == "12345");
  917. }
  918. }
  919. };
  920. F(true, 10).run();
  921. }
  922. void test_peer_removal() {
  923. struct F : fixture_t {
  924. using fixture_t::fixture_t;
  925. void main(diff_builder_t &builder) noexcept override {
  926. builder.remove_peer(*peer_device).apply(*sup);
  927. CHECK(static_cast<r::actor_base_t *>(target.get())->access<to::state>() == r::state_t::SHUT_DOWN);
  928. CHECK(static_cast<r::actor_base_t *>(peer_actor.get())->access<to::state>() == r::state_t::SHUT_DOWN);
  929. CHECK(target->get_shutdown_reason()->root()->ec == utils::error_code_t::peer_has_been_removed);
  930. }
  931. };
  932. F(true, 10).run();
  933. }
  934. int _init() {
  935. REGISTER_TEST_CASE(test_startup, "test_startup", "[net]");
  936. REGISTER_TEST_CASE(test_index_receiving, "test_index_receiving", "[net]");
  937. REGISTER_TEST_CASE(test_index_sending, "test_index_sending", "[net]");
  938. REGISTER_TEST_CASE(test_downloading, "test_downloading", "[net]");
  939. REGISTER_TEST_CASE(test_downloading_errors, "test_downloading_errors", "[net]");
  940. REGISTER_TEST_CASE(test_my_sharing, "test_my_sharing", "[net]");
  941. REGISTER_TEST_CASE(test_sending_index_updates, "test_sending_index_updates", "[net]");
  942. REGISTER_TEST_CASE(test_uploading, "test_uploading", "[net]");
  943. REGISTER_TEST_CASE(test_peer_removal, "test_peer_removal", "[net]");
  944. return 1;
  945. }
  946. static int v = _init();