926 lines
26 KiB
C++
926 lines
26 KiB
C++
/*
|
|
|
|
Copyright (c) 2015, Arvid Norberg
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
* Neither the name of the author nor the names of its
|
|
contributors may be used to endorse or promote products derived
|
|
from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
#include "libtorrent/session.hpp"
|
|
#include "libtorrent/torrent_handle.hpp"
|
|
#include "libtorrent/settings_pack.hpp"
|
|
#include "libtorrent/alert_types.hpp"
|
|
#include "libtorrent/deadline_timer.hpp"
|
|
#include "settings.hpp"
|
|
#include "create_torrent.hpp"
|
|
#include "simulator/simulator.hpp"
|
|
#include <iostream>
|
|
|
|
using namespace sim;
|
|
using namespace libtorrent;
|
|
|
|
const int num_torrents = 10;
|
|
namespace lt = libtorrent;
|
|
|
|
using sim::asio::ip::address_v4;
|
|
|
|
std::unique_ptr<sim::asio::io_service> make_io_service(sim::simulation& sim, int i)
|
|
{
|
|
char ep[30];
|
|
snprintf(ep, sizeof(ep), "50.0.%d.%d", (i + 1) >> 8, (i + 1) & 0xff);
|
|
return std::unique_ptr<sim::asio::io_service>(new sim::asio::io_service(
|
|
sim, asio::ip::address_v4::from_string(ep)));
|
|
}
|
|
|
|
// this is the general template for these tests. create the session with custom
|
|
// settings (Settings), set up the test, by adding torrents with certain
|
|
// arguments (Setup), run the test and verify the end state (Test)
|
|
template <typename Settings, typename Setup, typename Test>
|
|
void run_test(Settings const& sett, Setup const& setup, Test const& test)
|
|
{
|
|
// setup the simulation
|
|
sim::default_config network_cfg;
|
|
sim::simulation sim{network_cfg};
|
|
std::unique_ptr<sim::asio::io_service> ios = make_io_service(sim, 0);
|
|
lt::session_proxy zombie;
|
|
|
|
// setup settings pack to use for the session (customization point)
|
|
lt::settings_pack pack = settings();
|
|
sett(pack);
|
|
|
|
// create session
|
|
std::shared_ptr<lt::session> ses = std::make_shared<lt::session>(pack, *ios);
|
|
|
|
// set up test, like adding torrents (customization point)
|
|
setup(*ses);
|
|
|
|
// set up a timer to fire later, to verify everything we expected to happen
|
|
// happened
|
|
lt::deadline_timer timer(*ios);
|
|
timer.expires_from_now(lt::seconds((num_torrents + 1) * 60));
|
|
timer.async_wait([&](boost::system::error_code const& ec)
|
|
{
|
|
test(*ses);
|
|
|
|
// shut down
|
|
zombie = ses->abort();
|
|
ses.reset();
|
|
});
|
|
|
|
sim.run();
|
|
}
|
|
|
|
TORRENT_TEST(dont_count_slow_torrents)
|
|
{
|
|
run_test(
|
|
[](lt::settings_pack& sett) {
|
|
// session settings
|
|
sett.set_bool(lt::settings_pack::dont_count_slow_torrents, true);
|
|
sett.set_int(lt::settings_pack::active_downloads, 1);
|
|
sett.set_int(lt::settings_pack::active_seeds, 1);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
for (int i = 0; i < num_torrents; ++i)
|
|
{
|
|
lt::add_torrent_params params = create_torrent(i, false);
|
|
params.flags |= lt::add_torrent_params::flag_auto_managed;
|
|
params.flags |= lt::add_torrent_params::flag_paused;
|
|
ses.async_add_torrent(params);
|
|
}
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// verify result
|
|
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point last = lt::time_point::min();
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
int num_started = 0;
|
|
for (alert* a : alerts)
|
|
{
|
|
printf("%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count()), a->message().c_str());
|
|
if (alert_cast<torrent_resumed_alert>(a) == nullptr) continue;
|
|
|
|
lt::time_point t = a->timestamp();
|
|
if (last != lt::time_point::min())
|
|
{
|
|
// expect starting of new torrents to be spaced by 60 seconds
|
|
// the division by 2 is to allow some slack (it's integer
|
|
// division)
|
|
TEST_EQUAL(duration_cast<lt::seconds>(t - last).count() / 2, 60 / 2);
|
|
}
|
|
last = t;
|
|
++num_started;
|
|
}
|
|
|
|
TEST_EQUAL(num_started, num_torrents);
|
|
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
TEST_CHECK(h.status().auto_managed);
|
|
TEST_EQUAL(h.status().paused, false);
|
|
}
|
|
});
|
|
}
|
|
|
|
TORRENT_TEST(count_slow_torrents)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {
|
|
// session settings
|
|
sett.set_bool(settings_pack::dont_count_slow_torrents, false);
|
|
sett.set_int(settings_pack::active_downloads, 1);
|
|
sett.set_int(settings_pack::active_seeds, 1);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
for (int i = 0; i < num_torrents; ++i)
|
|
{
|
|
lt::add_torrent_params params = create_torrent(i, false);
|
|
params.flags |= add_torrent_params::flag_auto_managed;
|
|
params.flags |= add_torrent_params::flag_paused;
|
|
ses.async_add_torrent(params);
|
|
}
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// verify result (only one should have been started, even though
|
|
// they're all idle)
|
|
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
int num_started = 0;
|
|
for (alert* a : alerts)
|
|
{
|
|
printf("%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count()), a->message().c_str());
|
|
if (alert_cast<torrent_resumed_alert>(a) == nullptr) continue;
|
|
++num_started;
|
|
}
|
|
|
|
TEST_EQUAL(num_started, 1);
|
|
|
|
num_started = 0;
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
TEST_CHECK(h.status().auto_managed);
|
|
num_started += !h.status().paused;
|
|
}
|
|
TEST_EQUAL(num_started, 1);
|
|
});
|
|
}
|
|
|
|
TORRENT_TEST(force_stopped_download)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {
|
|
// session settings
|
|
sett.set_bool(settings_pack::dont_count_slow_torrents, true);
|
|
sett.set_int(settings_pack::active_downloads, 10);
|
|
sett.set_int(settings_pack::active_seeds, 10);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
for (int i = 0; i < num_torrents; ++i)
|
|
{
|
|
lt::add_torrent_params params = create_torrent(i, false);
|
|
// torrents are paused and not auto-managed
|
|
params.flags &= ~add_torrent_params::flag_auto_managed;
|
|
params.flags |= add_torrent_params::flag_paused;
|
|
ses.async_add_torrent(params);
|
|
}
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// verify result (none should have been started)
|
|
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
for (alert* a : alerts)
|
|
{
|
|
printf("%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count()), a->message().c_str());
|
|
// we don't expect any torrents being started or stopped, since
|
|
// they're all force stopped
|
|
TEST_CHECK(alert_cast<torrent_resumed_alert>(a) == nullptr);
|
|
TEST_CHECK(alert_cast<torrent_paused_alert>(a) == nullptr);
|
|
}
|
|
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
TEST_CHECK(!h.status().auto_managed);
|
|
TEST_CHECK(h.status().paused);
|
|
}
|
|
});
|
|
}
|
|
|
|
TORRENT_TEST(force_started)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {
|
|
// session settings
|
|
sett.set_bool(settings_pack::dont_count_slow_torrents, false);
|
|
sett.set_int(settings_pack::active_downloads, 1);
|
|
sett.set_int(settings_pack::active_seeds, 1);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
for (int i = 0; i < num_torrents; ++i)
|
|
{
|
|
lt::add_torrent_params params = create_torrent(i, false);
|
|
// torrents are started and not auto-managed
|
|
params.flags &= ~add_torrent_params::flag_auto_managed;
|
|
params.flags &= ~add_torrent_params::flag_paused;
|
|
ses.async_add_torrent(params);
|
|
}
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// verify result (none should have been started)
|
|
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
for (alert* a : alerts)
|
|
{
|
|
printf("%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count()), a->message().c_str());
|
|
// we don't expect any torrents being started or stopped, since
|
|
// they're all force started
|
|
TEST_CHECK(alert_cast<torrent_resumed_alert>(a) == nullptr);
|
|
TEST_CHECK(alert_cast<torrent_paused_alert>(a) == nullptr);
|
|
}
|
|
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
TEST_CHECK(!h.status().auto_managed);
|
|
TEST_CHECK(!h.status().paused);
|
|
}
|
|
});
|
|
}
|
|
|
|
TORRENT_TEST(seed_limit)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {
|
|
// session settings
|
|
// set the seed limit to 3
|
|
sett.set_bool(settings_pack::dont_count_slow_torrents, false);
|
|
sett.set_int(settings_pack::active_checking, 1);
|
|
sett.set_int(settings_pack::active_seeds, 3);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
// add 5 seeds
|
|
for (int i = 0; i < num_torrents; ++i)
|
|
{
|
|
lt::add_torrent_params params = create_torrent(i, true);
|
|
// torrents are paused and auto-managed
|
|
params.flags |= add_torrent_params::flag_auto_managed;
|
|
params.flags |= add_torrent_params::flag_paused;
|
|
ses.async_add_torrent(params);
|
|
}
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// make sure only 3 got started
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
int num_started = 0;
|
|
int num_checking = 0;
|
|
int num_seeding = 0;
|
|
for (alert* a : alerts)
|
|
{
|
|
fprintf(stderr, "%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count()), a->message().c_str());
|
|
if (alert_cast<torrent_resumed_alert>(a))
|
|
{
|
|
++num_started;
|
|
|
|
fprintf(stderr, "started: %d checking: %d seeding: %d\n"
|
|
, num_started, num_checking, num_seeding);
|
|
}
|
|
else if (alert_cast<torrent_paused_alert>(a))
|
|
{
|
|
TEST_CHECK(num_started > 0);
|
|
--num_started;
|
|
|
|
fprintf(stderr, "started: %d checking: %d seeding: %d\n"
|
|
, num_started, num_checking, num_seeding);
|
|
}
|
|
else if (state_changed_alert* sc = alert_cast<state_changed_alert>(a))
|
|
{
|
|
if (sc->prev_state == torrent_status::checking_files)
|
|
--num_checking;
|
|
else if (sc->prev_state == torrent_status::seeding)
|
|
--num_seeding;
|
|
|
|
if (sc->state == torrent_status::checking_files)
|
|
++num_checking;
|
|
else if (sc->state == torrent_status::seeding)
|
|
++num_seeding;
|
|
|
|
fprintf(stderr, "started: %d checking: %d seeding: %d\n"
|
|
, num_started, num_checking, num_seeding);
|
|
|
|
// while at least one torrent is checking, there may be another
|
|
// started torrent (the checking one), other than that, only 3
|
|
// torrents are allowed to be started and seeding
|
|
TEST_CHECK(num_started <= 3 + 1);
|
|
TEST_CHECK(num_started <= 1 || num_seeding > 0);
|
|
}
|
|
}
|
|
|
|
TEST_EQUAL(num_started, 3);
|
|
|
|
num_started = 0;
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
TEST_CHECK(h.status().auto_managed);
|
|
TEST_CHECK(h.status().is_seeding);
|
|
num_started += !h.status().paused;
|
|
}
|
|
TEST_EQUAL(num_started, 3);
|
|
});
|
|
}
|
|
|
|
TORRENT_TEST(download_limit)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {
|
|
// session settings
|
|
// set the seed limit to 3
|
|
sett.set_bool(settings_pack::dont_count_slow_torrents, false);
|
|
sett.set_int(settings_pack::active_checking, 1);
|
|
sett.set_int(settings_pack::active_downloads, 3);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
// add 5 seeds
|
|
for (int i = 0; i < num_torrents; ++i)
|
|
{
|
|
lt::add_torrent_params params = create_torrent(i, false);
|
|
// torrents are paused and auto-managed
|
|
params.flags |= add_torrent_params::flag_auto_managed;
|
|
params.flags |= add_torrent_params::flag_paused;
|
|
ses.async_add_torrent(params);
|
|
}
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// make sure only 3 got started
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
int num_started = 0;
|
|
int num_checking = 0;
|
|
int num_downloading = 0;
|
|
for (alert* a : alerts)
|
|
{
|
|
fprintf(stderr, "%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count()), a->message().c_str());
|
|
if (alert_cast<torrent_resumed_alert>(a))
|
|
{
|
|
++num_started;
|
|
|
|
fprintf(stderr, "started: %d checking: %d downloading: %d\n"
|
|
, num_started, num_checking, num_downloading);
|
|
}
|
|
else if (alert_cast<torrent_paused_alert>(a))
|
|
{
|
|
TEST_CHECK(num_started > 0);
|
|
--num_started;
|
|
|
|
fprintf(stderr, "started: %d checking: %d downloading: %d\n"
|
|
, num_started, num_checking, num_downloading);
|
|
}
|
|
else if (state_changed_alert* sc = alert_cast<state_changed_alert>(a))
|
|
{
|
|
if (sc->prev_state == torrent_status::checking_files)
|
|
--num_checking;
|
|
else if (sc->prev_state == torrent_status::downloading)
|
|
--num_downloading;
|
|
|
|
if (sc->state == torrent_status::checking_files)
|
|
++num_checking;
|
|
else if (sc->state == torrent_status::downloading)
|
|
++num_downloading;
|
|
|
|
fprintf(stderr, "started: %d checking: %d downloading: %d\n"
|
|
, num_started, num_checking, num_downloading);
|
|
|
|
// while at least one torrent is checking, there may be another
|
|
// started torrent (the checking one), other than that, only 3
|
|
// torrents are allowed to be started and seeding
|
|
TEST_CHECK(num_started <= 3 + 1);
|
|
TEST_CHECK(num_started <= 1 || num_downloading > 0);
|
|
}
|
|
}
|
|
|
|
TEST_EQUAL(num_started, 3);
|
|
|
|
num_started = 0;
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
TEST_CHECK(h.status().auto_managed);
|
|
TEST_CHECK(!h.status().is_finished);
|
|
num_started += !h.status().paused;
|
|
}
|
|
TEST_EQUAL(num_started, 3);
|
|
});
|
|
}
|
|
// make sure torrents don't announce to the tracker when transitioning from
|
|
// checking to paused downloading
|
|
TORRENT_TEST(checking_announce)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {
|
|
// session settings
|
|
// set the seed limit to 3
|
|
sett.set_bool(settings_pack::dont_count_slow_torrents, false);
|
|
sett.set_int(settings_pack::active_checking, 1);
|
|
|
|
// just set the tracker retry intervals really long, to make sure we
|
|
// don't keep retrying the tracker (since there's nothing running
|
|
// there, it will fail)
|
|
sett.set_int(settings_pack::tracker_backoff, 100000);
|
|
// only the first torrent added should ever announce
|
|
sett.set_int(settings_pack::active_seeds, 1);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
// add 5 seeds
|
|
for (int i = 0; i < num_torrents; ++i)
|
|
{
|
|
lt::add_torrent_params params = create_torrent(i, true);
|
|
// torrents are paused and auto-managed
|
|
params.flags |= add_torrent_params::flag_auto_managed;
|
|
params.flags |= add_torrent_params::flag_paused;
|
|
// we need this to get the tracker_announce_alert
|
|
params.trackers.push_back("http://10.10.0.2/announce");
|
|
ses.async_add_torrent(params);
|
|
}
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// make sure only 3 got started
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
int num_announce = 0;
|
|
for (alert* a : alerts)
|
|
{
|
|
fprintf(stderr, "%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count()), a->message().c_str());
|
|
if (alert_cast<tracker_announce_alert>(a))
|
|
++num_announce;
|
|
}
|
|
|
|
TEST_EQUAL(num_announce, 1);
|
|
|
|
int num_started = 0;
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
TEST_CHECK(h.status().auto_managed);
|
|
num_started += !h.status().paused;
|
|
}
|
|
TEST_EQUAL(num_started, 1);
|
|
});
|
|
}
|
|
|
|
TORRENT_TEST(paused_checking)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {
|
|
// session settings
|
|
// set the seed limit to 3
|
|
sett.set_bool(settings_pack::dont_count_slow_torrents, true);
|
|
sett.set_int(settings_pack::active_checking, 1);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
// add 5 seeds
|
|
for (int i = 0; i < num_torrents; ++i)
|
|
{
|
|
lt::add_torrent_params params = create_torrent(i, true);
|
|
// torrents are paused and auto-managed
|
|
params.flags &= ~add_torrent_params::flag_auto_managed;
|
|
params.flags |= add_torrent_params::flag_paused;
|
|
ses.async_add_torrent(params);
|
|
}
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// make sure only 3 got started
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
for (alert* a : alerts)
|
|
{
|
|
fprintf(stderr, "%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count()), a->message().c_str());
|
|
if (state_changed_alert* sc = alert_cast<state_changed_alert>(a))
|
|
{
|
|
TEST_CHECK(sc->state == torrent_status::checking_files
|
|
|| sc->state == torrent_status::checking_resume_data);
|
|
}
|
|
}
|
|
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
// even though all torrents are seeding, libtorrent shouldn't know
|
|
// that, because they should never have been checked (because they
|
|
// were force stopped)
|
|
TEST_CHECK(!h.status().is_seeding);
|
|
TEST_CHECK(!h.status().auto_managed);
|
|
TEST_CHECK(h.status().paused);
|
|
}
|
|
});
|
|
}
|
|
|
|
// set the stop_when_ready flag and make sure we receive a paused alert *before*
|
|
// a state_changed_alert
|
|
TORRENT_TEST(stop_when_ready)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
lt::add_torrent_params params = create_torrent(0, true);
|
|
// torrents are started and auto-managed
|
|
params.flags |= add_torrent_params::flag_auto_managed;
|
|
params.flags |= add_torrent_params::flag_stop_when_ready;
|
|
// we need this to get the tracker_announce_alert
|
|
params.trackers.push_back("http://10.10.0.2/announce");
|
|
ses.async_add_torrent(params);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// verify result (none should have been started)
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
int num_paused = 0;
|
|
for (alert* a : alerts)
|
|
{
|
|
fprintf(stderr, "%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count()), a->message().c_str());
|
|
|
|
if (alert_cast<torrent_paused_alert>(a))
|
|
{
|
|
++num_paused;
|
|
}
|
|
|
|
if (state_changed_alert* sc = alert_cast<state_changed_alert>(a))
|
|
{
|
|
if (sc->state == torrent_status::seeding)
|
|
{
|
|
// once we turn into beeing a seed. we should have been paused
|
|
// already.
|
|
TEST_EQUAL(num_paused, 1);
|
|
}
|
|
}
|
|
// there should not have been any announces. the torrent should have
|
|
// been stopped *before* announcing.
|
|
TEST_CHECK(alert_cast<tracker_announce_alert>(a) == NULL);
|
|
}
|
|
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
// the torrent should have been force-stopped (after checking was
|
|
// donw, because we set the stop_when_ready flag). Force stopped
|
|
// means not auto-managed and paused.
|
|
torrent_status st = h.status();
|
|
TEST_CHECK(!st.auto_managed);
|
|
TEST_EQUAL(st.paused, true);
|
|
// it should be seeding. If it's not seeding it may not have had its
|
|
// files checked.
|
|
TEST_EQUAL(st.state, torrent_status::seeding);
|
|
}
|
|
});
|
|
}
|
|
|
|
// This test makes sure that the fastresume check will still run, and
|
|
// potentially fail, for stopped torrents. The actual checking of files won't
|
|
// start until the torrent is un-paused/resumed though
|
|
TORRENT_TEST(resume_reject_when_paused)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {
|
|
sett.set_int(settings_pack::alert_mask, alert::all_categories);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
lt::add_torrent_params params = create_torrent(0, true);
|
|
|
|
// the torrent is not auto managed and paused. Once the resume data
|
|
// check completes, it will stay paused but the resume_rejected_alert
|
|
// will be posted
|
|
params.flags &= ~add_torrent_params::flag_auto_managed;
|
|
params.flags |= add_torrent_params::flag_paused;
|
|
|
|
// an empty dictionary will be rejected
|
|
params.resume_data = {'d', 'e'};
|
|
ses.async_add_torrent(params);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
int num_piece_finished = 0;
|
|
int resume_rejected = 0;
|
|
int state_changed = 0;
|
|
|
|
for (alert* a : alerts)
|
|
{
|
|
fprintf(stderr, "%-3d %-25s %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count())
|
|
, a->what()
|
|
, a->message().c_str());
|
|
|
|
if (alert_cast<piece_finished_alert>(a))
|
|
++num_piece_finished;
|
|
|
|
if (alert_cast<fastresume_rejected_alert>(a))
|
|
++resume_rejected;
|
|
|
|
if (auto sc = alert_cast<state_changed_alert>(a))
|
|
{
|
|
if (sc->state == torrent_status::checking_files)
|
|
++state_changed;
|
|
}
|
|
}
|
|
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
// the torrent should have been force-stopped. Force stopped means
|
|
// not auto-managed and paused.
|
|
torrent_status st = h.status();
|
|
TEST_CHECK(!st.auto_managed);
|
|
TEST_EQUAL(st.paused, true);
|
|
// it should be checking files, because the resume data should have
|
|
// failed validation.
|
|
TEST_EQUAL(st.state, torrent_status::checking_files);
|
|
}
|
|
|
|
TEST_EQUAL(num_piece_finished, 0);
|
|
TEST_EQUAL(resume_rejected, 1);
|
|
TEST_EQUAL(state_changed, 1);
|
|
});
|
|
}
|
|
|
|
// this test adds the torrent in paused state and no resume data. Expecting the
|
|
// resume check to complete and just transition into checking state, but without
|
|
// actually checking anything
|
|
TORRENT_TEST(no_resume_when_paused)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {
|
|
sett.set_int(settings_pack::alert_mask, alert::all_categories);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
lt::add_torrent_params params = create_torrent(0, true);
|
|
|
|
// the torrent is not auto managed and paused.
|
|
params.flags &= ~add_torrent_params::flag_auto_managed;
|
|
params.flags |= add_torrent_params::flag_paused;
|
|
|
|
ses.async_add_torrent(params);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
int num_piece_finished = 0;
|
|
int resume_rejected = 0;
|
|
int state_changed = 0;
|
|
|
|
for (alert* a : alerts)
|
|
{
|
|
fprintf(stderr, "%-3d %-25s %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count())
|
|
, a->what()
|
|
, a->message().c_str());
|
|
|
|
if (alert_cast<piece_finished_alert>(a))
|
|
++num_piece_finished;
|
|
|
|
if (alert_cast<fastresume_rejected_alert>(a))
|
|
++resume_rejected;
|
|
|
|
if (auto sc = alert_cast<state_changed_alert>(a))
|
|
{
|
|
if (sc->state == torrent_status::checking_files)
|
|
++state_changed;
|
|
}
|
|
}
|
|
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
// the torrent should have been force-stopped. Force stopped means
|
|
// not auto-managed and paused.
|
|
torrent_status st = h.status();
|
|
TEST_CHECK(!st.auto_managed);
|
|
TEST_EQUAL(st.paused, true);
|
|
// it should be checking files, because the resume data should have
|
|
// failed validation.
|
|
TEST_EQUAL(st.state, torrent_status::checking_files);
|
|
}
|
|
|
|
TEST_EQUAL(num_piece_finished, 0);
|
|
TEST_EQUAL(resume_rejected, 0);
|
|
TEST_EQUAL(state_changed, 1);
|
|
});
|
|
}
|
|
|
|
// this is just asserting that when the files are checked we do in fact get
|
|
// piece_finished_alerts. The other tests rely on this assumption
|
|
TORRENT_TEST(no_resume_when_started)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {
|
|
sett.set_int(settings_pack::alert_mask, alert::all_categories);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrents
|
|
lt::add_torrent_params params = create_torrent(0, true);
|
|
ses.async_add_torrent(params);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
int num_piece_finished = 0;
|
|
int state_changed = 0;
|
|
|
|
for (alert* a : alerts)
|
|
{
|
|
fprintf(stderr, "%-3d %-25s %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count())
|
|
, a->what()
|
|
, a->message().c_str());
|
|
|
|
if (alert_cast<piece_finished_alert>(a))
|
|
++num_piece_finished;
|
|
|
|
if (auto sc = alert_cast<state_changed_alert>(a))
|
|
{
|
|
if (sc->state == torrent_status::checking_files)
|
|
++state_changed;
|
|
}
|
|
}
|
|
|
|
TEST_EQUAL(num_piece_finished, 9);
|
|
TEST_EQUAL(state_changed, 1);
|
|
});
|
|
}
|
|
|
|
// when setting active_seeds to 0, any completed torrent should be paused
|
|
TORRENT_TEST(pause_completed_torrents)
|
|
{
|
|
run_test(
|
|
[](settings_pack& sett) {
|
|
// session settings
|
|
sett.set_bool(settings_pack::dont_count_slow_torrents, true);
|
|
sett.set_int(settings_pack::active_downloads, 1);
|
|
sett.set_int(settings_pack::active_seeds, 0);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// add torrent
|
|
lt::add_torrent_params params = create_torrent(0, true);
|
|
params.flags |= add_torrent_params::flag_auto_managed;
|
|
params.flags |= add_torrent_params::flag_paused;
|
|
ses.async_add_torrent(params);
|
|
},
|
|
|
|
[](lt::session& ses) {
|
|
// verify result
|
|
// the torrent should have been paused immediately as it completed,
|
|
// since we don't allow any seeding torrents
|
|
|
|
std::vector<lt::alert*> alerts;
|
|
ses.pop_alerts(&alerts);
|
|
|
|
lt::time_point start_time = alerts[0]->timestamp();
|
|
|
|
int num_started = 0;
|
|
int num_finished = 0;
|
|
int num_paused = 0;
|
|
lt::time_point finished;
|
|
lt::time_point paused;
|
|
for (alert* a : alerts)
|
|
{
|
|
printf("%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
|
- start_time).count()), a->message().c_str());
|
|
if (alert_cast<torrent_resumed_alert>(a))
|
|
++num_started;
|
|
if (alert_cast<torrent_finished_alert>(a))
|
|
{
|
|
++num_finished;
|
|
finished = a->timestamp();
|
|
}
|
|
if (alert_cast<torrent_paused_alert>(a))
|
|
{
|
|
++num_paused;
|
|
paused = a->timestamp();
|
|
}
|
|
}
|
|
|
|
TEST_EQUAL(num_started, 1);
|
|
TEST_EQUAL(num_finished, 1);
|
|
TEST_EQUAL(num_paused, 1);
|
|
|
|
if (num_finished > 0 && num_paused > 0)
|
|
{
|
|
TEST_CHECK(paused >= finished);
|
|
TEST_CHECK(paused - finished < chrono::milliseconds(1));
|
|
}
|
|
|
|
num_paused = 0;
|
|
for (torrent_handle const& h : ses.get_torrents())
|
|
{
|
|
TEST_CHECK(h.status().auto_managed);
|
|
num_paused += h.status().paused;
|
|
}
|
|
TEST_EQUAL(num_paused, 1);
|
|
});
|
|
}
|
|
|
|
|
|
// TODO: assert that the torrent_paused_alert is posted when pausing
|
|
// downloading, seeding, checking torrents as well as the graceful pause
|
|
// TODO: test limits of tracker, DHT and LSD announces
|
|
|
|
|