Files
libtorrent/test/test_alert_manager.cpp
2022-06-22 21:42:55 +02:00

342 lines
9.1 KiB
C++

/*
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 <functional>
#include <thread>
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<piece_finished_alert>(torrent_handle(), i);
TEST_EQUAL(mgr.pending(), true);
std::vector<alert*> 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<piece_finished_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<int>::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<piece_finished_alert>(torrent_handle(), i);
for (auto i = 0_piece; i < 600_piece; ++i)
mgr.emplace_alert<torrent_removed_alert>(torrent_handle(), info_hash_t(), client_data_t{});
std::vector<alert*> 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<piece_finished_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<file_rename_failed_alert>(torrent_handle(), i, error_code());
std::vector<alert*> 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<add_torrent_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<add_torrent_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<alert*> alerts;
mgr.get_all(alerts);
TEST_EQUAL(mgr.pending(), false);
for (int i = 0; i < 20; ++i)
mgr.emplace_alert<add_torrent_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<test_plugin>(0));
mgr.add_extension(std::make_shared<test_plugin>(1));
mgr.add_extension(std::make_shared<test_plugin>(2));
for (int i = 0; i < 53; ++i)
mgr.emplace_alert<add_torrent_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<add_torrent_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<add_torrent_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<alert*>(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<add_torrent_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<alert*> 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<add_torrent_alert>());
TEST_CHECK(mgr.should_post<torrent_paused_alert>());
mgr.set_alert_mask({});
TEST_CHECK(!mgr.should_post<add_torrent_alert>());
TEST_CHECK(!mgr.should_post<torrent_paused_alert>());
}
TORRENT_TEST(get_all_empty)
{
aux::alert_manager mgr(100, alert_category::all);
std::vector<alert*> 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_finished_alert>(torrent_handle());
// still nothing, there's space for one alert
mgr.emplace_alert<torrent_finished_alert>(torrent_handle());
// still nothing, there's space for one alert
mgr.emplace_alert<torrent_finished_alert>(torrent_handle());
// that last alert got dropped though, since it would have brought the queue
// size to 3
std::vector<alert*> alerts;
mgr.get_all(alerts);
auto const d = alert_cast<alerts_dropped_alert>(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_finished_alert>(torrent_handle());
mgr.emplace_alert<torrent_finished_alert>(torrent_handle());
mgr.emplace_alert<torrent_finished_alert>(torrent_handle());
// that last alert got dropped though, since it would have brought the queue
// size to 3
std::vector<alert*> 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_dropped_alert>(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<piece_finished_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<post_plugin>(mgr);
mgr.add_extension(pl);
mgr.emplace_alert<piece_finished_alert>(torrent_handle(), 0_piece);
TEST_EQUAL(pl->depth, 11);
}
#endif // TORRENT_DISABLE_EXTENSIONS