From a75699eff1a695c3a721068bad621d86d1c6a563 Mon Sep 17 00:00:00 2001 From: arvidn Date: Mon, 10 Aug 2015 09:17:41 -0400 Subject: [PATCH] move test_metadata_extension to a simulation instead of a live test --- simulation/Jamfile | 1 + simulation/setup_swarm.cpp | 7 +- simulation/setup_swarm.hpp | 11 +- simulation/swarm_config.hpp | 11 +- simulation/test_metadata_extension.cpp | 243 +++++++++++++++++++++++++ simulation/test_utp.cpp | 7 +- test/Jamfile | 2 - test/Makefile.am | 2 - test/test_metadata_extension.cpp | 235 ------------------------ 9 files changed, 270 insertions(+), 249 deletions(-) create mode 100644 simulation/test_metadata_extension.cpp delete mode 100644 test/test_metadata_extension.cpp diff --git a/simulation/Jamfile b/simulation/Jamfile index ff803d76c..3a588131e 100644 --- a/simulation/Jamfile +++ b/simulation/Jamfile @@ -27,5 +27,6 @@ alias libtorrent-sims : [ run test_utp.cpp ] [ run test_dht.cpp ] [ run test_pe_crypto.cpp ] + [ run test_metadata_extension.cpp ] ; diff --git a/simulation/setup_swarm.cpp b/simulation/setup_swarm.cpp index 174b29345..f32de092a 100644 --- a/simulation/setup_swarm.cpp +++ b/simulation/setup_swarm.cpp @@ -74,6 +74,7 @@ struct swarm boost::make_shared(pack , boost::ref(*m_io_service.back())); m_nodes.push_back(ses); + m_config.on_session_added(i, *ses); // reserve a slot in here for when the torrent gets added (notified by // an alert) @@ -144,6 +145,9 @@ struct swarm lt::torrent_handle h = at->handle; m_torrents[session_index] = h; + // let the config object have a chance to set up the torrent + m_config.on_torrent_added(session_index, h); + // now, connect this torrent to all the others in the swarm for (int k = 0; k < session_index; ++k) { @@ -154,7 +158,8 @@ struct swarm } } - if (m_config.on_alert(a, session_index, m_torrents)) + if (m_config.on_alert(a, session_index, m_torrents + , *m_nodes[session_index])) term = true; } diff --git a/simulation/setup_swarm.hpp b/simulation/setup_swarm.hpp index ab63879fc..33431658c 100644 --- a/simulation/setup_swarm.hpp +++ b/simulation/setup_swarm.hpp @@ -45,13 +45,22 @@ struct swarm_setup_provider // called for every alert. if the simulation is done, return true virtual bool on_alert(libtorrent::alert const* alert , int session_idx - , std::vector const& handles) { return false; } + , std::vector const& handles + , libtorrent::session& ses) { return false; } // called for every torrent that's added (and every session that's started). // this is useful to give every session a unique save path and to make some // sessions seeds and others downloaders virtual libtorrent::add_torrent_params add_torrent(int idx) = 0; + // called for every torrent that's added once the torrent_handle comes back. + // can be used to set options on the torrent + virtual void on_torrent_added(int idx, libtorrent::torrent_handle h) {} + + // called for every session that's created. Leaves an opportunity for the + // configuration object to add extensions etc. + virtual void on_session_added(int idx, libtorrent::session& ses) {} + // called for every session that's added virtual libtorrent::settings_pack add_session(int idx) = 0; }; diff --git a/simulation/swarm_config.hpp b/simulation/swarm_config.hpp index d8941ef1e..7a4b10ca5 100644 --- a/simulation/swarm_config.hpp +++ b/simulation/swarm_config.hpp @@ -61,7 +61,7 @@ struct swarm_config : swarm_setup_provider file.close(); } - virtual void on_exit(std::vector const& torrents) + virtual void on_exit(std::vector const& torrents) override { TEST_CHECK(torrents.size() > 0); for (int i = 0; i < int(torrents.size()); ++i) @@ -75,7 +75,8 @@ struct swarm_config : swarm_setup_provider // called for every alert. if the simulation is done, return true virtual bool on_alert(libtorrent::alert const* alert , int session_idx - , std::vector const& torrents) + , std::vector const& torrents + , libtorrent::session& ses) override { if (torrents.empty()) return false; @@ -96,7 +97,7 @@ struct swarm_config : swarm_setup_provider // called for every torrent that's added (and every session that's started). // this is useful to give every session a unique save path and to make some // sessions seeds and others downloaders - virtual libtorrent::add_torrent_params add_torrent(int idx) + virtual libtorrent::add_torrent_params add_torrent(int idx) override { add_torrent_params p; p.flags &= ~add_torrent_params::flag_paused; @@ -108,7 +109,7 @@ struct swarm_config : swarm_setup_provider return p; } - std::string save_path(int idx) const + virtual std::string save_path(int idx) const { char path[200]; snprintf(path, sizeof(path), "swarm-%04d-peer-%02d" @@ -117,7 +118,7 @@ struct swarm_config : swarm_setup_provider } // called for every session that's added - virtual libtorrent::settings_pack add_session(int idx) + virtual libtorrent::settings_pack add_session(int idx) override { settings_pack pack = settings(); diff --git a/simulation/test_metadata_extension.cpp b/simulation/test_metadata_extension.cpp new file mode 100644 index 000000000..d7fb5828f --- /dev/null +++ b/simulation/test_metadata_extension.cpp @@ -0,0 +1,243 @@ +/* + +Copyright (c) 2008, 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 "test.hpp" +#include "setup_transfer.hpp" +#include "test_utils.hpp" +#include "test_utils.hpp" +#include "swarm_config.hpp" + +#include "libtorrent/session.hpp" +#include "libtorrent/hasher.hpp" +#include "libtorrent/alert_types.hpp" +#include "libtorrent/thread.hpp" +#include "libtorrent/extensions/metadata_transfer.hpp" +#include "libtorrent/extensions/ut_metadata.hpp" + +#include + +using namespace libtorrent; + +enum flags_t +{ + clear_files = 1, + + // disconnect immediately after receiving the metadata (to test that + // edge case, it caused a crash once) + disconnect = 2, + + // force encryption (to make sure the plugin uses the peer_connection + // API in a compatible way) + full_encryption = 4, + + // have the downloader connect to the seeder + // (instead of the other way around) + reverse = 8, + + // only use uTP + utp = 16, + + // upload-only mode + upload_only = 32 +}; + +struct test_swarm_config : swarm_config +{ + test_swarm_config(int flags + , boost::shared_ptr (*plugin)(torrent_handle const&, void*)) + : swarm_config() + , m_flags(flags) + , m_plugin(plugin) + {} + + // called for every session that's added + virtual libtorrent::settings_pack add_session(int idx) override + { + settings_pack s = swarm_config::add_session(idx); + + fprintf(stderr, " session %d\n", idx); + + fprintf(stderr, "\n==== test transfer: %s%s%s%s%s%s ====\n\n" + , (m_flags & clear_files) ? "clear-files " : "" + , (m_flags & disconnect) ? "disconnect " : "" + , (m_flags & full_encryption) ? "encryption " : "" + , (m_flags & reverse) ? "reverse " : "" + , (m_flags & utp) ? "utp " : "" + , (m_flags & upload_only) ? "upload_only " : ""); + + s.set_int(settings_pack::out_enc_policy, settings_pack::pe_forced); + s.set_int(settings_pack::in_enc_policy, settings_pack::pe_forced); + s.set_bool(settings_pack::prefer_rc4, m_flags & full_encryption); + + if (m_flags & utp) + { + s.set_bool(settings_pack::utp_dynamic_sock_buf, true); + s.set_bool(settings_pack::enable_incoming_utp, true); + s.set_bool(settings_pack::enable_outgoing_utp, true); + s.set_bool(settings_pack::enable_incoming_tcp, false); + s.set_bool(settings_pack::enable_outgoing_tcp, false); + } + else + { + s.set_bool(settings_pack::enable_incoming_utp, false); + s.set_bool(settings_pack::enable_outgoing_utp, false); + s.set_bool(settings_pack::enable_incoming_tcp, true); + s.set_bool(settings_pack::enable_outgoing_tcp, true); + } + + return s; + } + + virtual libtorrent::add_torrent_params add_torrent(int idx) override + { + add_torrent_params p = swarm_config::add_torrent(idx); + + if (m_flags & reverse) + { + p.save_path = save_path(1 - idx); + } + + if (idx == 1) + { + // this is the guy who should download the metadata. + p.info_hash = p.ti->info_hash(); + p.ti.reset(); + } + + return p; + } + + void on_session_added(int idx, session& ses) override + { + ses.add_extension(m_plugin); + } + + bool on_alert(libtorrent::alert const* alert + , int session_idx + , std::vector const& handles + , libtorrent::session& ses) override + { + // make sure this function can be called on + // torrents without metadata + if ((m_flags & disconnect) == 0) + { + handles[session_idx].status(); + } + + if ((m_flags & disconnect) + && session_idx == 1 + && alert_cast(alert)) + { + ses.remove_torrent(handles[session_idx]); + return true; + } + return false; + } + + virtual void on_torrent_added(int idx, torrent_handle h) override + { + if (idx == 0) return; + + if (m_flags & upload_only) + { + h.set_upload_mode(true); + } + } + + virtual void on_exit(std::vector const& torrents) override + { + // in this case we should have completed without downloading anything + // because the downloader had upload only set + if (m_flags & upload_only) return; + + swarm_config::on_exit(torrents); + } + +private: + int m_flags; + boost::shared_ptr (*m_plugin)(torrent_handle const&, void*); +}; + +TORRENT_TEST(ut_metadata_encryption_reverse) +{ + test_swarm_config cfg(full_encryption | reverse, &create_ut_metadata_plugin); + setup_swarm(2, cfg); +} + +TORRENT_TEST(ut_metadata_encryption_utp) +{ + test_swarm_config cfg(full_encryption | utp, &create_ut_metadata_plugin); + setup_swarm(2, cfg); +} + +TORRENT_TEST(ut_metadata_reverse) +{ + test_swarm_config cfg(reverse, &create_ut_metadata_plugin); + setup_swarm(2, cfg); +} + +TORRENT_TEST(ut_metadata_upload_only) +{ + test_swarm_config cfg(upload_only, &create_ut_metadata_plugin); + setup_swarm(2, cfg); +} + +#ifndef TORRENT_NO_DEPRECATE + +// TODO: add more flags combinations? + +TORRENT_TEST(metadata_encryption_reverse) +{ + test_swarm_config cfg(full_encryption | reverse, &create_metadata_plugin); + setup_swarm(2, cfg); +} + +TORRENT_TEST(metadata_encryption_utp) +{ + test_swarm_config cfg(full_encryption | utp, &create_metadata_plugin); + setup_swarm(2, cfg); +} + +TORRENT_TEST(metadata_reverse) +{ + test_swarm_config cfg(reverse, &create_metadata_plugin); + setup_swarm(2, cfg); +} + +TORRENT_TEST(metadata_upload_only) +{ + test_swarm_config cfg(upload_only, &create_metadata_plugin); + setup_swarm(2, cfg); +} + +#endif + diff --git a/simulation/test_utp.cpp b/simulation/test_utp.cpp index 11a49edb7..1d049d117 100644 --- a/simulation/test_utp.cpp +++ b/simulation/test_utp.cpp @@ -105,7 +105,8 @@ struct swarm_config : swarm_setup_provider // called for every alert. if the simulation is done, return true virtual bool on_alert(libtorrent::alert const* alert , int session_idx - , std::vector const& torrents) + , std::vector const& torrents + , libtorrent::session& ses) override { if (torrents.empty()) return false; @@ -126,7 +127,7 @@ struct swarm_config : swarm_setup_provider // called for every torrent that's added (and every session that's started). // this is useful to give every session a unique save path and to make some // sessions seeds and others downloaders - virtual libtorrent::add_torrent_params add_torrent(int idx) + virtual libtorrent::add_torrent_params add_torrent(int idx) override { add_torrent_params p; p.flags &= ~add_torrent_params::flag_paused; @@ -148,7 +149,7 @@ struct swarm_config : swarm_setup_provider } // called for every session that's added - virtual libtorrent::settings_pack add_session(int idx) + virtual libtorrent::settings_pack add_session(int idx) override { settings_pack pack = settings(); diff --git a/test/Jamfile b/test/Jamfile index 2959aa1ae..24c31b58d 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -177,7 +177,6 @@ test-suite libtorrent : [ run test_http_connection.cpp ] [ run test_torrent.cpp ] [ run test_transfer.cpp ] - [ run test_metadata_extension.cpp ] [ run test_trackers_extension.cpp ] [ run test_time_critical.cpp ] [ run test_pex.cpp ] @@ -201,7 +200,6 @@ alias win-tests : test_torrent test_transfer test_time_critical - test_metadata_extension test_pex test_priority test_super_seeding diff --git a/test/Makefile.am b/test/Makefile.am index e6a89eaae..a8b3ecd32 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -13,7 +13,6 @@ test_programs = \ test_fast_extension \ test_http_connection \ test_lsd \ - test_metadata_extension \ test_pe_crypto \ test_pex \ test_read_piece \ @@ -170,7 +169,6 @@ test_checking_SOURCES = test_checking.cpp test_fast_extension_SOURCES = test_fast_extension.cpp test_http_connection_SOURCES = test_http_connection.cpp test_lsd_SOURCES = test_lsd.cpp -test_metadata_extension_SOURCES = test_metadata_extension.cpp test_pe_crypto_SOURCES = test_pe_crypto.cpp test_pex_SOURCES = test_pex.cpp test_read_piece_SOURCES = test_read_piece.cpp diff --git a/test/test_metadata_extension.cpp b/test/test_metadata_extension.cpp deleted file mode 100644 index 58c7a9e8b..000000000 --- a/test/test_metadata_extension.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - -Copyright (c) 2008, 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 "test.hpp" -#include "setup_transfer.hpp" -#include "test_utils.hpp" -#include "test_utils.hpp" - -#include "libtorrent/session.hpp" -#include "libtorrent/hasher.hpp" -#include "libtorrent/thread.hpp" -#include "libtorrent/extensions/metadata_transfer.hpp" -#include "libtorrent/extensions/ut_metadata.hpp" - -#include - -using boost::tuples::ignore; - -enum flags_t -{ - clear_files = 1, - - // disconnect immediately after receiving the metadata (to test that - // edge case, it caused a crash once) - disconnect = 2, - - // force encryption (to make sure the plugin uses the peer_connection - // API in a compatible way) - full_encryption = 4, - - // have the downloader connect to the seeder - // (instead of the other way around) - reverse = 8, - - // only use uTP - utp = 16, - - // upload-only mode - upload_only = 32 -}; - -void test_transfer(int flags - , boost::shared_ptr (*constructor)(libtorrent::torrent_handle const&, void*) - , int timeout) -{ - using namespace libtorrent; - namespace lt = libtorrent; - - fprintf(stderr, "\n==== test transfer: timeout=%d %s%s%s%s%s%s ====\n\n" - , timeout - , (flags & clear_files) ? "clear-files " : "" - , (flags & disconnect) ? "disconnect " : "" - , (flags & full_encryption) ? "encryption " : "" - , (flags & reverse) ? "reverse " : "" - , (flags & utp) ? "utp " : "" - , (flags & upload_only) ? "upload_only " : ""); - - // these are declared before the session objects - // so that they are destructed last. This enables - // the sessions to destruct in parallel - session_proxy p1; - session_proxy p2; - - settings_pack pack; - pack.set_int(settings_pack::out_enc_policy, settings_pack::pe_forced); - pack.set_int(settings_pack::in_enc_policy, settings_pack::pe_forced); - pack.set_bool(settings_pack::prefer_rc4, flags & full_encryption); - - if (flags & utp) - { - pack.set_bool(settings_pack::utp_dynamic_sock_buf, true); - pack.set_bool(settings_pack::enable_incoming_utp, true); - pack.set_bool(settings_pack::enable_outgoing_utp, true); - pack.set_bool(settings_pack::enable_incoming_tcp, false); - pack.set_bool(settings_pack::enable_outgoing_tcp, false); - } - else - { - pack.set_bool(settings_pack::enable_incoming_utp, false); - pack.set_bool(settings_pack::enable_outgoing_utp, false); - pack.set_bool(settings_pack::enable_incoming_tcp, true); - pack.set_bool(settings_pack::enable_outgoing_tcp, true); - } - - // TODO: it would be nice to test reversing - // which session is making the connection as well - pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:48100"); - lt::session ses1(pack); - pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:49100"); - lt::session ses2(pack); - ses1.add_extension(constructor); - ses2.add_extension(constructor); - torrent_handle tor1; - torrent_handle tor2; - - lt::session* downloader = &ses2; - lt::session* seed = &ses1; - - boost::tie(tor1, tor2, ignore) = setup_transfer(seed, downloader, NULL - , flags & clear_files, true, false, "_meta"); - - if (flags & upload_only) - { - tor2.set_upload_mode(true); - } - - if (flags & reverse) - { - error_code ec; - int port = seed->listen_port(); - fprintf(stderr, "%s: downloader: connecting peer port: %d\n" - , time_now_string(), port); - tor2.connect_peer(tcp::endpoint(address::from_string("127.0.0.1", ec) - , port)); - } - else - { - error_code ec; - int port = downloader->listen_port(); - fprintf(stderr, "%s: seed: connecting peer port: %d\n" - , time_now_string(), port); - tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1", ec) - , port)); - } - - for (int i = 0; i < timeout * 10; ++i) - { - // make sure this function can be called on - // torrents without metadata - if ((flags & disconnect) == 0) tor2.status(); - print_alerts(*seed, "seed", false, true); - print_alerts(*downloader, "downloader", false, true); - - if ((flags & disconnect) && tor2.is_valid()) downloader->remove_torrent(tor2); - if ((flags & disconnect) == 0 - && tor2.status().has_metadata) break; - test_sleep(100); - } - - if (flags & disconnect) goto done; - - TEST_CHECK(tor2.status().has_metadata); - - if (flags & upload_only) goto done; - - fprintf(stderr, "waiting for transfer to complete\n"); - - for (int i = 0; i < timeout * 10; ++i) - { - torrent_status st1 = tor1.status(); - torrent_status st2 = tor2.status(); - - print_alerts(*seed, "seed", false, true); - print_alerts(*downloader, "downloader", false, true); - - print_ses_rate(i / 10.f, &st1, &st2); - if (st2.is_seeding) break; - test_sleep(100); - } - - TEST_CHECK(tor2.status().is_seeding); - if (tor2.status().is_seeding) fprintf(stderr, "done\n"); - -done: - - // this allows shutting down the sessions in parallel - p1 = seed->abort(); - p2 = downloader->abort(); - - error_code ec; - remove_all("tmp1_meta", ec); - remove_all("tmp2_meta", ec); -} - -TORRENT_TEST(metadata_extension) -{ - using namespace libtorrent; - -#ifndef TORRENT_NO_DEPRECATE - -#ifdef TORRENT_USE_VALGRIND - const int timeout = 8; -#else - const int timeout = 3; -#endif - - test_transfer(full_encryption | reverse, &create_ut_metadata_plugin, timeout); - test_transfer(full_encryption | utp, &create_ut_metadata_plugin, timeout); - test_transfer(reverse, &create_ut_metadata_plugin, timeout); - test_transfer(upload_only, &create_ut_metadata_plugin, timeout); - -#ifndef TORRENT_NO_DEPRECATE - for (int f = 0; f <= (clear_files | disconnect | full_encryption); ++f) - test_transfer(f, &create_metadata_plugin, timeout * 2); -#endif - - for (int f = 0; f <= (clear_files | disconnect | full_encryption); ++f) - test_transfer(f, &create_ut_metadata_plugin, timeout); - - error_code ec; - remove_all("tmp1", ec); - remove_all("tmp2", ec); - -#endif // TORRENT_NO_DEPRECATE -} -