premiere-libtorrent/test/test_piece_picker.cpp

831 lines
28 KiB
C++

#include "libtorrent/piece_picker.hpp"
#include "libtorrent/policy.hpp"
#include "libtorrent/bitfield.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <algorithm>
#include <vector>
#include <set>
#include "test.hpp"
using namespace libtorrent;
const int blocks_per_piece = 4;
bitfield string2vec(char const* have_str)
{
const int num_pieces = strlen(have_str);
bitfield have(num_pieces, false);
for (int i = 0; i < num_pieces; ++i)
if (have_str[i] != ' ') have.set_bit(i);
return have;
}
// availability is a string where each character is the
// availability of that piece, '1', '2' etc.
// have_str is a string where each character represents a
// piece, ' ' means we don't have the piece and any other
// character means we have it
boost::shared_ptr<piece_picker> setup_picker(
char const* availability
, char const* have_str
, char const* priority
, char const* partial)
{
const int num_pieces = strlen(availability);
assert(int(strlen(have_str)) == num_pieces);
boost::shared_ptr<piece_picker> p(new piece_picker);
p->init(blocks_per_piece, num_pieces * blocks_per_piece);
bitfield have = string2vec(have_str);
for (int i = 0; i < num_pieces; ++i)
{
if (partial[i] == 0) break;
if (partial[i] == ' ') continue;
int blocks = 0;
if (partial[i] >= '0' && partial[i] <= '9')
blocks = partial[i] - '0';
else
blocks = partial[i] - 'a' + 10;
int counter = 0;
if (blocks & 1)
{
++counter;
p->mark_as_finished(piece_block(i, 0), 0);
}
if (blocks & 2)
{
++counter;
p->mark_as_finished(piece_block(i, 1), 0);
}
if (blocks & 4)
{
++counter;
p->mark_as_finished(piece_block(i, 2), 0);
}
if (blocks & 8)
{
++counter;
p->mark_as_finished(piece_block(i, 3), 0);
}
piece_picker::downloading_piece st;
p->piece_info(i, st);
TEST_CHECK(st.writing == 0);
TEST_CHECK(st.requested == 0);
TEST_CHECK(st.index == i);
TEST_CHECK(st.finished == counter);
}
for (int i = 0; i < num_pieces; ++i)
{
if (priority[i] == 0) break;
const int prio = priority[i] - '0';
assert(prio >= 0);
p->set_piece_priority(i, prio);
TEST_CHECK(p->piece_priority(i) == prio);
}
for (int i = 0; i < num_pieces; ++i)
{
if (!have[i]) continue;
p->we_have(i);
for (int j = 0; j < blocks_per_piece; ++j)
TEST_CHECK(p->is_finished(piece_block(i, j)));
}
for (int i = 0; i < num_pieces; ++i)
{
const int avail = availability[i] - '0';
assert(avail >= 0);
for (int j = 0; j < avail; ++j) p->inc_refcount(i);
}
std::vector<int> availability_vec;
p->get_availability(availability_vec);
for (int i = 0; i < num_pieces; ++i)
{
const int avail = availability[i] - '0';
assert(avail >= 0);
TEST_CHECK(avail == availability_vec[i]);
}
#ifndef NDEBUG
p->check_invariant();
#endif
return p;
}
bool verify_pick(boost::shared_ptr<piece_picker> p
, std::vector<piece_block> const& picked)
{
#ifndef NDEBUG
p->check_invariant();
#endif
for (std::vector<piece_block>::const_iterator i = picked.begin()
, end(picked.end()); i != end; ++i)
{
if (p->num_peers(*i) > 0) return false;
}
// make sure there are no duplicated
std::set<piece_block> blocks;
std::copy(picked.begin(), picked.end(), std::insert_iterator<std::set<piece_block> >(blocks, blocks.end()));
return picked.size() == blocks.size();
}
void print_pick(std::vector<piece_block> const& picked)
{
for (int i = 0; i < int(picked.size()); ++i)
{
std::cout << "(" << picked[i].piece_index << ", " << picked[i].block_index << ") ";
}
std::cout << std::endl;
}
void print_title(char const* name)
{
std::cerr << "==== " << name << " ====\n";
}
int test_pick(boost::shared_ptr<piece_picker> const& p)
{
std::vector<piece_block> picked;
const std::vector<int> empty_vector;
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) == 1);
return picked[0].piece_index;
}
int test_main()
{
tcp::endpoint endp;
policy::peer peer_struct(endp, policy::peer::connectable, 0);
std::vector<piece_block> picked;
boost::shared_ptr<piece_picker> p;
const std::vector<int> empty_vector;
// make sure the block that is picked is from piece 1, since it
// it is the piece with the lowest availability
print_title("test pick lowest availability");
p = setup_picker("2223333", "* * * ", "", "");
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front().piece_index == 1);
// ========================================================
// make sure the block that is picked is from piece 5, since it
// has the highest priority among the available pieces
print_title("test pick highest priority");
p = setup_picker("1111111", "* * * ", "1111122", "");
picked.clear();
p->pick_pieces(string2vec("****** "), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front().piece_index == 5);
// ========================================================
// make sure the 4 blocks are picked from the same piece if
// whole pieces are preferred. The only whole piece is 1.
print_title("test pick whole pieces");
p = setup_picker("1111111", " ", "1111111", "1023460");
picked.clear();
p->pick_pieces(string2vec("****** "), picked, 1, 1, &peer_struct, piece_picker::fast, true, true, empty_vector);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
for (int i = 0; i < blocks_per_piece && i < int(picked.size()); ++i)
TEST_CHECK(picked[i].piece_index == 1);
// ========================================================
// test the distributed copies function. It should include ourself
// in the availability. i.e. piece 0 has availability 2.
// there are 2 pieces with availability 2 and 5 with availability 3
print_title("test distributed copies");
p = setup_picker("1233333", "* ", "", "");
float dc = p->distributed_copies();
TEST_CHECK(fabs(dc - (2.f + 5.f / 7.f)) < 0.01f);
// ========================================================
// make sure filtered pieces are ignored
print_title("test filtered pieces");
p = setup_picker("1111111", " ", "0010000", "");
picked.clear();
p->pick_pieces(string2vec("*** ** "), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front().piece_index == 2);
// ========================================================
// make sure we_dont_have works
print_title("test we_dont_have");
p = setup_picker("1111111", "*******", "0100000", "");
picked.clear();
p->we_dont_have(1);
p->we_dont_have(2);
p->pick_pieces(string2vec("*** ** "), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front().piece_index == 1);
// ========================================================
// make sure requested blocks aren't picked
print_title("test don't pick requested blocks");
p = setup_picker("1234567", " ", "", "");
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front().piece_index == 0);
piece_block first = picked.front();
p->mark_as_downloading(picked.front(), &peer_struct, piece_picker::fast);
TEST_CHECK(p->num_peers(picked.front()) == 1);
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front() != first);
TEST_CHECK(picked.front().piece_index == 0);
// ========================================================
/*
// test sequenced download
p = setup_picker("7654321", " ", "", "");
picked.clear();
p->set_sequenced_download_threshold(3);
p->pick_pieces(string2vec("***** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) == 5 * blocks_per_piece);
for (int i = 0; i < 5 * blocks_per_piece && i < int(picked.size()); ++i)
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece);
picked.clear();
p->set_sequenced_download_threshold(4);
p->pick_pieces(string2vec("**** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) == 4 * blocks_per_piece);
for (int i = 0; i < 4 * blocks_per_piece && i < int(picked.size()); ++i)
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece);
picked.clear();
p->set_sequenced_download_threshold(2);
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) == 6 * blocks_per_piece);
for (int i = 0; i < 6 * blocks_per_piece && i < int(picked.size()); ++i)
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece);
picked.clear();
p->set_piece_priority(0, 0);
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) == 5 * blocks_per_piece);
for (int i = 0; i < 5 * blocks_per_piece && i < int(picked.size()); ++i)
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece + 1);
picked.clear();
p->set_piece_priority(0, 1);
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) == 6 * blocks_per_piece);
for (int i = 0; i < 6 * blocks_per_piece && i < int(picked.size()); ++i)
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece);
*/
// ========================================================
// test piece priorities
print_title("test piece priorities");
p = setup_picker("5555555", " ", "3214576", "");
TEST_CHECK(p->num_filtered() == 0);
TEST_CHECK(p->num_have_filtered() == 0);
p->set_piece_priority(0, 0);
TEST_CHECK(p->num_filtered() == 1);
TEST_CHECK(p->num_have_filtered() == 0);
p->mark_as_finished(piece_block(0,0), 0);
p->we_have(0);
TEST_CHECK(p->num_filtered() == 0);
TEST_CHECK(p->num_have_filtered() == 1);
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) == 6 * blocks_per_piece);
TEST_CHECK(picked[0 * blocks_per_piece].piece_index == 5);
// priority 5 and 6 is currently the same
TEST_CHECK(picked[1 * blocks_per_piece].piece_index == 6 || picked[1 * blocks_per_piece].piece_index == 4);
TEST_CHECK(picked[2 * blocks_per_piece].piece_index == 6 || picked[2 * blocks_per_piece].piece_index == 4);
TEST_CHECK(picked[3 * blocks_per_piece].piece_index == 3);
TEST_CHECK(picked[4 * blocks_per_piece].piece_index == 1);
TEST_CHECK(picked[5 * blocks_per_piece].piece_index == 2);
std::vector<int> prios;
p->piece_priorities(prios);
TEST_CHECK(prios.size() == 7);
int prio_comp[] = {0, 2, 1, 4, 5, 7, 6};
TEST_CHECK(std::equal(prios.begin(), prios.end(), prio_comp));
// ========================================================
// test restore_piece
print_title("test restore piece");
p = setup_picker("1234567", " ", "", "");
p->mark_as_finished(piece_block(0,0), 0);
p->mark_as_finished(piece_block(0,1), 0);
p->mark_as_finished(piece_block(0,2), 0);
p->mark_as_finished(piece_block(0,3), 0);
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= 1);
TEST_CHECK(picked.front().piece_index == 1);
p->restore_piece(0);
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= 1);
TEST_CHECK(picked.front().piece_index == 0);
p->mark_as_finished(piece_block(0,0), 0);
p->mark_as_finished(piece_block(0,1), 0);
p->mark_as_finished(piece_block(0,2), 0);
p->mark_as_finished(piece_block(0,3), 0);
p->set_piece_priority(0, 0);
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= 1);
TEST_CHECK(picked.front().piece_index == 1);
p->restore_piece(0);
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= 1);
TEST_CHECK(picked.front().piece_index == 1);
p->set_piece_priority(0, 1);
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= 1);
TEST_CHECK(picked.front().piece_index == 0);
// ========================================================
// test non-rarest-first mode
print_title("test not rarest first");
p = setup_picker("1234567", "* * * ", "1111122", "");
picked.clear();
p->pick_pieces(string2vec("****** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, false, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) == 3 * blocks_per_piece);
for (int i = 0; i < 4 * blocks_per_piece && i < int(picked.size()); ++i)
{
TEST_CHECK(picked[i].piece_index != 0);
TEST_CHECK(picked[i].piece_index != 2);
TEST_CHECK(picked[i].piece_index != 4);
}
// ========================================================
// test have_all and have_none
print_title("test have_all and have_none");
p = setup_picker("0123333", "* ", "", "");
dc = p->distributed_copies();
std::cout << "distributed copies: " << dc << std::endl;
TEST_CHECK(fabs(dc - (1.f + 5.f / 7.f)) < 0.01f);
p->inc_refcount_all();
dc = p->distributed_copies();
std::cout << "distributed copies: " << dc << std::endl;
TEST_CHECK(fabs(dc - (2.f + 5.f / 7.f)) < 0.01f);
p->dec_refcount_all();
dc = p->distributed_copies();
std::cout << "distributed copies: " << dc << std::endl;
TEST_CHECK(fabs(dc - (1.f + 5.f / 7.f)) < 0.01f);
p->inc_refcount(0);
p->dec_refcount_all();
dc = p->distributed_copies();
std::cout << "distributed copies: " << dc << std::endl;
TEST_CHECK(fabs(dc - (0.f + 6.f / 7.f)) < 0.01f);
TEST_CHECK(test_pick(p) == 2);
// ========================================================
// test have_all and have_none with sequential download
print_title("test have_all and have_none with sequential download");
p = setup_picker("0123333", "* ", "", "");
dc = p->distributed_copies();
std::cout << "distributed copies: " << dc << std::endl;
TEST_CHECK(fabs(dc - (1.f + 5.f / 7.f)) < 0.01f);
p->inc_refcount_all();
dc = p->distributed_copies();
std::cout << "distributed copies: " << dc << std::endl;
TEST_CHECK(fabs(dc - (2.f + 5.f / 7.f)) < 0.01f);
p->sequential_download(true);
p->dec_refcount_all();
dc = p->distributed_copies();
std::cout << "distributed copies: " << dc << std::endl;
TEST_CHECK(fabs(dc - (1.f + 5.f / 7.f)) < 0.01f);
p->inc_refcount(0);
p->dec_refcount_all();
dc = p->distributed_copies();
std::cout << "distributed copies: " << dc << std::endl;
TEST_CHECK(fabs(dc - (0.f + 6.f / 7.f)) < 0.01f);
p->inc_refcount(1);
TEST_CHECK(test_pick(p) == 1);
// ========================================================
// test inc_ref and dec_ref
print_title("test inc_ref dec_ref");
p = setup_picker("1233333", " * ", "", "");
TEST_CHECK(test_pick(p) == 0);
p->dec_refcount(0);
TEST_CHECK(test_pick(p) == 1);
p->dec_refcount(4);
p->dec_refcount(4);
TEST_CHECK(test_pick(p) == 4);
// decrease refcount on something that's not in the piece list
p->dec_refcount(5);
p->inc_refcount(5);
p->inc_refcount(0);
p->dec_refcount(4);
TEST_CHECK(test_pick(p) == 0);
// ========================================================
/*
// test have_all and have_none, with a sequenced download threshold
p = setup_picker("1233333", "* ", "", "");
p->set_sequenced_download_threshold(3);
p->inc_refcount_all();
dc = p->distributed_copies();
TEST_CHECK(fabs(dc - (3.f + 5.f / 7.f)) < 0.01f);
p->dec_refcount_all();
dc = p->distributed_copies();
TEST_CHECK(fabs(dc - (2.f + 5.f / 7.f)) < 0.01f);
p->dec_refcount(2);
dc = p->distributed_copies();
TEST_CHECK(fabs(dc - (2.f + 4.f / 7.f)) < 0.01f);
p->mark_as_downloading(piece_block(1,0), &peer_struct, piece_picker::fast);
p->mark_as_downloading(piece_block(1,1), &peer_struct, piece_picker::fast);
p->we_have(1);
dc = p->distributed_copies();
TEST_CHECK(fabs(dc - (2.f + 5.f / 7.f)) < 0.01f);
picked.clear();
// make sure it won't pick the piece we just got
p->pick_pieces(string2vec(" * ****"), picked, 100, false, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= 4 * blocks_per_piece);
TEST_CHECK(picked[0 * blocks_per_piece].piece_index == 3);
TEST_CHECK(picked[1 * blocks_per_piece].piece_index == 4);
TEST_CHECK(picked[2 * blocks_per_piece].piece_index == 5);
TEST_CHECK(picked[3 * blocks_per_piece].piece_index == 6);
*/
// ========================================================
// test unverified_blocks, marking blocks and get_downloader
print_title("test unverified blocks");
p = setup_picker("1111111", " ", "", "0300700");
TEST_CHECK(p->unverified_blocks() == 2 + 3);
TEST_CHECK(p->get_downloader(piece_block(4, 0)) == 0);
TEST_CHECK(p->get_downloader(piece_block(4, 1)) == 0);
TEST_CHECK(p->get_downloader(piece_block(4, 2)) == 0);
TEST_CHECK(p->get_downloader(piece_block(4, 3)) == 0);
p->mark_as_downloading(piece_block(4, 3), &peer_struct, piece_picker::fast);
TEST_CHECK(p->get_downloader(piece_block(4, 3)) == &peer_struct);
piece_picker::downloading_piece st;
p->piece_info(4, st);
TEST_CHECK(st.requested == 1);
TEST_CHECK(st.writing == 0);
TEST_CHECK(st.finished == 3);
TEST_CHECK(p->unverified_blocks() == 2 + 3);
p->mark_as_writing(piece_block(4, 3), &peer_struct);
TEST_CHECK(p->get_downloader(piece_block(4, 3)) == &peer_struct);
p->piece_info(4, st);
TEST_CHECK(st.requested == 0);
TEST_CHECK(st.writing == 1);
TEST_CHECK(st.finished == 3);
TEST_CHECK(p->unverified_blocks() == 2 + 3);
p->mark_as_finished(piece_block(4, 3), &peer_struct);
TEST_CHECK(p->get_downloader(piece_block(4, 3)) == &peer_struct);
p->piece_info(4, st);
TEST_CHECK(st.requested == 0);
TEST_CHECK(st.writing == 0);
TEST_CHECK(st.finished == 4);
TEST_CHECK(p->unverified_blocks() == 2 + 4);
p->we_have(4);
p->piece_info(4, st);
TEST_CHECK(st.requested == 0);
TEST_CHECK(st.writing == 0);
TEST_CHECK(st.finished == 4);
TEST_CHECK(p->get_downloader(piece_block(4, 3)) == 0);
TEST_CHECK(p->unverified_blocks() == 2);
// ========================================================
// test prefer_whole_pieces
print_title("test prefer whole pieces");
p = setup_picker("1111111", " ", "", "");
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, 3, 0, piece_picker::fast, true, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= 3 * blocks_per_piece);
piece_block b = picked.front();
for (int i = 1; i < int(picked.size()); ++i)
{
TEST_CHECK(picked[i].piece_index * blocks_per_piece + picked[i].block_index
== b.piece_index * blocks_per_piece + b.block_index + 1);
b = picked[i];
}
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, 3, 0, piece_picker::fast, false, false, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= 3 * blocks_per_piece);
b = picked.front();
for (int i = 1; i < int(picked.size()); ++i)
{
TEST_CHECK(picked[i].piece_index * blocks_per_piece + picked[i].block_index
== b.piece_index * blocks_per_piece + b.block_index + 1);
b = picked[i];
}
// ========================================================
// test parole mode
print_title("test parole mode");
p = setup_picker("3333133", " ", "", "");
p->mark_as_finished(piece_block(0, 0), 0);
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, 1, 0, piece_picker::fast, true, true, empty_vector);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= blocks_per_piece - 1);
for (int i = 1; i < int(picked.size()); ++i)
{
TEST_CHECK(picked[i].piece_index == 0);
TEST_CHECK(picked[i].block_index == i + 1);
}
// make sure that the partial piece is not picked by a
// peer that is has not downloaded/requested the other blocks
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, 1, &peer_struct, piece_picker::fast, true, true, empty_vector);
print_pick(picked);
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
for (int i = 1; i < int(picked.size()); ++i)
{
TEST_CHECK(picked[i].piece_index == 4);
TEST_CHECK(picked[i].block_index == i);
}
// ========================================================
// test suggested pieces
print_title("test suggested pieces");
p = setup_picker("1111222233334444", " ", "", "");
int v[] = {1, 5};
std::vector<int> suggested_pieces(v, v + 2);
picked.clear();
p->pick_pieces(string2vec("****************"), picked, 1, 1, 0, piece_picker::fast, true, true, suggested_pieces);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
for (int i = 1; i < int(picked.size()); ++i)
{
TEST_CHECK(picked[i].piece_index == 1);
TEST_CHECK(picked[i].block_index == i);
}
p->set_piece_priority(0, 0);
p->set_piece_priority(1, 0);
p->set_piece_priority(2, 0);
p->set_piece_priority(3, 0);
picked.clear();
p->pick_pieces(string2vec("****************"), picked, 1, 1, 0, piece_picker::fast, true, true, suggested_pieces);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
for (int i = 1; i < int(picked.size()); ++i)
{
TEST_CHECK(picked[i].piece_index == 5);
TEST_CHECK(picked[i].block_index == i);
}
p = setup_picker("1111222233334444", "**** ", "", "");
picked.clear();
p->pick_pieces(string2vec("****************"), picked, 1, 1, 0, piece_picker::fast, true, true, suggested_pieces);
print_pick(picked);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
for (int i = 1; i < int(picked.size()); ++i)
{
TEST_CHECK(picked[i].piece_index == 5);
TEST_CHECK(picked[i].block_index == i);
}
// MISSING TESTS:
// 2. inc_ref() from 0 to 1 while sequenced download threshold is 1
// 4. filtered_pieces
// 5. clear peer
// 6. pick_pieces with prefer whole pieces
// 7. is_requested
// 8. is_downloaded
// 9. get_downloaders
// 10. abort_download
/*
p.pick_pieces(peer1, picked, 1, false, 0, piece_picker::fast, true);
TEST_CHECK(int(picked.size()) == 1);
TEST_CHECK(picked.front().piece_index == 2);
// now pick a piece from peer2. The block is supposed to be
// from piece 3, since it is the rarest piece that peer has.
picked.clear();
p.pick_pieces(peer2, picked, 1, false, 0, piece_picker::fast, true);
TEST_CHECK(int(picked.size()) == 1);
TEST_CHECK(picked.front().piece_index == 3);
// same thing for peer3.
picked.clear();
p.pick_pieces(peer3, picked, 1, false, 0, piece_picker::fast, true);
TEST_CHECK(int(picked.size()) == 1);
TEST_CHECK(picked.front().piece_index == 5);
// now, if all peers would have piece 1 (the piece we have partially)
// it should be prioritized over picking a completely new piece.
peer3[1] = true;
p.inc_refcount(1);
picked.clear();
p.pick_pieces(peer3, picked, 1, false, 0, piece_picker::fast, true);
TEST_CHECK(int(picked.size()) == 1);
TEST_CHECK(picked.front().piece_index == 1);
// and the block picked should not be 0 or 2
// since we already have those blocks
TEST_CHECK(picked.front().block_index != 0);
TEST_CHECK(picked.front().block_index != 2);
// now, if we mark piece 1 and block 0 in piece 2
// as being downloaded and picks a block from peer1,
// it should pick a block from piece 2. But since
// block 0 is marked as requested from another peer,
// the piece_picker will continue to pick blocks
// until it can return at least 1 block (since we
// tell it we want one block) that is not being
// downloaded from anyone else. This is to make it
// possible for us to determine if we want to request
// the block from more than one peer.
// Both piece 1 and 2 are partial pieces, but pice
// 2 is the rarest, so that's why it is picked.
// we have block 0 and 2 already, so we can't mark
// them as begin downloaded.
p.mark_as_downloading(piece_block(1, 1), &peer_struct, piece_picker::fast);
p.mark_as_downloading(piece_block(1, 3), &peer_struct, piece_picker::fast);
p.mark_as_downloading(piece_block(2, 0), &peer_struct, piece_picker::fast);
std::vector<piece_picker::downloading_piece> const& downloads = p.get_download_queue();
TEST_CHECK(downloads.size() == 2);
TEST_CHECK(downloads[0].index == 1);
TEST_CHECK(downloads[0].info[0].state == piece_picker::block_info::state_finished);
TEST_CHECK(downloads[0].info[1].state == piece_picker::block_info::state_requested);
TEST_CHECK(downloads[0].info[2].state == piece_picker::block_info::state_finished);
TEST_CHECK(downloads[0].info[3].state == piece_picker::block_info::state_requested);
TEST_CHECK(downloads[1].index == 2);
TEST_CHECK(downloads[1].info[0].state == piece_picker::block_info::state_requested);
TEST_CHECK(downloads[1].info[1].state == piece_picker::block_info::state_none);
TEST_CHECK(downloads[1].info[2].state == piece_picker::block_info::state_none);
TEST_CHECK(downloads[1].info[3].state == piece_picker::block_info::state_none);
TEST_CHECK(p.is_requested(piece_block(1, 1)));
TEST_CHECK(p.is_requested(piece_block(1, 3)));
TEST_CHECK(p.is_requested(piece_block(2, 0)));
TEST_CHECK(!p.is_requested(piece_block(2, 1)));
picked.clear();
p.pick_pieces(peer1, picked, 1, false, 0, piece_picker::fast, true);
TEST_CHECK(int(picked.size()) == 2);
piece_block expected3[] = { piece_block(2, 0), piece_block(2, 1) };
TEST_CHECK(std::equal(picked.begin()
, picked.end(), expected3));
// now, if we assume we're downloading at such a speed that
// we might prefer to download whole pieces at a time from
// this peer. It should not pick piece 1 or 2 (since those are
// partially selected)
picked.clear();
p.pick_pieces(peer1, picked, 1, true, 0, piece_picker::fast, true);
// it will pick 4 blocks, since we said we
// wanted whole pieces.
TEST_CHECK(int(picked.size()) == 4);
piece_block expected4[] =
{
piece_block(3, 0), piece_block(3, 1)
, piece_block(3, 2), piece_block(3, 3)
};
TEST_CHECK(std::equal(picked.begin()
, picked.end(), expected4));
// now, try the same thing, but pick as many pieces as possible
// to make sure it can still fall back on partial pieces
picked.clear();
p.pick_pieces(peer1, picked, 100, true, 0, piece_picker::fast, true);
TEST_CHECK(int(picked.size()) == 12);
piece_block expected5[] =
{
piece_block(3, 0), piece_block(3, 1)
, piece_block(3, 2), piece_block(3, 3)
, piece_block(5, 0), piece_block(5, 1)
, piece_block(5, 2), piece_block(5, 3)
, piece_block(2, 0), piece_block(2, 1)
, piece_block(2, 2), piece_block(2, 3)
};
TEST_CHECK(std::equal(picked.begin()
, picked.end(), expected5));
// now, try the same thing, but pick as many pieces as possible
// to make sure it can still fall back on partial pieces
picked.clear();
p.pick_pieces(peer1, picked, 100, true, &peer_struct, piece_picker::fast, true);
TEST_CHECK(int(picked.size()) == 11);
piece_block expected6[] =
{
piece_block(2, 1), piece_block(2, 2)
, piece_block(2, 3)
, piece_block(3, 0), piece_block(3, 1)
, piece_block(3, 2), piece_block(3, 3)
, piece_block(5, 0), piece_block(5, 1)
, piece_block(5, 2), piece_block(5, 3)
};
TEST_CHECK(std::equal(picked.begin()
, picked.end(), expected6));
// make sure the piece picker allows filtered pieces
// to become available
p.mark_as_finished(piece_block(4, 2), 0);
*/
return 0;
}