Migrate tests from the old message_parser to test the message_deserializer class (#4166)

* Replace message_parser test for confirm_ack to test message_deserializer

The old test checked the bytes generated the same confirm_ack object by
ensuring its visitor was processed only once. Also verified the
parse_status was success. In the new implementation the visitor isn't
part of the deserializer. The outcome object is compared to the
original, and the parse_status should be success. This is the sanity
test, where the deserialization is expected to happen successfully.

Also checks if the message pointer can be downcast to the proper type,
that is the same of verifying its type is supported.

* Move message_parser confirm_req tests to the message_deserializer format

* Move message_parser publish test to the message_deserializer format

* Move message_parser keepalive test to the message_deserializer format

* Remove the dev_visitor class

* Add message_deserialize tests for all the remaining message types

* Add more comments to the message_deserializer_success_checker function

* Update the file name to core_test/message_deserializer.cpp
This commit is contained in:
Thiago Silva 2023-03-07 12:48:57 -03:00 committed by GitHub
commit 955c79e664
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 224 additions and 259 deletions

View file

@ -28,7 +28,7 @@ add_executable(
locks.cpp
logger.cpp
message.cpp
message_parser.cpp
message_deserializer.cpp
memory_pool.cpp
network.cpp
network_filter.cpp

View file

@ -0,0 +1,223 @@
#include <nano/node/transport/message_deserializer.hpp>
#include <nano/test_common/system.hpp>
#include <nano/test_common/testutil.hpp>
#include <gtest/gtest.h>
#include <boost/none.hpp>
#include <memory>
#include <vector>
// Test the successful cases for message_deserializer, checking the supported message types and
// the integrity of the deserialized outcome.
template <class message_type>
auto message_deserializer_success_checker (message_type & message_original) -> void
{
// Dependencies for the message deserializer.
nano::network_filter filter (1);
nano::block_uniquer block_uniquer;
nano::vote_uniquer vote_uniquer (block_uniquer);
// Data used to simulate the incoming buffer to be deserialized, the offset tracks how much has been read from the input_source
// as the read function is called first to read the header, then called again to read the payload.
std::vector<uint8_t> input_source;
auto offset = 0u;
// Message Deserializer with the query function tweaked to read from the `input_source`.
auto const message_deserializer = std::make_shared<nano::transport::message_deserializer> (nano::dev::network_params.network, filter, block_uniquer, vote_uniquer,
[&input_source, &offset] (std::shared_ptr<std::vector<uint8_t>> const & data_a, size_t size_a, std::function<void (boost::system::error_code const &, std::size_t)> callback_a) {
debug_assert (input_source.size () >= size_a);
data_a->resize (size_a);
auto const copy_start = input_source.begin () + offset;
std::copy (copy_start, copy_start + size_a, data_a->data ());
offset += size_a;
callback_a (boost::system::errc::make_error_code (boost::system::errc::success), size_a);
});
// Generating the values for the `input_source`.
{
nano::vectorstream stream (input_source);
message_original.serialize (stream);
}
// Deserializing and testing the success path.
message_deserializer->read (
[&message_original] (boost::system::error_code ec_a, std::unique_ptr<nano::message> message_a) {
auto deserialized_message = dynamic_cast<message_type *> (message_a.get ());
// Ensure the message type is supported.
ASSERT_NE (deserialized_message, nullptr);
auto deserialized_bytes = deserialized_message->to_bytes ();
auto original_bytes = message_original.to_bytes ();
// Ensure the integrity of the deserialized message.
ASSERT_EQ (*deserialized_bytes, *original_bytes);
});
// This is a sanity test, to ensure the successful deserialization case passes.
ASSERT_EQ (message_deserializer->status, nano::transport::message_deserializer::parse_status::success);
}
TEST (message_deserializer, exact_confirm_ack)
{
nano::test::system system{ 1 };
nano::block_builder builder;
auto block = builder
.send ()
.previous (1)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (*system.work.generate (nano::root (1)))
.build_shared ();
auto vote (std::make_shared<nano::vote> (0, nano::keypair ().prv, 0, 0, std::vector<nano::block_hash>{ block->hash () }));
nano::confirm_ack message{ nano::dev::network_params.network, vote };
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_confirm_req)
{
nano::test::system system{ 1 };
nano::block_builder builder;
auto block = builder
.send ()
.previous (1)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (*system.work.generate (nano::root (1)))
.build_shared ();
nano::confirm_req message{ nano::dev::network_params.network, block };
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_confirm_req_hash)
{
nano::test::system system{ 1 };
nano::block_builder builder;
auto block = builder
.send ()
.previous (1)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (*system.work.generate (nano::root (1)))
.build ();
// This test differs from the previous `exact_confirm_req` because this tests the confirm_req created from the block hash.
nano::confirm_req message{ nano::dev::network_params.network, block->hash (), block->root () };
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_publish)
{
nano::test::system system{ 1 };
nano::block_builder builder;
auto block = builder
.send ()
.previous (1)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (*system.work.generate (nano::root (1)))
.build_shared ();
nano::publish message{ nano::dev::network_params.network, block };
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_keepalive)
{
nano::keepalive message{ nano::dev::network_params.network };
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_frontier_req)
{
nano::frontier_req message{ nano::dev::network_params.network };
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_telemetry_req)
{
nano::telemetry_req message{ nano::dev::network_params.network };
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_telemetry_ack)
{
nano::telemetry_data data;
data.unknown_data.push_back (0xFF);
nano::telemetry_ack message{ nano::dev::network_params.network, data };
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_bulk_pull)
{
nano::bulk_pull message{ nano::dev::network_params.network };
message.header.flag_set (nano::message_header::bulk_pull_ascending_flag);
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_bulk_pull_account)
{
nano::bulk_pull_account message{ nano::dev::network_params.network };
message.flags = nano::bulk_pull_account_flags::pending_address_only;
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_bulk_push)
{
nano::bulk_push message{ nano::dev::network_params.network };
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_node_id_handshake)
{
nano::node_id_handshake message{ nano::dev::network_params.network, boost::none, boost::none };
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_asc_pull_req)
{
nano::asc_pull_req message{ nano::dev::network_params.network };
// The asc_pull_req checks for the message fields and the payload to be filled.
message.id = 7;
message.type = nano::asc_pull_type::account_info;
nano::asc_pull_req::account_info_payload message_payload;
message_payload.target = nano::test::random_account ();
message_payload.target_type = nano::asc_pull_req::hash_type::account;
message.payload = message_payload;
message.update_header ();
message_deserializer_success_checker<decltype (message)> (message);
}
TEST (message_deserializer, exact_asc_pull_ack)
{
nano::asc_pull_ack message{ nano::dev::network_params.network };
// The asc_pull_ack checks for the message fields and the payload to be filled.
message.id = 11;
message.type = nano::asc_pull_type::account_info;
nano::asc_pull_ack::account_info_payload message_payload;
message_payload.account = nano::test::random_account ();
message_payload.account_open = nano::test::random_hash ();
message_payload.account_head = nano::test::random_hash ();
message_payload.account_block_count = 932932132;
message_payload.account_conf_frontier = nano::test::random_hash ();
message_payload.account_conf_height = 847312;
message.payload = message_payload;
message.update_header ();
message_deserializer_success_checker<decltype (message)> (message);
}

View file

@ -1,258 +0,0 @@
#include <nano/test_common/system.hpp>
#include <nano/test_common/testutil.hpp>
#include <gtest/gtest.h>
namespace
{
class dev_visitor : public nano::message_visitor
{
public:
void keepalive (nano::keepalive const &) override
{
++keepalive_count;
}
void publish (nano::publish const &) override
{
++publish_count;
}
void confirm_req (nano::confirm_req const &) override
{
++confirm_req_count;
}
void confirm_ack (nano::confirm_ack const &) override
{
++confirm_ack_count;
}
void bulk_pull (nano::bulk_pull const &) override
{
ASSERT_FALSE (true);
}
void bulk_pull_account (nano::bulk_pull_account const &) override
{
ASSERT_FALSE (true);
}
void bulk_push (nano::bulk_push const &) override
{
ASSERT_FALSE (true);
}
void frontier_req (nano::frontier_req const &) override
{
ASSERT_FALSE (true);
}
void node_id_handshake (nano::node_id_handshake const &) override
{
ASSERT_FALSE (true);
}
void telemetry_req (nano::telemetry_req const &) override
{
ASSERT_FALSE (true);
}
void telemetry_ack (nano::telemetry_ack const &) override
{
ASSERT_FALSE (true);
}
uint64_t keepalive_count{ 0 };
uint64_t publish_count{ 0 };
uint64_t confirm_req_count{ 0 };
uint64_t confirm_ack_count{ 0 };
};
}
TEST (message_parser, exact_confirm_ack_size)
{
nano::test::system system (1);
dev_visitor visitor;
nano::network_filter filter (1);
nano::block_uniquer block_uniquer;
nano::vote_uniquer vote_uniquer (block_uniquer);
nano::message_parser parser (filter, block_uniquer, vote_uniquer, visitor, system.work, nano::dev::network_params.network);
nano::block_builder builder;
auto block = builder
.send ()
.previous (1)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (*system.work.generate (nano::root (1)))
.build_shared ();
auto vote (std::make_shared<nano::vote> (0, nano::keypair ().prv, 0, 0, std::vector<nano::block_hash>{ block->hash () }));
nano::confirm_ack message{ nano::dev::network_params.network, vote };
std::vector<uint8_t> bytes;
{
nano::vectorstream stream (bytes);
message.serialize (stream);
}
ASSERT_EQ (0, visitor.confirm_ack_count);
ASSERT_EQ (parser.status, nano::message_parser::parse_status::success);
auto error (false);
nano::bufferstream stream1 (bytes.data (), bytes.size ());
nano::message_header header1 (error, stream1);
ASSERT_FALSE (error);
parser.deserialize_confirm_ack (stream1, header1);
ASSERT_EQ (1, visitor.confirm_ack_count);
ASSERT_EQ (parser.status, nano::message_parser::parse_status::success);
bytes.push_back (0);
nano::bufferstream stream2 (bytes.data (), bytes.size ());
nano::message_header header2 (error, stream2);
ASSERT_FALSE (error);
parser.deserialize_confirm_ack (stream2, header2);
ASSERT_EQ (1, visitor.confirm_ack_count);
ASSERT_NE (parser.status, nano::message_parser::parse_status::success);
}
TEST (message_parser, exact_confirm_req_size)
{
nano::test::system system (1);
dev_visitor visitor;
nano::network_filter filter (1);
nano::block_uniquer block_uniquer;
nano::vote_uniquer vote_uniquer (block_uniquer);
nano::message_parser parser (filter, block_uniquer, vote_uniquer, visitor, system.work, nano::dev::network_params.network);
nano::block_builder builder;
auto block = builder
.send ()
.previous (1)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (*system.work.generate (nano::root (1)))
.build_shared ();
nano::confirm_req message{ nano::dev::network_params.network, block };
std::vector<uint8_t> bytes;
{
nano::vectorstream stream (bytes);
message.serialize (stream);
}
ASSERT_EQ (0, visitor.confirm_req_count);
ASSERT_EQ (parser.status, nano::message_parser::parse_status::success);
auto error (false);
nano::bufferstream stream1 (bytes.data (), bytes.size ());
nano::message_header header1 (error, stream1);
ASSERT_FALSE (error);
parser.deserialize_confirm_req (stream1, header1);
ASSERT_EQ (1, visitor.confirm_req_count);
ASSERT_EQ (parser.status, nano::message_parser::parse_status::success);
bytes.push_back (0);
nano::bufferstream stream2 (bytes.data (), bytes.size ());
nano::message_header header2 (error, stream2);
ASSERT_FALSE (error);
parser.deserialize_confirm_req (stream2, header2);
ASSERT_EQ (1, visitor.confirm_req_count);
ASSERT_NE (parser.status, nano::message_parser::parse_status::success);
}
TEST (message_parser, exact_confirm_req_hash_size)
{
nano::test::system system (1);
dev_visitor visitor;
nano::network_filter filter (1);
nano::block_uniquer block_uniquer;
nano::vote_uniquer vote_uniquer (block_uniquer);
nano::message_parser parser (filter, block_uniquer, vote_uniquer, visitor, system.work, nano::dev::network_params.network);
nano::block_builder builder;
auto block = builder
.send ()
.previous (1)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (*system.work.generate (nano::root (1)))
.build ();
nano::confirm_req message{ nano::dev::network_params.network, block->hash (), block->root () };
std::vector<uint8_t> bytes;
{
nano::vectorstream stream (bytes);
message.serialize (stream);
}
ASSERT_EQ (0, visitor.confirm_req_count);
ASSERT_EQ (parser.status, nano::message_parser::parse_status::success);
auto error (false);
nano::bufferstream stream1 (bytes.data (), bytes.size ());
nano::message_header header1 (error, stream1);
ASSERT_FALSE (error);
parser.deserialize_confirm_req (stream1, header1);
ASSERT_EQ (1, visitor.confirm_req_count);
ASSERT_EQ (parser.status, nano::message_parser::parse_status::success);
bytes.push_back (0);
nano::bufferstream stream2 (bytes.data (), bytes.size ());
nano::message_header header2 (error, stream2);
ASSERT_FALSE (error);
parser.deserialize_confirm_req (stream2, header2);
ASSERT_EQ (1, visitor.confirm_req_count);
ASSERT_NE (parser.status, nano::message_parser::parse_status::success);
}
TEST (message_parser, exact_publish_size)
{
nano::test::system system (1);
dev_visitor visitor;
nano::network_filter filter (1);
nano::block_uniquer block_uniquer;
nano::vote_uniquer vote_uniquer (block_uniquer);
nano::message_parser parser (filter, block_uniquer, vote_uniquer, visitor, system.work, nano::dev::network_params.network);
nano::block_builder builder;
auto block = builder
.send ()
.previous (1)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (*system.work.generate (nano::root (1)))
.build_shared ();
nano::publish message{ nano::dev::network_params.network, block };
std::vector<uint8_t> bytes;
{
nano::vectorstream stream (bytes);
message.serialize (stream);
}
ASSERT_EQ (0, visitor.publish_count);
ASSERT_EQ (parser.status, nano::message_parser::parse_status::success);
auto error (false);
nano::bufferstream stream1 (bytes.data (), bytes.size ());
nano::message_header header1 (error, stream1);
ASSERT_FALSE (error);
parser.deserialize_publish (stream1, header1);
ASSERT_EQ (1, visitor.publish_count);
ASSERT_EQ (parser.status, nano::message_parser::parse_status::success);
bytes.push_back (0);
nano::bufferstream stream2 (bytes.data (), bytes.size ());
nano::message_header header2 (error, stream2);
ASSERT_FALSE (error);
parser.deserialize_publish (stream2, header2);
ASSERT_EQ (1, visitor.publish_count);
ASSERT_NE (parser.status, nano::message_parser::parse_status::success);
}
TEST (message_parser, exact_keepalive_size)
{
nano::test::system system (1);
dev_visitor visitor;
nano::network_filter filter (1);
nano::block_uniquer block_uniquer;
nano::vote_uniquer vote_uniquer (block_uniquer);
nano::message_parser parser (filter, block_uniquer, vote_uniquer, visitor, system.work, nano::dev::network_params.network);
nano::keepalive message{ nano::dev::network_params.network };
std::vector<uint8_t> bytes;
{
nano::vectorstream stream (bytes);
message.serialize (stream);
}
ASSERT_EQ (0, visitor.keepalive_count);
ASSERT_EQ (parser.status, nano::message_parser::parse_status::success);
auto error (false);
nano::bufferstream stream1 (bytes.data (), bytes.size ());
nano::message_header header1 (error, stream1);
ASSERT_FALSE (error);
parser.deserialize_keepalive (stream1, header1);
ASSERT_EQ (1, visitor.keepalive_count);
ASSERT_EQ (parser.status, nano::message_parser::parse_status::success);
bytes.push_back (0);
nano::bufferstream stream2 (bytes.data (), bytes.size ());
nano::message_header header2 (error, stream2);
ASSERT_FALSE (error);
parser.deserialize_keepalive (stream2, header2);
ASSERT_EQ (1, visitor.keepalive_count);
ASSERT_NE (parser.status, nano::message_parser::parse_status::success);
}