mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-05 17:52:29 +00:00
Related refactoring to updated of ThrottleList to use new Scheduler.
This commit is contained in:
+4
-2
@@ -71,8 +71,6 @@ AC_DEFINE(HAVE_CONFIG_H, 1, true if config.h was included)
|
||||
AC_DEFINE(USER_AGENT, [std::string(PACKAGE "/" VERSION "/") + torrent::version()], Http user agent)
|
||||
|
||||
AC_CHECK_FUNCS(posix_memalign)
|
||||
TORRENT_CHECK_CACHELINE()
|
||||
TORRENT_CHECK_POPCOUNT()
|
||||
|
||||
CC_ATTRIBUTE_UNUSED(
|
||||
AC_DEFINE([__UNUSED], [__attribute__((unused))], [Wrapper around unused attribute]),
|
||||
@@ -85,10 +83,14 @@ LIBS="$PTHREAD_LIBS $CURSES_LIB $CURSES_LIBS $LIBCURL $LIBCURL_LIBS $DEPENDENCIE
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
|
||||
|
||||
TORRENT_CHECK_CACHELINE()
|
||||
TORRENT_CHECK_POPCOUNT()
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
doc/Makefile
|
||||
src/Makefile
|
||||
test/Makefile
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
+28
-35
@@ -51,15 +51,15 @@ Manager::push_log(const char* msg) {
|
||||
}
|
||||
|
||||
Manager::Manager() :
|
||||
m_hashingView(NULL),
|
||||
m_log_important(torrent::log_open_log_buffer("important")),
|
||||
m_log_complete(torrent::log_open_log_buffer("complete"))
|
||||
{
|
||||
m_downloadStore = new DownloadStore();
|
||||
m_downloadList = new DownloadList();
|
||||
m_fileStatusCache = new FileStatusCache();
|
||||
m_httpQueue = new HttpQueue();
|
||||
m_httpStack = new CurlStack();
|
||||
m_hashingView(nullptr),
|
||||
m_log_important(torrent::log_open_log_buffer("important")),
|
||||
m_log_complete(torrent::log_open_log_buffer("complete")) {
|
||||
|
||||
m_download_store = std::make_unique<DownloadStore>();
|
||||
m_download_list = std::make_unique<DownloadList>();
|
||||
m_file_status_cache = std::make_unique<FileStatusCache>();
|
||||
m_http_queue = std::make_unique<HttpQueue>();
|
||||
m_http_stack = std::make_unique<CurlStack>();
|
||||
|
||||
torrent::Throttle* unthrottled = torrent::Throttle::create_throttle();
|
||||
unthrottled->set_max_rate(0);
|
||||
@@ -68,19 +68,12 @@ Manager::Manager() :
|
||||
|
||||
Manager::~Manager() {
|
||||
torrent::Throttle::destroy_throttle(m_throttles["NULL"].first);
|
||||
delete m_downloadList;
|
||||
|
||||
// TODO: Clean up logs objects.
|
||||
|
||||
delete m_downloadStore;
|
||||
delete m_httpQueue;
|
||||
delete m_fileStatusCache;
|
||||
}
|
||||
|
||||
void
|
||||
Manager::set_hashing_view(View* v) {
|
||||
if (v == NULL || m_hashingView != NULL)
|
||||
throw torrent::internal_error("Manager::set_hashing_view(...) received NULL or is already set.");
|
||||
if (v == nullptr || m_hashingView != nullptr)
|
||||
throw torrent::internal_error("Manager::set_hashing_view(...) received nullptr or is already set.");
|
||||
|
||||
m_hashingView = v;
|
||||
m_hashingView->signal_changed().push_back(std::bind(&Manager::receive_hashing_changed, this));
|
||||
@@ -89,12 +82,12 @@ Manager::set_hashing_view(View* v) {
|
||||
torrent::ThrottlePair
|
||||
Manager::get_throttle(const std::string& name) {
|
||||
ThrottleMap::const_iterator itr = m_throttles.find(name);
|
||||
torrent::ThrottlePair throttles = (itr == m_throttles.end() ? torrent::ThrottlePair(NULL, NULL) : itr->second);
|
||||
torrent::ThrottlePair throttles = (itr == m_throttles.end() ? torrent::ThrottlePair(nullptr, nullptr) : itr->second);
|
||||
|
||||
if (throttles.first == NULL)
|
||||
if (throttles.first == nullptr)
|
||||
throttles.first = torrent::up_throttle_global();
|
||||
|
||||
if (throttles.second == NULL)
|
||||
if (throttles.second == nullptr)
|
||||
throttles.second = torrent::down_throttle_global();
|
||||
|
||||
return throttles;
|
||||
@@ -108,7 +101,7 @@ Manager::set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePai
|
||||
|
||||
torrent::ThrottlePair
|
||||
Manager::get_address_throttle(const sockaddr* addr) {
|
||||
return m_addressThrottles.get(rak::socket_address::cast_from(addr)->sa_inet()->address_h(), torrent::ThrottlePair(NULL, NULL));
|
||||
return m_addressThrottles.get(rak::socket_address::cast_from(addr)->sa_inet()->address_h(), torrent::ThrottlePair(nullptr, nullptr));
|
||||
}
|
||||
|
||||
int64_t
|
||||
@@ -121,7 +114,7 @@ Manager::retrieve_throttle_value(const torrent::Object::string_type& name, bool
|
||||
torrent::Throttle* throttle = up ? itr->second.first : itr->second.second;
|
||||
|
||||
// check whether the actual up/down throttle exist (one of the pair can be missing)
|
||||
if (throttle == NULL)
|
||||
if (throttle == nullptr)
|
||||
return (int64_t)-1;
|
||||
|
||||
int64_t throttle_max = (int64_t)throttle->max_rate();
|
||||
@@ -143,36 +136,36 @@ Manager::retrieve_throttle_value(const torrent::Object::string_type& name, bool
|
||||
// Most of this should be possible to move out.
|
||||
void
|
||||
Manager::initialize_second() {
|
||||
torrent::Http::slot_factory() = std::bind(&CurlStack::new_object, m_httpStack);
|
||||
m_httpQueue->set_slot_factory(std::bind(&CurlStack::new_object, m_httpStack));
|
||||
torrent::Http::slot_factory() = std::bind(&CurlStack::new_object, m_http_stack.get());
|
||||
m_http_queue->set_slot_factory(std::bind(&CurlStack::new_object, m_http_stack.get()));
|
||||
|
||||
CurlStack::global_init();
|
||||
}
|
||||
|
||||
void
|
||||
Manager::cleanup() {
|
||||
m_httpStack->shutdown();
|
||||
m_http_stack->shutdown();
|
||||
|
||||
// Need to disconnect log signals? Not really since we won't receive
|
||||
// any more.
|
||||
|
||||
m_downloadList->clear();
|
||||
m_download_list->clear();
|
||||
|
||||
// When we implement asynchronous DNS lookups, we need to cancel them
|
||||
// here before the torrent::* objects are deleted.
|
||||
|
||||
torrent::cleanup();
|
||||
|
||||
delete m_httpStack;
|
||||
m_http_stack.reset();
|
||||
CurlStack::global_cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
Manager::shutdown(bool force) {
|
||||
if (!force)
|
||||
std::for_each(m_downloadList->begin(), m_downloadList->end(), [this](Download* d) { m_downloadList->pause_default(d); });
|
||||
std::for_each(m_download_list->begin(), m_download_list->end(), [this](Download* d) { m_download_list->pause_default(d); });
|
||||
else
|
||||
std::for_each(m_downloadList->begin(), m_downloadList->end(), [this](Download* d) { m_downloadList->close_quick(d); });
|
||||
std::for_each(m_download_list->begin(), m_download_list->end(), [this](Download* d) { m_download_list->close_quick(d); });
|
||||
}
|
||||
|
||||
void
|
||||
@@ -226,7 +219,7 @@ Manager::set_bind_address(const std::string& addr) {
|
||||
if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0 &&
|
||||
(err = rak::address_info::get_address_info(addr.c_str(), PF_INET6, SOCK_STREAM, &ai)) != 0)
|
||||
throw torrent::input_error("Could not set bind address: " + std::string(rak::address_info::strerror(err)) + ".");
|
||||
|
||||
|
||||
try {
|
||||
|
||||
if (torrent::connection_manager()->listen_port() != 0) {
|
||||
@@ -238,7 +231,7 @@ Manager::set_bind_address(const std::string& addr) {
|
||||
torrent::connection_manager()->set_bind_address(ai->address()->c_sockaddr());
|
||||
}
|
||||
|
||||
m_httpStack->set_bind_address(!ai->address()->is_address_any() ? ai->address()->address_str() : std::string());
|
||||
m_http_stack->set_bind_address(!ai->address()->is_address_any() ? ai->address()->address_str() : std::string());
|
||||
|
||||
rak::address_info::free_address_info(ai);
|
||||
|
||||
@@ -477,13 +470,13 @@ void
|
||||
Manager::receive_hashing_changed() {
|
||||
bool foundHashing = std::find_if(m_hashingView->begin_visible(), m_hashingView->end_visible(),
|
||||
std::mem_fn(&Download::is_hash_checking)) != m_hashingView->end_visible();
|
||||
|
||||
|
||||
// Try quick hashing all those with hashing == initial, set them to
|
||||
// something else when failed.
|
||||
for (View::iterator itr = m_hashingView->begin_visible(), last = m_hashingView->end_visible(); itr != last; ++itr) {
|
||||
if ((*itr)->is_hash_checked())
|
||||
throw torrent::internal_error("core::Manager::receive_hashing_changed() (*itr)->is_hash_checked().");
|
||||
|
||||
|
||||
if ((*itr)->is_hash_checking() || (*itr)->is_hash_failed())
|
||||
continue;
|
||||
|
||||
@@ -495,7 +488,7 @@ Manager::receive_hashing_changed() {
|
||||
continue;
|
||||
|
||||
try {
|
||||
m_downloadList->open_throw(*itr);
|
||||
m_download_list->open_throw(*itr);
|
||||
|
||||
// Since the bitfield is allocated on loading of resume load or
|
||||
// hash start, and unallocated on close, we know that if it it
|
||||
|
||||
+10
-14
@@ -4,7 +4,6 @@
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <torrent/utils/log_buffer.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/object.h>
|
||||
@@ -35,18 +34,15 @@ public:
|
||||
typedef DownloadList::iterator DListItr;
|
||||
typedef utils::FileStatusCache FileStatusCache;
|
||||
|
||||
// typedef std::function<void (DownloadList::iterator)> slot_ready;
|
||||
// typedef std::function<void ()> slot_void;
|
||||
|
||||
Manager();
|
||||
~Manager();
|
||||
|
||||
DownloadList* download_list() { return m_downloadList; }
|
||||
DownloadStore* download_store() { return m_downloadStore; }
|
||||
FileStatusCache* file_status_cache() { return m_fileStatusCache; }
|
||||
DownloadList* download_list() { return m_download_list.get(); }
|
||||
DownloadStore* download_store() { return m_download_store.get(); }
|
||||
FileStatusCache* file_status_cache() { return m_file_status_cache.get(); }
|
||||
|
||||
HttpQueue* http_queue() { return m_httpQueue; }
|
||||
CurlStack* http_stack() { return m_httpStack; }
|
||||
HttpQueue* http_queue() { return m_http_queue.get(); }
|
||||
CurlStack* http_stack() { return m_http_stack.get(); }
|
||||
|
||||
View* hashing_view() { return m_hashingView; }
|
||||
void set_hashing_view(View* v);
|
||||
@@ -109,11 +105,11 @@ private:
|
||||
void receive_http_failed(std::string msg);
|
||||
void receive_hashing_changed();
|
||||
|
||||
DownloadList* m_downloadList;
|
||||
DownloadStore* m_downloadStore;
|
||||
FileStatusCache* m_fileStatusCache;
|
||||
HttpQueue* m_httpQueue;
|
||||
CurlStack* m_httpStack;
|
||||
std::unique_ptr<DownloadList> m_download_list;
|
||||
std::unique_ptr<DownloadStore> m_download_store;
|
||||
std::unique_ptr<FileStatusCache> m_file_status_cache;
|
||||
std::unique_ptr<HttpQueue> m_http_queue;
|
||||
std::unique_ptr<CurlStack> m_http_stack;
|
||||
|
||||
View* m_hashingView;
|
||||
|
||||
|
||||
+3
-3
@@ -159,7 +159,9 @@ main(int argc, char** argv) {
|
||||
srandom(random_seed);
|
||||
srand48(random_seed);
|
||||
|
||||
// Initialize logging:
|
||||
torrent::Poll::slot_create_poll() = [](){ return create_poll(); };
|
||||
|
||||
torrent::initialize_main_thread();
|
||||
torrent::log_initialize();
|
||||
|
||||
control = new Control;
|
||||
@@ -188,8 +190,6 @@ main(int argc, char** argv) {
|
||||
torrent::log_add_group_output(torrent::LOG_NOTICE, "important");
|
||||
torrent::log_add_group_output(torrent::LOG_INFO, "complete");
|
||||
|
||||
torrent::Poll::slot_create_poll() = [](){ return create_poll(); };
|
||||
|
||||
torrent::initialize();
|
||||
torrent::set_main_thread_slots(std::bind(&client_perform));
|
||||
|
||||
|
||||
+24
-17
@@ -14,33 +14,40 @@ rtorrent_Test_Common = \
|
||||
main.cc \
|
||||
\
|
||||
helpers/assert.h \
|
||||
helpers/mock_compare.h \
|
||||
helpers/mock_function.cc \
|
||||
helpers/mock_function.h \
|
||||
helpers/progress_listener.cc \
|
||||
helpers/progress_listener.h \
|
||||
helpers/protectors.cc \
|
||||
helpers/protectors.h \
|
||||
helpers/test_fixture.cc \
|
||||
helpers/test_fixture.h \
|
||||
helpers/test_main_thread.cc \
|
||||
helpers/test_main_thread.h \
|
||||
helpers/test_thread.cc \
|
||||
helpers/test_thread.h \
|
||||
helpers/utils.h
|
||||
|
||||
rtorrent_Test_Rpc_SOURCES = $(rtorrent_Test_Common) \
|
||||
rpc/command_test.cc \
|
||||
rpc/command_test.h \
|
||||
rpc/command_map_test.cc \
|
||||
rpc/command_map_test.h \
|
||||
rpc/jsonrpc_test.cc \
|
||||
rpc/jsonrpc_test.h \
|
||||
rpc/xmlrpc_test.cc \
|
||||
rpc/xmlrpc_test.h \
|
||||
rpc/command_slot_test.cc \
|
||||
rpc/command_slot_test.h \
|
||||
rpc/object_storage_test.cc \
|
||||
rpc/object_storage_test.h \
|
||||
rpc/test_command.cc \
|
||||
rpc/test_command.h \
|
||||
rpc/test_command_map.cc \
|
||||
rpc/test_command_map.h \
|
||||
rpc/test_jsonrpc.cc \
|
||||
rpc/test_jsonrpc.h \
|
||||
rpc/test_xmlrpc.cc \
|
||||
rpc/test_xmlrpc.h \
|
||||
rpc/test_command_slot.cc \
|
||||
rpc/test_command_slot.h \
|
||||
rpc/test_object_storage.cc \
|
||||
rpc/test_object_storage.h \
|
||||
rpc/test_parse_options.cc \
|
||||
rpc/test_parse_options.h \
|
||||
src/command_dynamic_test.cc \
|
||||
src/command_dynamic_test.h
|
||||
rpc/test_parse_options.h
|
||||
|
||||
rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
|
||||
src/command_dynamic_test.cc \
|
||||
src/command_dynamic_test.h
|
||||
src/test_command_dynamic.cc \
|
||||
src/test_command_dynamic.h
|
||||
|
||||
rtorrent_Test_Rpc_CXXFLAGS = $(CPPUNIT_CFLAGS)
|
||||
rtorrent_Test_Rpc_LDFLAGS = $(CPPUNIT_LIBS) -ldl
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#ifndef LIBTORRENT_HELPERS_MOCK_COMPARE_H
|
||||
#define LIBTORRENT_HELPERS_MOCK_COMPARE_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <torrent/event.h>
|
||||
#include <torrent/net/socket_address.h>
|
||||
|
||||
// Compare arguments to mock functions with what is expected. The lhs
|
||||
// are the expected arguments, rhs are the ones called with.
|
||||
|
||||
template <typename Arg>
|
||||
inline bool mock_compare_arg(Arg lhs, Arg rhs) { return lhs == rhs; }
|
||||
|
||||
template <int I, typename A, typename... Args>
|
||||
typename std::enable_if<I == 1, int>::type
|
||||
mock_compare_tuple(const std::tuple<A, Args...>& lhs, const std::tuple<Args...>& rhs) {
|
||||
return mock_compare_arg(std::get<I>(lhs), std::get<I - 1>(rhs)) ? 0 : 1;
|
||||
}
|
||||
|
||||
template <int I, typename A, typename... Args>
|
||||
typename std::enable_if<1 < I, int>::type
|
||||
mock_compare_tuple(const std::tuple<A, Args...>& lhs, const std::tuple<Args...>& rhs) {
|
||||
auto res = mock_compare_tuple<I - 1>(lhs, rhs);
|
||||
|
||||
if (res != 0)
|
||||
return res;
|
||||
|
||||
return mock_compare_arg(std::get<I>(lhs), std::get<I - 1>(rhs)) ? 0 : I;
|
||||
}
|
||||
|
||||
//template <typename T, typename std::enable_if<!std::is_const<T>::value, int>::type = 0>
|
||||
template <typename T>
|
||||
struct mock_compare_map {
|
||||
typedef std::map<const T*, const T*> values_type;
|
||||
|
||||
static T* begin_pointer() { return reinterpret_cast<T*>(0x1000); }
|
||||
static T* end_pointer() { return reinterpret_cast<T*>(0x2000); }
|
||||
|
||||
static bool is_key(const T* k) {
|
||||
return k >= begin_pointer() && k < end_pointer();
|
||||
}
|
||||
|
||||
static bool has_key(const T* k) {
|
||||
return values.find(k) != values.end();
|
||||
}
|
||||
|
||||
static bool has_value(const T* v) {
|
||||
return std::find_if(values.begin(), values.end(), [v](typename values_type::value_type& kv) { return v == kv.second; }) != values.end();
|
||||
}
|
||||
|
||||
static const T* get(const T* k) {
|
||||
auto itr = values.find(k);
|
||||
CPPUNIT_ASSERT_MESSAGE("mock_compare_map get failed, not inserted", itr != values.end());
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
static values_type values;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
typename mock_compare_map<T>::values_type mock_compare_map<T>::values;
|
||||
|
||||
template<typename T>
|
||||
void mock_compare_add(T* v) {
|
||||
mock_compare_map<T>::add_value(v);
|
||||
}
|
||||
|
||||
//
|
||||
// Specialize:
|
||||
//
|
||||
|
||||
template <>
|
||||
inline bool mock_compare_arg<sockaddr*>(sockaddr* lhs, sockaddr* rhs) {
|
||||
return lhs != nullptr && rhs != nullptr && torrent::sa_equal(lhs, rhs);
|
||||
}
|
||||
template <>
|
||||
inline bool mock_compare_arg<const sockaddr*>(const sockaddr* lhs, const sockaddr* rhs) {
|
||||
return lhs != nullptr && rhs != nullptr && torrent::sa_equal(lhs, rhs);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool mock_compare_arg<torrent::Event*>(torrent::Event* lhs, torrent::Event* rhs) {
|
||||
if (mock_compare_map<torrent::Event>::is_key(lhs)) {
|
||||
if (!mock_compare_map<torrent::Event>::has_value(rhs)) {
|
||||
mock_compare_map<torrent::Event>::values[lhs] = rhs;
|
||||
return true;
|
||||
}
|
||||
|
||||
return mock_compare_map<torrent::Event>::has_key(lhs) && mock_compare_map<torrent::Event>::get(lhs) == rhs;
|
||||
}
|
||||
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,182 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test/helpers/mock_function.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <torrent/event.h>
|
||||
#include <torrent/net/socket_address.h>
|
||||
#include <torrent/net/fd.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/random.h>
|
||||
|
||||
#define MOCK_CLEANUP_MAP(MOCK_FUNC) \
|
||||
CPPUNIT_ASSERT_MESSAGE("expected mock function calls not completed for '" #MOCK_FUNC "'", mock_cleanup_map(&MOCK_FUNC) || ignore_assert);
|
||||
#define MOCK_LOG(log_fmt, ...) \
|
||||
lt_log_print(torrent::LOG_MOCK_CALLS, "%s: " log_fmt, __func__, __VA_ARGS__);
|
||||
|
||||
void
|
||||
mock_clear(bool ignore_assert) {
|
||||
MOCK_CLEANUP_MAP(torrent::fd__accept);
|
||||
MOCK_CLEANUP_MAP(torrent::fd__bind);
|
||||
MOCK_CLEANUP_MAP(torrent::fd__close);
|
||||
MOCK_CLEANUP_MAP(torrent::fd__connect);
|
||||
MOCK_CLEANUP_MAP(torrent::fd__fcntl_int);
|
||||
MOCK_CLEANUP_MAP(torrent::fd__listen);
|
||||
MOCK_CLEANUP_MAP(torrent::fd__setsockopt_int);
|
||||
MOCK_CLEANUP_MAP(torrent::fd__socket);
|
||||
|
||||
MOCK_CLEANUP_MAP(torrent::poll_event_open);
|
||||
MOCK_CLEANUP_MAP(torrent::poll_event_close);
|
||||
MOCK_CLEANUP_MAP(torrent::poll_event_closed);
|
||||
MOCK_CLEANUP_MAP(torrent::poll_event_insert_read);
|
||||
MOCK_CLEANUP_MAP(torrent::poll_event_insert_write);
|
||||
MOCK_CLEANUP_MAP(torrent::poll_event_insert_error);
|
||||
MOCK_CLEANUP_MAP(torrent::poll_event_remove_read);
|
||||
MOCK_CLEANUP_MAP(torrent::poll_event_remove_write);
|
||||
MOCK_CLEANUP_MAP(torrent::poll_event_remove_error);
|
||||
|
||||
MOCK_CLEANUP_MAP(torrent::random_uniform_uint16);
|
||||
MOCK_CLEANUP_MAP(torrent::random_uniform_uint32);
|
||||
|
||||
mock_compare_map<torrent::Event>::values.clear();
|
||||
};
|
||||
|
||||
void
|
||||
mock_init() {
|
||||
log_add_group_output(torrent::LOG_MOCK_CALLS, "test_output");
|
||||
mock_clear(true);
|
||||
}
|
||||
|
||||
void
|
||||
mock_cleanup() {
|
||||
mock_clear(false);
|
||||
}
|
||||
|
||||
void
|
||||
mock_redirect_defaults([[maybe_unused]] mock_redirect_flags flags) {
|
||||
mock_redirect(torrent::fd__close, std::function<int(int fildes)>([](int fildes) { return ::close(fildes); }));
|
||||
mock_redirect(torrent::fd__fcntl_int, std::function<int(int fildes, int cmd, int arg)>([](int fildes, int cmd, int arg) { return ::fcntl(fildes, cmd, arg); }));
|
||||
mock_redirect(torrent::fd__setsockopt_int, std::function<int(int socket, int level, int option_name, int option_value)>([](int socket, int level, int option_name, int option_value) { return ::setsockopt(socket, level, option_name, &option_value, sizeof(int)); }));
|
||||
mock_redirect(torrent::fd__socket, std::function<int(int domain, int type, int protocol)>([](int domain, int type, int protocol) { return ::socket(domain, type, protocol); }));
|
||||
}
|
||||
|
||||
namespace torrent {
|
||||
|
||||
//
|
||||
// Mock functions for 'torrent/net/fd.h':
|
||||
//
|
||||
|
||||
int fd__accept(int socket, sockaddr *address, socklen_t *address_len) {
|
||||
MOCK_LOG("entry socket:%i address:%s address_len:%u",
|
||||
socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)(*address_len));
|
||||
auto ret = mock_call<int>(__func__, &torrent::fd__accept, socket, address, address_len);
|
||||
MOCK_LOG("exit socket:%i address:%s address_len:%u",
|
||||
socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)(*address_len));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fd__bind(int socket, const sockaddr *address, socklen_t address_len) {
|
||||
MOCK_LOG("socket:%i address:%s address_len:%u",
|
||||
socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)address_len);
|
||||
return mock_call<int>(__func__, &torrent::fd__bind, socket, address, address_len);
|
||||
}
|
||||
|
||||
int fd__close(int fildes) {
|
||||
MOCK_LOG("filedes:%i", fildes);
|
||||
return mock_call<int>(__func__, &torrent::fd__close, fildes);
|
||||
}
|
||||
|
||||
int fd__connect(int socket, const sockaddr *address, socklen_t address_len) {
|
||||
MOCK_LOG("socket:%i address:%s address_len:%u",
|
||||
socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)address_len);
|
||||
return mock_call<int>(__func__, &torrent::fd__connect, socket, address, address_len);
|
||||
}
|
||||
|
||||
int fd__fcntl_int(int fildes, int cmd, int arg) {
|
||||
MOCK_LOG("filedes:%i cmd:%i arg:%i", fildes, cmd, arg);
|
||||
return mock_call<int>(__func__, &torrent::fd__fcntl_int, fildes, cmd, arg);
|
||||
}
|
||||
|
||||
int fd__listen(int socket, int backlog) {
|
||||
MOCK_LOG("socket:%i backlog:%i", socket, backlog);
|
||||
return mock_call<int>(__func__, &torrent::fd__listen, socket, backlog);
|
||||
}
|
||||
|
||||
int fd__setsockopt_int(int socket, int level, int option_name, int option_value) {
|
||||
MOCK_LOG("socket:%i level:%i option_name:%i option_value:%i",
|
||||
socket, level, option_name, option_value);
|
||||
return mock_call<int>(__func__, &torrent::fd__setsockopt_int, socket, level, option_name, option_value);
|
||||
}
|
||||
|
||||
int fd__socket(int domain, int type, int protocol) {
|
||||
MOCK_LOG("domain:%i type:%i protocol:%i", domain, type, protocol);
|
||||
return mock_call<int>(__func__, &torrent::fd__socket, domain, type, protocol);
|
||||
}
|
||||
|
||||
//
|
||||
// Mock functions for 'torrent/event.h':
|
||||
//
|
||||
|
||||
void poll_event_open(Event* event) {
|
||||
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
|
||||
return mock_call<void>(__func__, &torrent::poll_event_open, event);
|
||||
}
|
||||
|
||||
void poll_event_close(Event* event) {
|
||||
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
|
||||
return mock_call<void>(__func__, &torrent::poll_event_close, event);
|
||||
}
|
||||
|
||||
void poll_event_closed(Event* event) {
|
||||
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
|
||||
return mock_call<void>(__func__, &torrent::poll_event_closed, event);
|
||||
}
|
||||
|
||||
void poll_event_insert_read(Event* event) {
|
||||
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
|
||||
return mock_call<void>(__func__, &torrent::poll_event_insert_read, event);
|
||||
}
|
||||
|
||||
void poll_event_insert_write(Event* event) {
|
||||
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
|
||||
return mock_call<void>(__func__, &torrent::poll_event_insert_write, event);
|
||||
}
|
||||
|
||||
void poll_event_insert_error(Event* event) {
|
||||
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
|
||||
return mock_call<void>(__func__, &torrent::poll_event_insert_error, event);
|
||||
}
|
||||
|
||||
void poll_event_remove_read(Event* event) {
|
||||
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
|
||||
return mock_call<void>(__func__, &torrent::poll_event_remove_read, event);
|
||||
}
|
||||
|
||||
void poll_event_remove_write(Event* event) {
|
||||
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
|
||||
return mock_call<void>(__func__, &torrent::poll_event_remove_write, event);
|
||||
}
|
||||
|
||||
void poll_event_remove_error(Event* event) {
|
||||
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
|
||||
return mock_call<void>(__func__, &torrent::poll_event_remove_error, event);
|
||||
}
|
||||
|
||||
//
|
||||
// Mock functions for 'torrent/utils/random.h':
|
||||
//
|
||||
|
||||
uint16_t random_uniform_uint16(uint16_t min, uint16_t max) {
|
||||
MOCK_LOG("min:%" PRIu16 " max:%" PRIu16, min, max);
|
||||
return mock_call<uint16_t>(__func__, &torrent::random_uniform_uint16, min, max);
|
||||
}
|
||||
|
||||
uint32_t random_uniform_uint32(uint32_t min, uint32_t max) {
|
||||
MOCK_LOG("min:%" PRIu32 " max:%" PRIu32, min, max);
|
||||
return mock_call<uint32_t>(__func__, &torrent::random_uniform_uint32, min, max);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
#ifndef LIBTORRENT_HELPERS_MOCK_FUNCTION_H
|
||||
#define LIBTORRENT_HELPERS_MOCK_FUNCTION_H
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
#include "test/helpers/mock_compare.h"
|
||||
|
||||
namespace torrent {
|
||||
extern int fd__accept(int socket, sockaddr *address, socklen_t *address_len);
|
||||
extern int fd__bind(int socket, const sockaddr *address, socklen_t address_len);
|
||||
extern int fd__close(int fildes);
|
||||
extern int fd__connect(int socket, const sockaddr *address, socklen_t address_len);
|
||||
extern int fd__fcntl_int(int fildes, int cmd, int arg);
|
||||
extern int fd__listen(int socket, int backlog);
|
||||
extern int fd__setsockopt_int(int socket, int level, int option_name, int option_value);
|
||||
extern int fd__socket(int domain, int type, int protocol);
|
||||
}
|
||||
|
||||
enum mock_redirect_flags {
|
||||
mock_redirect_all = ~0,
|
||||
};
|
||||
|
||||
void mock_init();
|
||||
void mock_cleanup();
|
||||
void mock_redirect_defaults(mock_redirect_flags flags = mock_redirect_all);
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct mock_function_map {
|
||||
typedef std::tuple<R, Args...> call_type;
|
||||
typedef std::vector<call_type> call_list_type;
|
||||
typedef std::map<void*, call_list_type> func_map_type;
|
||||
|
||||
typedef std::function<R (Args...)> function_type;
|
||||
typedef std::map<void*, function_type> redirect_map_type;
|
||||
|
||||
static std::mutex mutex;
|
||||
static func_map_type functions;
|
||||
static redirect_map_type redirects;
|
||||
|
||||
static bool cleanup(void* fn) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
redirects.erase(fn);
|
||||
return functions.erase(fn) == 0;
|
||||
}
|
||||
|
||||
static R ret_erase(void* fn) {
|
||||
auto itr = functions.find(fn);
|
||||
auto ret = std::get<0>(itr->second.front());
|
||||
itr->second.erase(itr->second.begin());
|
||||
|
||||
if (itr->second.empty())
|
||||
functions.erase(itr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
std::mutex mock_function_map<R, Args...>::mutex;
|
||||
template<typename R, typename... Args>
|
||||
typename mock_function_map<R, Args...>::func_map_type mock_function_map<R, Args...>::functions;
|
||||
template<typename R, typename... Args>
|
||||
typename mock_function_map<R, Args...>::redirect_map_type mock_function_map<R, Args...>::redirects;
|
||||
|
||||
struct mock_void {};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct mock_function_type {
|
||||
typedef mock_function_map<R, Args...> type;
|
||||
|
||||
static int compare_expected(typename type::call_type lhs, Args... rhs) {
|
||||
return mock_compare_tuple<sizeof...(Args)>(lhs, std::make_tuple(rhs...));
|
||||
}
|
||||
|
||||
static R ret_erase(void* fn) { return type::ret_erase(fn); }
|
||||
|
||||
static bool has_redirect(void* fn) {
|
||||
std::lock_guard<std::mutex> lock(type::mutex);
|
||||
return type::redirects.find(fn) != type::redirects.end();
|
||||
}
|
||||
|
||||
static R call_redirect(void* fn, Args... args) {
|
||||
std::lock_guard<std::mutex> lock(type::mutex);
|
||||
return type::redirects.find(fn)->second(args...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
struct mock_function_type<void, Args...> {
|
||||
typedef mock_function_map<mock_void, Args...> type;
|
||||
|
||||
static int compare_expected(typename type::call_type lhs, Args... rhs) {
|
||||
return mock_compare_tuple<sizeof...(Args)>(lhs, std::make_tuple(rhs...));
|
||||
}
|
||||
|
||||
static void ret_erase(void* fn) { type::ret_erase(fn); }
|
||||
|
||||
static bool has_redirect(void* fn) {
|
||||
std::lock_guard<std::mutex> lock(type::mutex);
|
||||
return type::redirects.find(fn) != type::redirects.end();
|
||||
}
|
||||
|
||||
static void call_redirect(void* fn, Args... args) {
|
||||
std::lock_guard<std::mutex> lock(type::mutex);
|
||||
type::redirects.find(fn)->second(args...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
bool
|
||||
mock_cleanup_map(R fn[[gnu::unused]](Args...)) {
|
||||
return mock_function_type<R, Args...>::type::cleanup(reinterpret_cast<void*>(fn));
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
void
|
||||
mock_expect(R fn(Args...), R ret, Args... args) {
|
||||
typedef mock_function_map<R, Args...> mock_map;
|
||||
std::lock_guard<std::mutex> lock(mock_map::mutex);
|
||||
mock_map::functions[reinterpret_cast<void*>(fn)].push_back(std::tuple<R, Args...>(ret, args...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void
|
||||
mock_expect(void fn(Args...), Args... args) {
|
||||
typedef mock_function_map<mock_void, Args...> mock_map;
|
||||
std::lock_guard<std::mutex> lock(mock_map::mutex);
|
||||
mock_map::functions[reinterpret_cast<void*>(fn)].push_back(std::tuple<mock_void, Args...>(mock_void(), args...));
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
void
|
||||
mock_redirect(R fn(Args...), std::function<R (Args...)> func) {
|
||||
typedef mock_function_map<R, Args...> mock_map;
|
||||
std::lock_guard<std::mutex> lock(mock_map::mutex);
|
||||
mock_map::redirects[reinterpret_cast<void*>(fn)] = func;
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
auto
|
||||
mock_call_direct(std::string name, R fn(Args...), Args... args) -> decltype(fn(args...)) {
|
||||
typedef mock_function_type<R, Args...> mock_type;
|
||||
|
||||
std::lock_guard<std::mutex> lock(mock_type::type::mutex);
|
||||
|
||||
auto itr = mock_type::type::functions.find(reinterpret_cast<void*>(fn));
|
||||
CPPUNIT_ASSERT_MESSAGE(("mock_call expected function calls exhausted by '" + name + "'").c_str(),
|
||||
itr != mock_type::type::functions.end());
|
||||
|
||||
auto mismatch_arg = mock_type::compare_expected(itr->second.front(), args...);
|
||||
CPPUNIT_ASSERT_MESSAGE(("mock_call expected function call argument " + std::to_string(mismatch_arg) + " mismatch for '" + name + "'").c_str(),
|
||||
mismatch_arg == 0);
|
||||
|
||||
return mock_type::ret_erase(reinterpret_cast<void*>(fn));
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
auto
|
||||
mock_call(std::string name, R fn(Args...), Args... args) -> decltype(fn(args...)) {
|
||||
typedef mock_function_type<R, Args...> mock_type;
|
||||
|
||||
if (mock_type::has_redirect(reinterpret_cast<void*>(fn)))
|
||||
return mock_type::call_redirect(reinterpret_cast<void*>(fn), args...);
|
||||
|
||||
return mock_call_direct(name, fn, args...);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test_fixture.h"
|
||||
|
||||
#include "torrent/utils/log.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void
|
||||
test_fixture::setUp() {
|
||||
mock_init();
|
||||
|
||||
log_add_group_output(torrent::LOG_CONNECTION_BIND, "test_output");
|
||||
log_add_group_output(torrent::LOG_CONNECTION_FD, "test_output");
|
||||
}
|
||||
|
||||
void
|
||||
test_fixture::tearDown() {
|
||||
mock_cleanup();
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef LIBTORRENT_HELPER_TEST_FIXTURE_H
|
||||
#define LIBTORRENT_HELPER_TEST_FIXTURE_H
|
||||
|
||||
#include <cppunit/TestFixture.h>
|
||||
|
||||
#include "test/helpers/mock_function.h"
|
||||
|
||||
class test_fixture : public CppUnit::TestFixture {
|
||||
public:
|
||||
void setUp();
|
||||
void tearDown();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test_main_thread.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "test/helpers/mock_function.h"
|
||||
#include "torrent/exceptions.h"
|
||||
#include "torrent/poll.h"
|
||||
#include "torrent/net/resolver.h"
|
||||
#include "torrent/utils/scheduler.h"
|
||||
|
||||
std::unique_ptr<TestMainThread>
|
||||
TestMainThread::create() {
|
||||
if (torrent::Poll::slot_create_poll() == nullptr)
|
||||
set_create_poll();
|
||||
|
||||
// Needs to be called before Thread is created.
|
||||
mock_redirect_defaults();
|
||||
|
||||
auto thread = new TestMainThread();
|
||||
return std::unique_ptr<TestMainThread>(thread);
|
||||
}
|
||||
|
||||
TestMainThread::TestMainThread() {}
|
||||
|
||||
TestMainThread::~TestMainThread() {
|
||||
m_self = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
TestMainThread::init_thread() {
|
||||
if (!torrent::Poll::slot_create_poll())
|
||||
throw torrent::internal_error("ThreadMain::init_thread(): Poll::slot_create_poll() not valid.");
|
||||
|
||||
m_poll = std::unique_ptr<torrent::Poll>(torrent::Poll::slot_create_poll()());
|
||||
m_resolver = std::make_unique<torrent::net::Resolver>();
|
||||
m_state = STATE_INITIALIZED;
|
||||
|
||||
//m_instrumentation_index = INSTRUMENTATION_POLLING_DO_POLL_MAIN - INSTRUMENTATION_POLLING_DO_POLL;
|
||||
|
||||
init_thread_local();
|
||||
}
|
||||
|
||||
void
|
||||
TestMainThread::call_events() {
|
||||
process_callbacks();
|
||||
}
|
||||
|
||||
std::chrono::microseconds
|
||||
TestMainThread::next_timeout() {
|
||||
return std::chrono::microseconds(10min);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef TEST_HELPERS_TEST_MAIN_THREAD_H
|
||||
#define TEST_HELPERS_TEST_MAIN_THREAD_H
|
||||
|
||||
#include <memory>
|
||||
#include <torrent/common.h>
|
||||
#include <torrent/utils/thread.h>
|
||||
|
||||
#include "test/helpers/test_thread.h"
|
||||
|
||||
class TestMainThread : public torrent::utils::Thread {
|
||||
public:
|
||||
static std::unique_ptr<TestMainThread> create();
|
||||
|
||||
~TestMainThread() override;
|
||||
|
||||
const char* name() const override { return "rtorrent test main"; }
|
||||
|
||||
void init_thread() override;
|
||||
|
||||
void test_set_cached_time(std::chrono::microseconds t) { set_cached_time(365 * 24h + t); }
|
||||
void test_process_events_without_cached_time() { process_events_without_cached_time(); }
|
||||
|
||||
private:
|
||||
TestMainThread();
|
||||
|
||||
void call_events() override;
|
||||
std::chrono::microseconds next_timeout() override;
|
||||
};
|
||||
|
||||
#endif // TEST_HELPERS_TEST_MAIN_THREAD_H
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test_thread.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/poll.h>
|
||||
|
||||
#include "test/helpers/mock_function.h"
|
||||
|
||||
const int test_thread::test_flag_pre_stop;
|
||||
const int test_thread::test_flag_long_timeout;
|
||||
|
||||
const int test_thread::test_flag_do_work;
|
||||
const int test_thread::test_flag_pre_poke;
|
||||
const int test_thread::test_flag_post_poke;
|
||||
|
||||
// TODO: Remove PollSelect.
|
||||
|
||||
torrent::Poll*
|
||||
create_poll() {
|
||||
torrent::Poll* poll = torrent::Poll::create(256);
|
||||
|
||||
if (poll == nullptr)
|
||||
throw torrent::internal_error("Unable to create poll object");
|
||||
|
||||
return poll;
|
||||
}
|
||||
|
||||
void
|
||||
set_create_poll() {
|
||||
torrent::Poll::slot_create_poll() = []() {
|
||||
return create_poll();
|
||||
};
|
||||
}
|
||||
|
||||
std::unique_ptr<test_thread>
|
||||
test_thread::create() {
|
||||
// Needs to be called before Thread is created.
|
||||
mock_redirect_defaults();
|
||||
|
||||
auto thread = new test_thread();
|
||||
return std::unique_ptr<test_thread>(thread);
|
||||
}
|
||||
|
||||
test_thread::test_thread() :
|
||||
m_test_state(TEST_NONE),
|
||||
m_test_flags(0) {
|
||||
}
|
||||
|
||||
test_thread::~test_thread() {
|
||||
if (is_active())
|
||||
stop_thread_wait();
|
||||
|
||||
m_self = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
test_thread::init_thread() {
|
||||
m_state = STATE_INITIALIZED;
|
||||
m_test_state = TEST_PRE_START;
|
||||
|
||||
m_poll = std::unique_ptr<torrent::Poll>(create_poll());
|
||||
}
|
||||
|
||||
void
|
||||
test_thread::call_events() {
|
||||
m_loop_count++;
|
||||
|
||||
if ((m_test_flags & test_flag_pre_stop) && m_test_state == TEST_PRE_START && m_state == STATE_ACTIVE)
|
||||
m_test_state = TEST_PRE_STOP;
|
||||
|
||||
if ((m_flags & flag_do_shutdown)) {
|
||||
if ((m_flags & flag_did_shutdown))
|
||||
throw torrent::internal_error("Already trigged shutdown.");
|
||||
|
||||
m_flags |= flag_did_shutdown;
|
||||
throw torrent::shutdown_exception();
|
||||
}
|
||||
|
||||
if ((m_test_flags & test_flag_pre_poke)) {
|
||||
}
|
||||
|
||||
if ((m_test_flags & test_flag_do_work)) {
|
||||
usleep(10 * 1000); // TODO: Don't just sleep, as that give up core.
|
||||
m_test_flags &= ~test_flag_do_work;
|
||||
}
|
||||
|
||||
if ((m_test_flags & test_flag_post_poke)) {
|
||||
}
|
||||
|
||||
process_callbacks();
|
||||
}
|
||||
|
||||
std::chrono::microseconds
|
||||
test_thread::next_timeout() {
|
||||
if ((m_test_flags & test_flag_long_timeout))
|
||||
return std::chrono::microseconds(10s);
|
||||
else
|
||||
return std::chrono::microseconds(100ms);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#ifndef TEST_HELPERS_TEST_THREAD_H
|
||||
#define TEST_HELPERS_TEST_THREAD_H
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include "torrent/common.h"
|
||||
#include "torrent/utils/thread.h"
|
||||
|
||||
class test_thread : public torrent::utils::Thread {
|
||||
public:
|
||||
enum test_state {
|
||||
TEST_NONE,
|
||||
TEST_PRE_START,
|
||||
TEST_PRE_STOP,
|
||||
TEST_STOP
|
||||
};
|
||||
|
||||
static const int test_flag_pre_stop = 0x1;
|
||||
static const int test_flag_long_timeout = 0x2;
|
||||
|
||||
static const int test_flag_do_work = 0x100;
|
||||
static const int test_flag_pre_poke = 0x200;
|
||||
static const int test_flag_post_poke = 0x400;
|
||||
|
||||
static std::unique_ptr<test_thread> create();
|
||||
|
||||
~test_thread() override;
|
||||
|
||||
int test_state() const { return m_test_state; }
|
||||
|
||||
bool is_state(int state) const { return m_state == state; }
|
||||
bool is_test_state(int state) const { return m_test_state == state; }
|
||||
bool is_test_flags(int flags) const { return (m_test_flags & flags) == flags; }
|
||||
bool is_not_test_flags(int flags) const { return !(m_test_flags & flags); }
|
||||
|
||||
// Loop count increments twice each loop.
|
||||
int loop_count() const { return m_loop_count; }
|
||||
|
||||
const char* name() const override { return "test_thread"; }
|
||||
|
||||
void init_thread() override;
|
||||
|
||||
void set_pre_stop() { m_test_flags |= test_flag_pre_stop; }
|
||||
void set_test_flag(int flags) { m_test_flags |= flags; }
|
||||
|
||||
private:
|
||||
test_thread();
|
||||
|
||||
void call_events() override;
|
||||
std::chrono::microseconds next_timeout() override;
|
||||
|
||||
std::atomic_int m_test_state;
|
||||
std::atomic_int m_test_flags;
|
||||
std::atomic_int m_loop_count{0};
|
||||
};
|
||||
|
||||
void set_create_poll();
|
||||
|
||||
// TODO: Need better cleanup here.
|
||||
// TODO: Replace these with class that holds the threads and cleans them up on destruction.
|
||||
|
||||
#define SETUP_THREAD_DISK() \
|
||||
auto thread_test = test_thread::create(); \
|
||||
thread_test->init_thread(); \
|
||||
torrent::ThreadDisk::create_thread(); \
|
||||
torrent::thread_disk()->init_thread(); \
|
||||
torrent::thread_disk()->start_thread();
|
||||
|
||||
#define CLEANUP_THREAD_DISK() \
|
||||
torrent::ThreadDisk::destroy_thread();
|
||||
|
||||
#endif
|
||||
@@ -1,19 +0,0 @@
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
#include "rpc/command.h"
|
||||
|
||||
class CommandTest : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST_SUITE(CommandTest);
|
||||
CPPUNIT_TEST(test_stack);
|
||||
CPPUNIT_TEST(test_stack_double);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp() { }
|
||||
void tearDown() {}
|
||||
|
||||
void test_stack();
|
||||
void test_stack_double();
|
||||
|
||||
private:
|
||||
};
|
||||
@@ -1,19 +0,0 @@
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
#include "rpc/command_map.h"
|
||||
#include "rpc/jsonrpc.h"
|
||||
|
||||
class JsonrpcTest : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST_SUITE(JsonrpcTest);
|
||||
CPPUNIT_TEST(test_basics);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp();
|
||||
void tearDown() {}
|
||||
|
||||
void test_basics();
|
||||
|
||||
private:
|
||||
rpc::JsonRpc m_jsonrpc;
|
||||
};
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "command_test.h"
|
||||
#include "test/rpc/test_command.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(CommandTest);
|
||||
#include "rpc/command.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommand);
|
||||
|
||||
bool
|
||||
command_stack_all_empty() {
|
||||
@@ -11,7 +13,7 @@ command_stack_all_empty() {
|
||||
}
|
||||
|
||||
void
|
||||
CommandTest::test_stack() {
|
||||
TestCommand::test_stack() {
|
||||
torrent::Object::list_type args;
|
||||
rpc::command_base::stack_type stack;
|
||||
torrent::Object* last_stack;
|
||||
@@ -50,7 +52,7 @@ CommandTest::test_stack() {
|
||||
}
|
||||
|
||||
void
|
||||
CommandTest::test_stack_double() {
|
||||
TestCommand::test_stack_double() {
|
||||
torrent::Object::list_type args;
|
||||
rpc::command_base::stack_type stack_first;
|
||||
rpc::command_base::stack_type stack_second;
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
class TestCommand : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestCommand);
|
||||
|
||||
CPPUNIT_TEST(test_stack);
|
||||
CPPUNIT_TEST(test_stack_double);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void test_stack();
|
||||
void test_stack_double();
|
||||
};
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test/rpc/test_command_map.h"
|
||||
|
||||
#include "command_helpers.h"
|
||||
#include "rpc/command_map.h"
|
||||
|
||||
#include "command_map_test.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(CommandMapTest);
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandMap);
|
||||
|
||||
#undef CMD2_A_FUNCTION
|
||||
|
||||
@@ -13,13 +13,13 @@ CPPUNIT_TEST_SUITE_REGISTRATION(CommandMapTest);
|
||||
m_map.insert_slot<rpc::command_base_is_type<rpc::function>::type>(key, slot, &rpc::function, \
|
||||
rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_rpc, NULL, NULL);
|
||||
|
||||
torrent::Object cmd_test_map_a(rpc::target_type t, const torrent::Object& obj) { return obj; }
|
||||
torrent::Object cmd_test_map_b(rpc::target_type t, const torrent::Object& obj, uint64_t c) { return torrent::Object(c); }
|
||||
torrent::Object cmd_test_map_a([[maybe_unused]] rpc::target_type t, const torrent::Object& obj) { return obj; }
|
||||
torrent::Object cmd_test_map_b([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj, uint64_t c) { return torrent::Object(c); }
|
||||
|
||||
torrent::Object cmd_test_any_string(__UNUSED rpc::target_type target, const std::string& rawArgs) { return (int64_t)3; }
|
||||
torrent::Object cmd_test_any_string([[maybe_unused]] rpc::target_type target, [[maybe_unused]] const std::string& rawArgs) { return (int64_t)3; }
|
||||
|
||||
void
|
||||
CommandMapTest::test_basics() {
|
||||
TestCommandMap::test_basics() {
|
||||
CMD2_ANY("test_a", &cmd_test_map_a);
|
||||
CMD2_ANY("test_b", std::bind(&cmd_test_map_b, std::placeholders::_1, std::placeholders::_2, (uint64_t)2));
|
||||
CMD2_ANY_STRING("any_string", &cmd_test_any_string);
|
||||
@@ -1,17 +1,18 @@
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
#include "rpc/command_map.h"
|
||||
|
||||
class CommandMapTest : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST_SUITE(CommandMapTest);
|
||||
class TestCommandMap : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestCommandMap);
|
||||
|
||||
CPPUNIT_TEST(test_basics);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
static const int cmd_size = 256;
|
||||
|
||||
void setUp() { m_commandItr = m_commands; }
|
||||
void tearDown() {}
|
||||
|
||||
void test_basics();
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test/rpc/test_command_slot.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <torrent/object.h>
|
||||
|
||||
#include "rpc/command_map.h"
|
||||
|
||||
#include "command_slot_test.h"
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandSlot);
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(CommandSlotTest);
|
||||
torrent::Object cmd_test_a([[maybe_unused]] rpc::target_type t, const torrent::Object& obj) { return obj; }
|
||||
torrent::Object cmd_test_b([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj, uint64_t c) { return torrent::Object(c); }
|
||||
|
||||
torrent::Object cmd_test_a(rpc::target_type t, const torrent::Object& obj) { return obj; }
|
||||
torrent::Object cmd_test_b(rpc::target_type t, const torrent::Object& obj, uint64_t c) { return torrent::Object(c); }
|
||||
torrent::Object cmd_test_list([[maybe_unused]] rpc::target_type t, const torrent::Object::list_type& obj) { return torrent::Object(obj.front()); }
|
||||
|
||||
torrent::Object cmd_test_list(rpc::target_type t, const torrent::Object::list_type& obj) { return torrent::Object(obj.front()); }
|
||||
|
||||
void cmd_test_convert_void(rpc::target_type t, const torrent::Object& obj) {}
|
||||
int32_t cmd_test_convert_int32_t(rpc::target_type t, const torrent::Object& obj) { return 9; }
|
||||
int64_t cmd_test_convert_int64_t(rpc::target_type t, const torrent::Object& obj) { return 10; }
|
||||
std::string cmd_test_convert_string(rpc::target_type t, const torrent::Object& obj) { return "test_1"; }
|
||||
const std::string& cmd_test_convert_const_string(rpc::target_type t, const torrent::Object& obj) { static const std::string ret = "test_2"; return ret; }
|
||||
void cmd_test_convert_void([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj) {}
|
||||
int32_t cmd_test_convert_int32_t([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj) { return 9; }
|
||||
int64_t cmd_test_convert_int64_t([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj) { return 10; }
|
||||
std::string cmd_test_convert_string([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj) { return "test_1"; }
|
||||
const std::string& cmd_test_convert_const_string([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj) { static const std::string ret = "test_2"; return ret; }
|
||||
|
||||
void
|
||||
CommandSlotTest::test_basics() {
|
||||
TestCommandSlot::test_basics() {
|
||||
// rpc::command_base test_any;
|
||||
// test_any.set_function<rpc::any_function>(&cmd_test_a);
|
||||
// CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).as_value() == 1);
|
||||
@@ -33,13 +34,13 @@ CommandSlotTest::test_basics() {
|
||||
}
|
||||
|
||||
void
|
||||
CommandSlotTest::test_type_validity() {
|
||||
TestCommandSlot::test_type_validity() {
|
||||
// CPPUNIT_ASSERT((rpc::command_base_is_type<rpc::any_function, &rpc::command_base_call_any>::value));
|
||||
// CPPUNIT_ASSERT((rpc::command_base_is_type<rpc::any_string_function, &rpc::command_base_call_any_string>::value));
|
||||
}
|
||||
|
||||
void
|
||||
CommandSlotTest::test_convert_return() {
|
||||
TestCommandSlot::test_convert_return() {
|
||||
// rpc::command_base test_any;
|
||||
|
||||
// test_any.set_function<rpc::any_function>(&cmd_test_convert_string);
|
||||
@@ -1,18 +1,15 @@
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
#include "rpc/command.h"
|
||||
class TestCommandSlot : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestCommandSlot);
|
||||
|
||||
class CommandSlotTest : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST_SUITE(CommandSlotTest);
|
||||
CPPUNIT_TEST(test_basics);
|
||||
CPPUNIT_TEST(test_type_validity);
|
||||
CPPUNIT_TEST(test_convert_return);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp() {}
|
||||
void tearDown() {}
|
||||
|
||||
void test_basics();
|
||||
void test_type_validity();
|
||||
void test_convert_return();
|
||||
@@ -1,14 +1,15 @@
|
||||
#include "config.h"
|
||||
#include <string>
|
||||
|
||||
#include "command_helpers.h"
|
||||
#include "rpc/command_map.h"
|
||||
#include "test/rpc/test_jsonrpc.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "control.h"
|
||||
#include "globals.h"
|
||||
#include "jsonrpc_test.h"
|
||||
#include "command_helpers.h"
|
||||
#include "rpc/command_map.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(JsonrpcTest);
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestJsonrpc);
|
||||
|
||||
torrent::Object
|
||||
jsonrpc_cmd_test_reflect([[maybe_unused]] rpc::target_type t, const torrent::Object& obj) { return obj; }
|
||||
@@ -117,19 +118,27 @@ std::vector<std::tuple<std::string, std::string, std::string>> basic_jsonrpc_req
|
||||
};
|
||||
|
||||
void
|
||||
JsonrpcTest::setUp() {
|
||||
TestJsonrpc::setUp() {
|
||||
m_test_main_thread = TestMainThread::create();
|
||||
m_test_main_thread->init_thread();
|
||||
|
||||
m_jsonrpc = rpc::JsonRpc();
|
||||
m_jsonrpc.initialize();
|
||||
setlocale(LC_ALL, "");
|
||||
// cachedTime = rak::timer::current();
|
||||
control = new Control;
|
||||
control = new Control;
|
||||
|
||||
if (rpc::commands.find("jsonrpc_reflect") == rpc::commands.end()) {
|
||||
CMD2_ANY("jsonrpc_reflect", &jsonrpc_cmd_test_reflect);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JsonrpcTest::test_basics() {
|
||||
TestJsonrpc::tearDown() {
|
||||
m_test_main_thread.reset();
|
||||
}
|
||||
|
||||
void
|
||||
TestJsonrpc::test_basics() {
|
||||
for (auto& test : basic_jsonrpc_requests) {
|
||||
std::string output;
|
||||
m_jsonrpc.process(std::get<1>(test).c_str(), std::get<1>(test).size(), [&output](const char* c, uint32_t l) { output.append(c, l); return true; });
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "test/helpers/test_fixture.h"
|
||||
#include "test/helpers/test_main_thread.h"
|
||||
|
||||
#include "rpc/command_map.h"
|
||||
#include "rpc/jsonrpc.h"
|
||||
|
||||
class TestJsonrpc : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestJsonrpc);
|
||||
|
||||
CPPUNIT_TEST(test_basics);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
void test_basics();
|
||||
|
||||
private:
|
||||
std::unique_ptr<TestMainThread> m_test_main_thread;
|
||||
|
||||
rpc::JsonRpc m_jsonrpc;
|
||||
};
|
||||
@@ -1,16 +1,17 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "object_storage_test.h"
|
||||
#include "test/rpc/test_object_storage.h"
|
||||
|
||||
#include "helpers/assert.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(ObjectStorageTest);
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestObjectStorage);
|
||||
|
||||
void
|
||||
ObjectStorageTest::test_basics() {
|
||||
TestObjectStorage::test_basics() {
|
||||
rpc::object_storage::iterator itr;
|
||||
|
||||
CPPUNIT_ASSERT(m_storage.empty());
|
||||
|
||||
|
||||
itr = m_storage.insert("test_1", torrent::Object("a"), rpc::object_storage::flag_string_type);
|
||||
|
||||
CPPUNIT_ASSERT(itr != m_storage.end());
|
||||
@@ -32,7 +33,7 @@ ObjectStorageTest::test_basics() {
|
||||
}
|
||||
|
||||
void
|
||||
ObjectStorageTest::test_conversions() {
|
||||
TestObjectStorage::test_conversions() {
|
||||
CPPUNIT_ASSERT(m_storage.insert("test_1", torrent::Object("a"), rpc::object_storage::flag_string_type) != m_storage.end());
|
||||
CPPUNIT_ASSERT(m_storage.insert_str(std::string("test_2"), torrent::Object("a"), rpc::object_storage::flag_string_type) != m_storage.end());
|
||||
|
||||
@@ -44,7 +45,7 @@ ObjectStorageTest::test_conversions() {
|
||||
}
|
||||
|
||||
void
|
||||
ObjectStorageTest::test_validate_keys() {
|
||||
TestObjectStorage::test_validate_keys() {
|
||||
torrent::raw_string raw_string_4("test_4\0foo", 10);
|
||||
|
||||
ASSERT_CATCH_INPUT_ERROR( { m_storage.insert(raw_string_4, torrent::Object("a"), rpc::object_storage::flag_string_type); } );
|
||||
@@ -55,7 +56,7 @@ ObjectStorageTest::test_validate_keys() {
|
||||
// Test for various conversions of fixed_key_type.
|
||||
|
||||
void
|
||||
ObjectStorageTest::test_access() {
|
||||
TestObjectStorage::test_access() {
|
||||
m_storage.insert("string_1", torrent::Object("gen_a"), rpc::object_storage::flag_string_type);
|
||||
m_storage.insert("value_1", int64_t(1), rpc::object_storage::flag_value_type);
|
||||
|
||||
@@ -68,7 +69,7 @@ ObjectStorageTest::test_access() {
|
||||
// CPPUNIT_ASSERT(m_storage.set_c_str_value("value_1", "123").as_value() == 123);
|
||||
// CPPUNIT_ASSERT(m_storage.set_c_str_value("value_1", torrent::raw_string::from_c_str("321")).as_value() == 321);
|
||||
// CPPUNIT_ASSERT(m_storage.set_c_str_value("value_1", torrent::raw_bencode::from_c_str("i567e")).as_value() == 567);
|
||||
|
||||
|
||||
// ASSERT_CATCH_INPUT_ERROR( { m_storage.set_c_str_value("value_1", "e123"); } );
|
||||
|
||||
// Test string from raw and normal, list, etc.
|
||||
@@ -1,19 +1,18 @@
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
#include "rpc/object_storage.h"
|
||||
|
||||
class ObjectStorageTest : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST_SUITE(ObjectStorageTest);
|
||||
class TestObjectStorage : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestObjectStorage);
|
||||
|
||||
CPPUNIT_TEST(test_basics);
|
||||
CPPUNIT_TEST(test_conversions);
|
||||
CPPUNIT_TEST(test_validate_keys);
|
||||
CPPUNIT_TEST(test_access);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp() { }
|
||||
void tearDown() {}
|
||||
|
||||
void test_basics();
|
||||
|
||||
void test_conversions();
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test_parse_options.h"
|
||||
|
||||
#include "helpers/assert.h"
|
||||
#include "test/rpc/test_parse_options.h"
|
||||
|
||||
#include <array>
|
||||
#include <torrent/connection_manager.h>
|
||||
@@ -10,6 +8,7 @@
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "test/helpers/assert.h"
|
||||
#include "rpc/parse_options.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestParseOptions);
|
||||
@@ -37,7 +36,7 @@ flag_to_int(const std::string& flag) {
|
||||
for (auto f : flag_list)
|
||||
if (f.first == flag)
|
||||
return f.second;
|
||||
|
||||
|
||||
throw torrent::input_error("unknown flag");
|
||||
}
|
||||
|
||||
@@ -86,7 +85,7 @@ TestParseOptions::test_flag_error() {
|
||||
FLAG_ASSERT_ERROR("");
|
||||
FLAG_ASSERT_ERROR("foo|bar");
|
||||
FLAG_ASSERT_ERROR("foo|bar|baz");
|
||||
|
||||
|
||||
FLAG_ASSERT_ERROR("foo |bar");
|
||||
FLAG_ASSERT_ERROR("foo | bar| baz");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
class TestParseOptions : public CppUnit::TestFixture {
|
||||
class TestParseOptions : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestParseOptions);
|
||||
|
||||
CPPUNIT_TEST(test_flag_basic);
|
||||
CPPUNIT_TEST(test_flag_error);
|
||||
|
||||
@@ -14,12 +15,10 @@ class TestParseOptions : public CppUnit::TestFixture {
|
||||
|
||||
CPPUNIT_TEST(test_flag_libtorrent);
|
||||
CPPUNIT_TEST(test_flags_libtorrent);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp() { }
|
||||
void tearDown() {}
|
||||
|
||||
void test_flag_basic();
|
||||
void test_flag_error();
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test/rpc/test_xmlrpc.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "control.h"
|
||||
#include "globals.h"
|
||||
#include "command_helpers.h"
|
||||
#include "rpc/command_map.h"
|
||||
|
||||
#include "xmlrpc_test.h"
|
||||
#include "control.h"
|
||||
#include "globals.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(XmlrpcTest);
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestXmlrpc);
|
||||
|
||||
torrent::Object xmlrpc_cmd_test_reflect([[maybe_unused]] rpc::target_type t, const torrent::Object& obj) { return obj; }
|
||||
|
||||
@@ -99,19 +100,27 @@ std::vector<std::tuple<std::string, std::string, std::string>> basic_requests =
|
||||
};
|
||||
|
||||
void
|
||||
XmlrpcTest::setUp() {
|
||||
TestXmlrpc::setUp() {
|
||||
m_test_main_thread = TestMainThread::create();
|
||||
m_test_main_thread->init_thread();
|
||||
|
||||
m_xmlrpc = rpc::XmlRpc();
|
||||
m_xmlrpc.initialize();
|
||||
setlocale(LC_ALL, "");
|
||||
// cachedTime = rak::timer::current();
|
||||
control = new Control;
|
||||
|
||||
if (rpc::commands.find("xmlrpc_reflect") == rpc::commands.end()) {
|
||||
CMD2_ANY("xmlrpc_reflect", &xmlrpc_cmd_test_reflect);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XmlrpcTest::test_basics() {
|
||||
TestXmlrpc::tearDown() {
|
||||
m_test_main_thread.reset();
|
||||
}
|
||||
|
||||
void
|
||||
TestXmlrpc::test_basics() {
|
||||
for (auto& test : basic_requests) {
|
||||
std::string output;
|
||||
m_xmlrpc.process(std::get<1>(test).c_str(), std::get<1>(test).size(), [&output](const char* c, uint32_t l){ output.append(c, l); return true;});
|
||||
@@ -120,7 +129,7 @@ XmlrpcTest::test_basics() {
|
||||
}
|
||||
|
||||
void
|
||||
XmlrpcTest::test_invalid_utf8() {
|
||||
TestXmlrpc::test_invalid_utf8() {
|
||||
// Surprisingly, this call doesn't fail. TinyXML-2 technically expects
|
||||
// valid UTF-8, but doesn't check strings, and Object strings are
|
||||
// just a series of bytes so it reflects just fine.
|
||||
@@ -132,7 +141,7 @@ XmlrpcTest::test_invalid_utf8() {
|
||||
}
|
||||
|
||||
void
|
||||
XmlrpcTest::test_size_limit() {
|
||||
TestXmlrpc::test_size_limit() {
|
||||
std::string input = "<?xml version=\"1.0\"?><methodCall><methodName>xmlrpc_reflect</methodName><params><param><value><string></string></value></param><param><value><string>\xc3\x28</string></value></param></params></methodCall>";
|
||||
std::string expected = "<?xml version=\"1.0\"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><i8>-509</i8></value></member><member><name>faultString</name><value><string>Content size exceeds maximum XML-RPC limit</string></value></member></struct></value></fault></methodResponse>";
|
||||
std::string output;
|
||||
@@ -140,9 +149,13 @@ XmlrpcTest::test_size_limit() {
|
||||
m_xmlrpc.process(input.c_str(), input.size(), [&output](const char* c, uint32_t l){ output.append(c, l); return true;});
|
||||
CPPUNIT_ASSERT_EQUAL(expected, output);
|
||||
}
|
||||
|
||||
#else
|
||||
void XmlrpcTest::test_invalid_utf8() {}
|
||||
void XmlrpcTest::test_basics() {}
|
||||
void XmlrpcTest::test_size_limit() {}
|
||||
void XmlrpcTest::setUp() {}
|
||||
|
||||
void TestXmlrpc::test_invalid_utf8() {}
|
||||
void TestXmlrpc::test_basics() {}
|
||||
void TestXmlrpc::test_size_limit() {}
|
||||
void TestXmlrpc::setUp() {}
|
||||
void TestXmlrpc::tearDown() {}
|
||||
|
||||
#endif
|
||||
@@ -1,29 +1,32 @@
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include "test/helpers/test_fixture.h"
|
||||
#include "test/helpers/test_main_thread.h"
|
||||
|
||||
#include "rpc/command_map.h"
|
||||
#include "rpc/xmlrpc.h"
|
||||
|
||||
class XmlrpcTest : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST_SUITE(XmlrpcTest);
|
||||
class TestXmlrpc : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestXmlrpc);
|
||||
|
||||
CPPUNIT_TEST(test_basics);
|
||||
CPPUNIT_TEST(test_invalid_utf8);
|
||||
CPPUNIT_TEST(test_size_limit);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
static const int cmd_size = 256;
|
||||
|
||||
void setUp();
|
||||
void tearDown() {}
|
||||
void tearDown();
|
||||
|
||||
void test_basics();
|
||||
void test_invalid_utf8();
|
||||
void test_size_limit();
|
||||
|
||||
private:
|
||||
rpc::XmlRpc m_xmlrpc;
|
||||
|
||||
rpc::CommandMap m_map;
|
||||
std::unique_ptr<TestMainThread> m_test_main_thread;
|
||||
|
||||
rpc::XmlRpc m_xmlrpc;
|
||||
rpc::CommandMap m_map;
|
||||
rpc::command_base m_commands[cmd_size];
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
class CommandDynamicTest : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST_SUITE(CommandDynamicTest);
|
||||
CPPUNIT_TEST(test_basics);
|
||||
CPPUNIT_TEST(test_get_set);
|
||||
CPPUNIT_TEST(test_old_style);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp();
|
||||
void tearDown() {}
|
||||
|
||||
void test_basics();
|
||||
void test_get_set();
|
||||
|
||||
void test_old_style();
|
||||
|
||||
private:
|
||||
};
|
||||
@@ -1,22 +1,21 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <iostream>
|
||||
#include "test/src/test_command_dynamic.h"
|
||||
|
||||
#include "command_dynamic_test.h"
|
||||
|
||||
#include "helpers/assert.h"
|
||||
|
||||
#include "rpc/parse_commands.h"
|
||||
#include "control.h"
|
||||
#include "globals.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(CommandDynamicTest);
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandDynamic);
|
||||
|
||||
void initialize_command_dynamic();
|
||||
void initialize_command_ui();
|
||||
|
||||
void
|
||||
CommandDynamicTest::setUp() {
|
||||
TestCommandDynamic::setUp() {
|
||||
m_test_main_thread = TestMainThread::create();
|
||||
m_test_main_thread->init_thread();
|
||||
|
||||
if (rpc::commands.find("method.insert") == rpc::commands.end()) {
|
||||
setlocale(LC_ALL, "");
|
||||
// cachedTime = rak::timer::current();
|
||||
@@ -28,13 +27,18 @@ CommandDynamicTest::setUp() {
|
||||
}
|
||||
|
||||
void
|
||||
CommandDynamicTest::test_basics() {
|
||||
TestCommandDynamic::tearDown() {
|
||||
m_test_main_thread.reset();
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandDynamic::test_basics() {
|
||||
rpc::commands.call_command("method.insert.value", rpc::create_object_list("test_basics.1", int64_t(1)));
|
||||
CPPUNIT_ASSERT(rpc::commands.call_command("test_basics.1", torrent::Object()).as_value() == 1);
|
||||
}
|
||||
|
||||
void
|
||||
CommandDynamicTest::test_get_set() {
|
||||
TestCommandDynamic::test_get_set() {
|
||||
rpc::commands.call_command("method.insert.simple", rpc::create_object_list("test_get_set.1", "cat=1"));
|
||||
CPPUNIT_ASSERT(rpc::commands.call_command("test_get_set.1", torrent::Object()).as_string() == "1");
|
||||
CPPUNIT_ASSERT(rpc::commands.call_command("method.get", "test_get_set.1").as_string() == "cat=1");
|
||||
@@ -44,7 +48,7 @@ CommandDynamicTest::test_get_set() {
|
||||
}
|
||||
|
||||
void
|
||||
CommandDynamicTest::test_old_style() {
|
||||
TestCommandDynamic::test_old_style() {
|
||||
rpc::commands.call_command("method.insert", rpc::create_object_list("test_old_style.1", "value", int64_t(1)));
|
||||
CPPUNIT_ASSERT(rpc::commands.call_command("test_old_style.1", torrent::Object()).as_value() == 1);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "test/helpers/test_fixture.h"
|
||||
#include "test/helpers/test_main_thread.h"
|
||||
|
||||
class TestCommandDynamic : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestCommandDynamic);
|
||||
|
||||
CPPUNIT_TEST(test_basics);
|
||||
CPPUNIT_TEST(test_get_set);
|
||||
CPPUNIT_TEST(test_old_style);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
void test_basics();
|
||||
void test_get_set();
|
||||
|
||||
void test_old_style();
|
||||
|
||||
private:
|
||||
std::unique_ptr<TestMainThread> m_test_main_thread;
|
||||
};
|
||||
Reference in New Issue
Block a user