32#include <boost/thread/mutex.hpp>
33#include <boost/thread/thread.hpp>
35#include "gtest/gtest.h"
54 test_levin_commands_handler()
60 virtual int invoke(
int command,
const epee::span<const uint8_t> in_buff, std::string& buff_out, test_levin_connection_context& context)
62 m_invoke_counter.inc();
63 boost::unique_lock<boost::mutex> lock(m_mutex);
64 m_last_command = command;
65 m_last_in_buf = std::string((
const char*)in_buff.
data(), in_buff.
size());
66 buff_out = m_invoke_out_buf;
70 virtual int notify(
int command,
const epee::span<const uint8_t> in_buff, test_levin_connection_context& context)
72 m_notify_counter.inc();
73 boost::unique_lock<boost::mutex> lock(m_mutex);
74 m_last_command = command;
75 m_last_in_buf = std::string((
const char*)in_buff.
data(), in_buff.
size());
79 virtual void callback(test_levin_connection_context& context)
81 m_callback_counter.inc();
85 virtual void on_connection_new(test_levin_connection_context& context)
87 m_new_connection_counter.inc();
91 virtual void on_connection_close(test_levin_connection_context& context)
93 m_close_connection_counter.inc();
97 size_t invoke_counter()
const {
return m_invoke_counter.get(); }
98 size_t notify_counter()
const {
return m_notify_counter.get(); }
99 size_t callback_counter()
const {
return m_callback_counter.get(); }
100 size_t new_connection_counter()
const {
return m_new_connection_counter.get(); }
101 size_t close_connection_counter()
const {
return m_close_connection_counter.get(); }
103 int return_code()
const {
return m_return_code; }
104 void return_code(
int v) { m_return_code = v; }
106 const std::string& invoke_out_buf()
const {
return m_invoke_out_buf; }
107 void invoke_out_buf(
const std::string& v) { m_invoke_out_buf = v; }
109 int last_command()
const {
return m_last_command; }
110 const std::string& last_in_buf()
const {
return m_last_in_buf; }
113 unit_test::call_counter m_invoke_counter;
114 unit_test::call_counter m_notify_counter;
115 unit_test::call_counter m_callback_counter;
116 unit_test::call_counter m_new_connection_counter;
117 unit_test::call_counter m_close_connection_counter;
119 boost::mutex m_mutex;
122 std::string m_invoke_out_buf;
125 std::string m_last_in_buf;
131 test_connection(boost::asio::io_service& io_service, test_levin_protocol_handler_config& protocol_config)
132 : m_io_service(io_service)
133 , m_protocol_handler(this, protocol_config, m_context)
134 , m_send_return(
true)
140 ASSERT_TRUE(m_protocol_handler.after_init_connection());
144 virtual bool do_send(
const void* ptr,
size_t cb)
147 m_send_counter.inc();
148 boost::unique_lock<boost::mutex> lock(m_mutex);
149 m_last_send_data.append(
reinterpret_cast<const char*
>(ptr), cb);
150 return m_send_return;
153 virtual bool close() {
return true; }
154 virtual bool send_done() {
return true; }
155 virtual bool call_run_once_service_io() { std::cout <<
"test_connection::call_run_once_service_io()" << std::endl;
return true; }
156 virtual bool request_callback() { std::cout <<
"test_connection::request_callback()" << std::endl;
return true; }
157 virtual boost::asio::io_service& get_io_service() { std::cout <<
"test_connection::get_io_service()" << std::endl;
return m_io_service; }
158 virtual bool add_ref() { std::cout <<
"test_connection::add_ref()" << std::endl;
return true; }
159 virtual bool release() { std::cout <<
"test_connection::release()" << std::endl;
return true; }
161 size_t send_counter()
const {
return m_send_counter.get(); }
163 const std::string& last_send_data()
const {
return m_last_send_data; }
164 void reset_last_send_data() { boost::unique_lock<boost::mutex> lock(m_mutex); m_last_send_data.clear(); }
166 bool send_return()
const {
return m_send_return; }
167 void send_return(
bool v) { m_send_return = v; }
173 boost::asio::io_service& m_io_service;
174 test_levin_connection_context m_context;
176 unit_test::call_counter m_send_counter;
177 boost::mutex m_mutex;
179 std::string m_last_send_data;
187 const static uint64_t invoke_timeout = 5 * 1000;
188 const static size_t max_packet_size = 10 * 1024 * 1024;
190 typedef std::unique_ptr<test_connection> test_connection_ptr;
192 async_protocol_handler_test():
193 m_pcommands_handler(new test_levin_commands_handler()),
194 m_commands_handler(*m_pcommands_handler)
196 m_handler_config.set_handler(m_pcommands_handler, [](epee::levin::levin_commands_handler<test_levin_connection_context> *handler) {
delete handler; });
197 m_handler_config.m_invoke_timeout = invoke_timeout;
198 m_handler_config.m_max_packet_size = max_packet_size;
206 test_connection_ptr create_connection(
bool start =
true)
208 test_connection_ptr conn(
new test_connection(m_io_service, m_handler_config));
217 boost::asio::io_service m_io_service;
219 test_levin_commands_handler *m_pcommands_handler, &m_commands_handler;
222 class positive_test_connection_to_levin_protocol_handler_calls :
public async_protocol_handler_test
226 class test_levin_protocol_handler__hanle_recv_with_invalid_data :
public async_protocol_handler_test
229 static const int expected_command = 5615871;
230 static const int expected_return_code = 782546;
232 test_levin_protocol_handler__hanle_recv_with_invalid_data()
233 : m_expected_invoke_out_buf(512,
'y')
239 async_protocol_handler_test::SetUp();
241 m_conn = create_connection();
243 m_in_data.assign(256,
't');
246 m_req_head.m_cb = m_in_data.size();
247 m_req_head.m_have_to_return_data =
true;
248 m_req_head.m_command = expected_command;
249 m_req_head.m_return_code =
LEVIN_OK;
253 m_commands_handler.return_code(expected_return_code);
254 m_commands_handler.invoke_out_buf(m_expected_invoke_out_buf);
260 m_buf.assign(
reinterpret_cast<const char*
>(&m_req_head),
sizeof(m_req_head));
265 test_connection_ptr m_conn;
266 epee::levin::bucket_head2 m_req_head;
267 std::string m_in_data;
269 std::string m_expected_invoke_out_buf;
273TEST_F(positive_test_connection_to_levin_protocol_handler_calls, new_handler_is_not_initialized)
275 test_connection_ptr conn = create_connection(
false);
276 ASSERT_FALSE(conn->m_protocol_handler.m_connection_initialized);
277 ASSERT_EQ(0, m_handler_config.get_connections_count());
278 ASSERT_EQ(0, m_commands_handler.new_connection_counter());
280 ASSERT_EQ(0, m_handler_config.get_connections_count());
281 ASSERT_EQ(0, m_commands_handler.close_connection_counter());
284TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_initialization_and_destruction_is_correct)
286 test_connection_ptr conn = create_connection();
287 ASSERT_TRUE(conn->m_protocol_handler.m_connection_initialized);
288 ASSERT_EQ(1, m_handler_config.get_connections_count());
289 ASSERT_EQ(1, m_commands_handler.new_connection_counter());
291 ASSERT_EQ(0, m_handler_config.get_connections_count());
292 ASSERT_EQ(1, m_commands_handler.close_connection_counter());
295TEST_F(positive_test_connection_to_levin_protocol_handler_calls, concurent_handler_initialization_and_destruction_is_correct)
297 const size_t connection_count = 10000;
298 auto create_and_destroy_connections = [
this]()
300 std::vector<test_connection_ptr> connections(connection_count);
301 for (
size_t i = 0; i < connection_count; ++i)
303 connections[i] = create_connection();
306 for (
size_t i = 0; i < connection_count; ++i)
308 connections[i].reset();
312 const size_t thread_count = boost::thread::hardware_concurrency();
313 std::vector<boost::thread> threads(thread_count);
314 for (boost::thread& th : threads)
316 th = boost::thread(create_and_destroy_connections);
319 for (boost::thread& th : threads)
324 ASSERT_EQ(0, m_handler_config.get_connections_count());
325 ASSERT_EQ(connection_count * thread_count, m_commands_handler.new_connection_counter());
326 ASSERT_EQ(connection_count * thread_count, m_commands_handler.close_connection_counter());
329TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_processes_handle_read_as_invoke)
332 const int expected_command = 2634981;
333 const int expected_return_code = 6732;
334 const std::string expected_out_data(128,
'w');
336 test_connection_ptr conn = create_connection();
338 std::string in_data(256,
'q');
342 req_head.
m_cb = in_data.size();
348 std::string
buf(
reinterpret_cast<const char*
>(&req_head),
sizeof(req_head));
351 m_commands_handler.invoke_out_buf(expected_out_data);
352 m_commands_handler.return_code(expected_return_code);
362 ASSERT_EQ(1, m_commands_handler.invoke_counter());
363 ASSERT_EQ(0, m_commands_handler.notify_counter());
364 ASSERT_EQ(expected_command, m_commands_handler.last_command());
365 ASSERT_EQ(in_data, m_commands_handler.last_in_buf());
369 std::string send_data = conn->last_send_data();
372 ASSERT_LT(
sizeof(resp_head), send_data.size());
373 std::string out_data = send_data.substr(
sizeof(resp_head));
386TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_processes_handle_read_as_notify)
389 const int expected_command = 4673261;
391 test_connection_ptr conn = create_connection();
393 std::string in_data(256,
'e');
397 req_head.
m_cb = in_data.size();
403 std::string
buf(
reinterpret_cast<const char*
>(&req_head),
sizeof(req_head));
410 ASSERT_EQ(1, m_commands_handler.notify_counter());
411 ASSERT_EQ(0, m_commands_handler.invoke_counter());
412 ASSERT_EQ(expected_command, m_commands_handler.last_command());
413 ASSERT_EQ(in_data, m_commands_handler.last_in_buf());
418TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_processes_qued_callback)
420 test_connection_ptr conn = create_connection();
422 conn->m_protocol_handler.handle_qued_callback();
423 conn->m_protocol_handler.handle_qued_callback();
424 conn->m_protocol_handler.handle_qued_callback();
426 ASSERT_EQ(3, m_commands_handler.callback_counter());
429TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_big_packet_1)
431 std::string
buf(
"yyyyyy");
432 ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(
buf.data(), max_packet_size + 1));
435TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_big_packet_2)
438 const size_t first_packet_size =
sizeof(m_req_head) - 1;
440 m_buf.resize(first_packet_size);
441 ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size()));
443 ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), max_packet_size - m_buf.size() + 1));
446TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_invalid_signature_for_full_header)
451 ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size()));
454TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_invalid_signature_for_partial_header)
458 m_buf.resize(
sizeof(m_req_head.m_signature));
460 ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size()));
463TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_big_cb)
465 m_req_head.m_cb = max_packet_size + 1;
468 ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size()));
471TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, does_not_handle_data_after_close)
476 ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size()));
479TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_network_error)
483 m_conn->send_return(
false);
484 ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size()));
487TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_chunked_header)
491 size_t buf1_size =
sizeof(m_req_head) / 2;
493 std::string buf1 = m_buf.substr(0, buf1_size);
494 std::string buf2 = m_buf.substr(buf1_size);
497 ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(buf1.data(), buf1.size()));
498 ASSERT_EQ(0, m_commands_handler.invoke_counter());
500 ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(buf2.data(), buf2.size()));
501 ASSERT_EQ(1, m_commands_handler.invoke_counter());
505TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_chunked_body)
509 size_t buf1_size =
sizeof(m_req_head) + (m_buf.size() -
sizeof(m_req_head)) / 2;
511 std::string buf1 = m_buf.substr(0, buf1_size);
512 std::string buf2 = m_buf.substr(buf1_size);
515 ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(buf1.data(), buf1.size()));
516 ASSERT_EQ(0, m_commands_handler.invoke_counter());
518 ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(buf2.data(), buf2.size()));
519 ASSERT_EQ(1, m_commands_handler.invoke_counter());
522TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_two_requests_at_once)
527 ASSERT_TRUE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size()));
528 ASSERT_EQ(2, m_commands_handler.invoke_counter());
531TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_unexpected_response)
536 ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size()));
constexpr std::size_t size() const noexcept
constexpr pointer data() const noexcept
#define TEST_F(test_fixture, test_name)
#define ASSERT_EQ(val1, val2)
#define ASSERT_LE(val1, val2)
#define ASSERT_FALSE(condition)
#define ASSERT_TRUE(condition)
#define ASSERT_LT(val1, val2)
#define LEVIN_PACKET_RESPONSE
#define LEVIN_PROTOCOL_VER_1
#define LEVIN_PACKET_REQUEST
epee::levin::async_protocol_handler_config< test_connection_context > test_levin_protocol_handler_config
epee::net_utils::connection< test_levin_protocol_handler > test_connection
epee::levin::async_protocol_handler< test_connection_context > test_levin_protocol_handler
unsigned __int64 uint64_t
uint32_t m_protocol_version
bool m_have_to_return_data