/* Copyright (c) 2018, Steven Siloti Copyright (c) 2015-2021, Arvid Norberg Copyright (c) 2016, 2018, 2020, Alden Torres Copyright (c) 2018, d-komarov All rights reserved. You may use, distribute and modify this code under the terms of the BSD license, see LICENSE file. */ #include "test.hpp" #include "test_utils.hpp" #include "libtorrent/aux_/alert_manager.hpp" #include "libtorrent/torrent_handle.hpp" #include "libtorrent/alert_types.hpp" #include "libtorrent/extensions.hpp" #include "setup_transfer.hpp" #include #include using namespace lt; TORRENT_TEST(limit) { aux::alert_manager mgr(500, alert_category::all); TEST_EQUAL(mgr.alert_queue_size_limit(), 500); TEST_EQUAL(mgr.pending(), false); // try add 600 torrent_add_alert to make sure we honor the limit of 500 // alerts. for (auto i = 0_piece; i < 600_piece; ++i) mgr.emplace_alert(torrent_handle(), i); TEST_EQUAL(mgr.pending(), true); std::vector alerts; mgr.get_all(alerts); // even though we posted 600, the limit was 500 // +1 for the alerts_dropped_alert TEST_EQUAL(alerts.size(), 501); TEST_EQUAL(mgr.pending(), false); // now, try lowering the limit and do the same thing again mgr.set_alert_queue_size_limit(200); for (auto i = 0_piece; i < 600_piece; ++i) mgr.emplace_alert(torrent_handle(), i); TEST_EQUAL(mgr.pending(), true); mgr.get_all(alerts); // even though we posted 600, the limit was 200 // +1 for the alerts_dropped_alert TEST_EQUAL(alerts.size(), 201); } TORRENT_TEST(limit_int_max) { int const inf = std::numeric_limits::max(); aux::alert_manager mgr(inf, alert_category::all); TEST_EQUAL(mgr.alert_queue_size_limit(), inf); for (auto i = 0_piece; i < 600_piece; ++i) mgr.emplace_alert(torrent_handle(), i); for (auto i = 0_piece; i < 600_piece; ++i) mgr.emplace_alert(torrent_handle(), info_hash_t(), client_data_t{}); std::vector alerts; mgr.get_all(alerts); TEST_EQUAL(alerts.size(), 1200); } TORRENT_TEST(priority_limit) { aux::alert_manager mgr(100, alert_category::all); TEST_EQUAL(mgr.alert_queue_size_limit(), 100); // this should only add 100 because of the limit for (auto i = 0_piece; i < 200_piece; ++i) mgr.emplace_alert(torrent_handle(), i); // the limit is twice as high for priority alerts for (auto i = 0_file; i < 300_file; ++i) mgr.emplace_alert(torrent_handle(), i, error_code()); std::vector alerts; mgr.get_all(alerts); // even though we posted 500, the limit was 100 for half of them and // 100 + 200 for the other half, meaning we should have 300 alerts now // +1 for the alerts_dropped_alert TEST_EQUAL(alerts.size(), 301); } namespace { void test_notify_fun(int& cnt) { ++cnt; } } // anonymous namespace TORRENT_TEST(notify_function) { int cnt = 0; aux::alert_manager mgr(100, alert_category::all); TEST_EQUAL(mgr.alert_queue_size_limit(), 100); TEST_EQUAL(mgr.pending(), false); for (int i = 0; i < 20; ++i) mgr.emplace_alert(torrent_handle(), add_torrent_params(), error_code()); TEST_EQUAL(mgr.pending(), true); // if there are queued alerts when we set the notify function, // that counts as an edge and it's called mgr.set_notify_function(std::bind(&test_notify_fun, std::ref(cnt))); TEST_EQUAL(mgr.pending(), true); TEST_EQUAL(cnt, 1); // subsequent posted alerts will not cause an edge (because there are // already alerts queued) for (int i = 0; i < 20; ++i) mgr.emplace_alert(torrent_handle(), add_torrent_params(), error_code()); TEST_EQUAL(mgr.pending(), true); TEST_EQUAL(cnt, 1); // however, if we pop all the alerts and post new ones, there will be // and edge triggering the notify call std::vector alerts; mgr.get_all(alerts); TEST_EQUAL(mgr.pending(), false); for (int i = 0; i < 20; ++i) mgr.emplace_alert(torrent_handle(), add_torrent_params(), error_code()); TEST_EQUAL(mgr.pending(), true); TEST_EQUAL(cnt, 2); } #ifndef TORRENT_DISABLE_EXTENSIONS namespace { int plugin_alerts[3] = { 0, 0, 0 }; struct test_plugin : lt::plugin { explicit test_plugin(int index) : m_index(index) {} void on_alert(alert const*) override { ++plugin_alerts[m_index]; } int m_index; }; } // anonymous namespace #endif TORRENT_TEST(extensions) { #ifndef TORRENT_DISABLE_EXTENSIONS memset(plugin_alerts, 0, sizeof(plugin_alerts)); aux::alert_manager mgr(100, alert_category::all); mgr.add_extension(std::make_shared(0)); mgr.add_extension(std::make_shared(1)); mgr.add_extension(std::make_shared(2)); for (int i = 0; i < 53; ++i) mgr.emplace_alert(torrent_handle(), add_torrent_params(), error_code()); TEST_EQUAL(plugin_alerts[0], 53); TEST_EQUAL(plugin_alerts[1], 53); TEST_EQUAL(plugin_alerts[2], 53); for (int i = 0; i < 17; ++i) mgr.emplace_alert(torrent_handle(), add_torrent_params(), error_code()); TEST_EQUAL(plugin_alerts[0], 70); TEST_EQUAL(plugin_alerts[1], 70); TEST_EQUAL(plugin_alerts[2], 70); #endif } /* namespace { void post_torrent_added(aux::alert_manager* mgr) { std::this_thread::sleep_for(lt::milliseconds(10)); mgr->emplace_alert(torrent_handle(), add_torrent_params(), error_code()); } } // anonymous namespace // this test is too flaky TORRENT_TEST(wait_for_alert) { aux::alert_manager mgr(100, alert_category::all); time_point start = clock_type::now(); alert* a = mgr.wait_for_alert(seconds(1)); time_point end = clock_type::now(); TEST_EQUAL(a, static_cast(nullptr)); std::printf("delay: %d ms (expected 1 second)\n" , int(total_milliseconds(end - start))); TEST_CHECK(end - start > milliseconds(900)); TEST_CHECK(end - start < milliseconds(1100)); mgr.emplace_alert(torrent_handle(), add_torrent_params(), error_code()); start = clock_type::now(); a = mgr.wait_for_alert(seconds(1)); end = clock_type::now(); std::printf("delay: %d ms\n", int(total_milliseconds(end - start))); TEST_CHECK(end - start < milliseconds(1)); TEST_CHECK(a->type() == add_torrent_alert::alert_type); std::vector alerts; mgr.get_all(alerts); start = clock_type::now(); std::thread posting_thread(&post_torrent_added, &mgr); a = mgr.wait_for_alert(seconds(10)); end = clock_type::now(); std::printf("delay: %d ms\n", int(total_milliseconds(end - start))); TEST_CHECK(end - start < milliseconds(500)); TEST_CHECK(a->type() == add_torrent_alert::alert_type); posting_thread.join(); } */ TORRENT_TEST(alert_mask) { aux::alert_manager mgr(100, alert_category::all); TEST_CHECK(mgr.should_post()); TEST_CHECK(mgr.should_post()); mgr.set_alert_mask({}); TEST_CHECK(!mgr.should_post()); TEST_CHECK(!mgr.should_post()); } TORRENT_TEST(get_all_empty) { aux::alert_manager mgr(100, alert_category::all); std::vector alerts(10); mgr.get_all(alerts); TEST_CHECK(alerts.empty()); } TORRENT_TEST(dropped_alerts) { aux::alert_manager mgr(1, alert_category::all); // nothing has dropped yet mgr.emplace_alert(torrent_handle()); // still nothing, there's space for one alert mgr.emplace_alert(torrent_handle()); // still nothing, there's space for one alert mgr.emplace_alert(torrent_handle()); // that last alert got dropped though, since it would have brought the queue // size to 3 std::vector alerts; mgr.get_all(alerts); auto const d = alert_cast(alerts.back())->dropped_alerts; TEST_EQUAL(d.count(), 1); TEST_CHECK(d.test(torrent_finished_alert::alert_type)); } TORRENT_TEST(alerts_dropped_alert) { aux::alert_manager mgr(1, alert_category::all); mgr.emplace_alert(torrent_handle()); mgr.emplace_alert(torrent_handle()); mgr.emplace_alert(torrent_handle()); // that last alert got dropped though, since it would have brought the queue // size to 3 std::vector alerts; mgr.get_all(alerts); #ifndef TORRENT_DISABLE_ALERT_MSG TEST_EQUAL(alerts.back()->message(), "dropped alerts: torrent_finished "); #endif auto* a = lt::alert_cast(alerts.back()); TEST_CHECK(a); TEST_CHECK(a->dropped_alerts[torrent_finished_alert::alert_type] == true); } #ifndef TORRENT_DISABLE_EXTENSIONS struct post_plugin : lt::plugin { explicit post_plugin(aux::alert_manager& m) : mgr(m) {} void on_alert(alert const*) override { if (++depth > 10) return; mgr.emplace_alert(torrent_handle(), 0_piece); } aux::alert_manager& mgr; int depth = 0; }; // make sure the alert manager supports alerts being posted while executing a // plugin handler TORRENT_TEST(recursive_alerts) { aux::alert_manager mgr(100, alert_category::all); auto pl = std::make_shared(mgr); mgr.add_extension(pl); mgr.emplace_alert(torrent_handle(), 0_piece); TEST_EQUAL(pl->depth, 11); } #endif // TORRENT_DISABLE_EXTENSIONS