Skip to content

Commit

Permalink
Move tcp_listener test into a single file
Browse files Browse the repository at this point in the history
  • Loading branch information
pwojcikdev committed Dec 10, 2024
1 parent 3da2dbd commit c6c1256
Show file tree
Hide file tree
Showing 4 changed files with 292 additions and 274 deletions.
1 change: 1 addition & 0 deletions nano/core_test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ add_executable(
signal_manager.cpp
socket.cpp
system.cpp
tcp_listener.cpp
telemetry.cpp
thread_pool.cpp
throttle.cpp
Expand Down
84 changes: 0 additions & 84 deletions nano/core_test/network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,90 +547,6 @@ TEST (network, endpoint_bad_fd)
ASSERT_TIMELY_EQ (10s, system.nodes[0]->network.endpoint ().port (), 0);
}

TEST (tcp_listener, tcp_node_id_handshake)
{
nano::test::system system (1);
auto socket (std::make_shared<nano::transport::tcp_socket> (*system.nodes[0]));
auto bootstrap_endpoint (system.nodes[0]->tcp_listener.endpoint ());
auto cookie (system.nodes[0]->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (bootstrap_endpoint)));
ASSERT_TRUE (cookie);
nano::node_id_handshake::query_payload query{ *cookie };
nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, query };
auto input (node_id_handshake.to_shared_const_buffer ());
std::atomic<bool> write_done (false);
socket->async_connect (bootstrap_endpoint, [&input, socket, &write_done] (boost::system::error_code const & ec) {
ASSERT_FALSE (ec);
socket->async_write (input, [&input, &write_done] (boost::system::error_code const & ec, size_t size_a) {
ASSERT_FALSE (ec);
ASSERT_EQ (input.size (), size_a);
write_done = true;
});
});

ASSERT_TIMELY (5s, write_done);

nano::node_id_handshake::response_payload response_zero{ 0 };
nano::node_id_handshake node_id_handshake_response{ nano::dev::network_params.network, std::nullopt, response_zero };
auto output (node_id_handshake_response.to_bytes ());
std::atomic<bool> done (false);
socket->async_read (output, output->size (), [&output, &done] (boost::system::error_code const & ec, size_t size_a) {
ASSERT_FALSE (ec);
ASSERT_EQ (output->size (), size_a);
done = true;
});
ASSERT_TIMELY (5s, done);
}

// Test disabled because it's failing intermittently.
// PR in which it got disabled: https://github.com/nanocurrency/nano-node/pull/3611
// Issue for investigating it: https://github.com/nanocurrency/nano-node/issues/3615
TEST (tcp_listener, DISABLED_tcp_listener_timeout_empty)
{
nano::test::system system (1);
auto node0 (system.nodes[0]);
auto socket (std::make_shared<nano::transport::tcp_socket> (*node0));
std::atomic<bool> connected (false);
socket->async_connect (node0->tcp_listener.endpoint (), [&connected] (boost::system::error_code const & ec) {
ASSERT_FALSE (ec);
connected = true;
});
ASSERT_TIMELY (5s, connected);
bool disconnected (false);
system.deadline_set (std::chrono::seconds (6));
while (!disconnected)
{
disconnected = node0->tcp_listener.connection_count () == 0;
ASSERT_NO_ERROR (system.poll ());
}
}

TEST (tcp_listener, tcp_listener_timeout_node_id_handshake)
{
nano::test::system system (1);
auto node0 (system.nodes[0]);
auto socket (std::make_shared<nano::transport::tcp_socket> (*node0));
auto cookie (node0->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (node0->tcp_listener.endpoint ())));
ASSERT_TRUE (cookie);
nano::node_id_handshake::query_payload query{ *cookie };
nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, query };
auto channel = std::make_shared<nano::transport::tcp_channel> (*node0, socket);
socket->async_connect (node0->tcp_listener.endpoint (), [&node_id_handshake, channel] (boost::system::error_code const & ec) {
ASSERT_FALSE (ec);
channel->send (node_id_handshake, [] (boost::system::error_code const & ec, size_t size_a) {
ASSERT_FALSE (ec);
});
});
ASSERT_TIMELY (5s, node0->stats.count (nano::stat::type::tcp_server, nano::stat::detail::node_id_handshake) != 0);
ASSERT_EQ (node0->tcp_listener.connection_count (), 1);
bool disconnected (false);
system.deadline_set (std::chrono::seconds (20));
while (!disconnected)
{
disconnected = node0->tcp_listener.connection_count () == 0;
ASSERT_NO_ERROR (system.poll ());
}
}

// Test disabled because it's failing repeatedly for Windows + LMDB.
// PR in which it got disabled: https://github.com/nanocurrency/nano-node/pull/3622
// Issue for investigating it: https://github.com/nanocurrency/nano-node/issues/3621
Expand Down
190 changes: 0 additions & 190 deletions nano/core_test/socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,196 +75,6 @@ TEST (socket_functions, count_subnetwork_connections)
ASSERT_EQ (4, nano::transport::socket_functions::count_subnetwork_connections (connections_per_address, address1.to_v6 (), 32));
}

TEST (tcp_listener, max_connections)
{
nano::test::system system;

nano::node_flags node_flags;
nano::node_config node_config = system.default_config ();
node_config.tcp.max_inbound_connections = 2;
auto node = system.add_node (node_config, node_flags);

// client side connection tracking
std::atomic<size_t> connection_attempts = 0;
auto connect_handler = [&connection_attempts] (boost::system::error_code const & ec_a) {
ASSERT_EQ (ec_a.value (), 0);
++connection_attempts;
};

// start 3 clients, 2 will persist but 1 will be dropped
auto client1 = std::make_shared<nano::transport::tcp_socket> (*node);
client1->async_connect (node->network.endpoint (), connect_handler);

auto client2 = std::make_shared<nano::transport::tcp_socket> (*node);
client2->async_connect (node->network.endpoint (), connect_handler);

auto client3 = std::make_shared<nano::transport::tcp_socket> (*node);
client3->async_connect (node->network.endpoint (), connect_handler);

ASSERT_TIMELY_EQ (5s, node->stats.count (nano::stat::type::tcp_listener, nano::stat::detail::accept_success), 2);
ASSERT_ALWAYS_EQ (1s, node->stats.count (nano::stat::type::tcp_listener, nano::stat::detail::accept_success), 2);
ASSERT_TIMELY_EQ (5s, connection_attempts, 3);

// create space for one socket and fill the connections table again
{
auto sockets1 = node->tcp_listener.sockets ();
ASSERT_EQ (sockets1.size (), 2);
sockets1[0]->close ();
}
ASSERT_TIMELY_EQ (10s, node->tcp_listener.sockets ().size (), 1);

auto client4 = std::make_shared<nano::transport::tcp_socket> (*node);
client4->async_connect (node->network.endpoint (), connect_handler);

auto client5 = std::make_shared<nano::transport::tcp_socket> (*node);
client5->async_connect (node->network.endpoint (), connect_handler);

ASSERT_TIMELY_EQ (5s, node->stats.count (nano::stat::type::tcp_listener, nano::stat::detail::accept_success), 3);
ASSERT_ALWAYS_EQ (1s, node->stats.count (nano::stat::type::tcp_listener, nano::stat::detail::accept_success), 3);
ASSERT_TIMELY_EQ (5s, connection_attempts, 5);

// close all existing sockets and fill the connections table again
{
auto sockets2 = node->tcp_listener.sockets ();
ASSERT_EQ (sockets2.size (), 2);
sockets2[0]->close ();
sockets2[1]->close ();
}
ASSERT_TIMELY_EQ (10s, node->tcp_listener.sockets ().size (), 0);

auto client6 = std::make_shared<nano::transport::tcp_socket> (*node);
client6->async_connect (node->network.endpoint (), connect_handler);

auto client7 = std::make_shared<nano::transport::tcp_socket> (*node);
client7->async_connect (node->network.endpoint (), connect_handler);

auto client8 = std::make_shared<nano::transport::tcp_socket> (*node);
client8->async_connect (node->network.endpoint (), connect_handler);

ASSERT_TIMELY_EQ (5s, node->stats.count (nano::stat::type::tcp_listener, nano::stat::detail::accept_success), 5);
ASSERT_ALWAYS_EQ (1s, node->stats.count (nano::stat::type::tcp_listener, nano::stat::detail::accept_success), 5);
ASSERT_TIMELY_EQ (5s, connection_attempts, 8); // connections initiated by the client
}

TEST (tcp_listener, max_connections_per_ip)
{
nano::test::system system;

nano::node_flags node_flags;
nano::node_config node_config = system.default_config ();
node_config.network.max_peers_per_ip = 3;
auto node = system.add_node (node_config, node_flags);
ASSERT_FALSE (node->flags.disable_max_peers_per_ip);

auto server_port = system.get_available_port ();

const auto max_ip_connections = node->config.network.max_peers_per_ip;
ASSERT_GE (max_ip_connections, 1);

// client side connection tracking
std::atomic<size_t> connection_attempts = 0;
auto connect_handler = [&connection_attempts] (boost::system::error_code const & ec_a) {
ASSERT_EQ (ec_a.value (), 0);
++connection_attempts;
};

// start n clients, n-1 will persist but 1 will be dropped, where n == max_ip_connections
std::vector<std::shared_ptr<nano::transport::tcp_socket>> client_list;
client_list.reserve (max_ip_connections + 1);

for (auto idx = 0; idx < max_ip_connections + 1; ++idx)
{
auto client = std::make_shared<nano::transport::tcp_socket> (*node);
client->async_connect (node->network.endpoint (), connect_handler);
client_list.push_back (client);
}

ASSERT_TIMELY_EQ (5s, node->stats.count (nano::stat::type::tcp_listener, nano::stat::detail::accept_success), max_ip_connections);
ASSERT_TIMELY_EQ (5s, node->stats.count (nano::stat::type::tcp_listener_rejected, nano::stat::detail::max_per_ip), 1);
ASSERT_TIMELY_EQ (5s, connection_attempts, max_ip_connections + 1);
}

TEST (tcp_listener, max_connections_per_subnetwork)
{
nano::test::system system;

nano::node_flags node_flags;
// disabling IP limit because it will be used the same IP address to check they come from the same subnetwork.
node_flags.disable_max_peers_per_ip = true;
node_flags.disable_max_peers_per_subnetwork = false;
nano::node_config node_config = system.default_config ();
node_config.network.max_peers_per_subnetwork = 3;
auto node = system.add_node (node_config, node_flags);

ASSERT_TRUE (node->flags.disable_max_peers_per_ip);
ASSERT_FALSE (node->flags.disable_max_peers_per_subnetwork);

const auto max_subnetwork_connections = node->config.network.max_peers_per_subnetwork;
ASSERT_GE (max_subnetwork_connections, 1);

// client side connection tracking
std::atomic<size_t> connection_attempts = 0;
auto connect_handler = [&connection_attempts] (boost::system::error_code const & ec_a) {
ASSERT_EQ (ec_a.value (), 0);
++connection_attempts;
};

// start n clients, n-1 will persist but 1 will be dropped, where n == max_subnetwork_connections
std::vector<std::shared_ptr<nano::transport::tcp_socket>> client_list;
client_list.reserve (max_subnetwork_connections + 1);

for (auto idx = 0; idx < max_subnetwork_connections + 1; ++idx)
{
auto client = std::make_shared<nano::transport::tcp_socket> (*node);
client->async_connect (node->network.endpoint (), connect_handler);
client_list.push_back (client);
}

ASSERT_TIMELY_EQ (5s, node->stats.count (nano::stat::type::tcp_listener, nano::stat::detail::accept_success), max_subnetwork_connections);
ASSERT_TIMELY_EQ (5s, node->stats.count (nano::stat::type::tcp_listener_rejected, nano::stat::detail::max_per_subnetwork), 1);
ASSERT_TIMELY_EQ (5s, connection_attempts, max_subnetwork_connections + 1);
}

TEST (tcp_listener, max_peers_per_ip)
{
nano::test::system system;

nano::node_flags node_flags;
node_flags.disable_max_peers_per_ip = true;
nano::node_config node_config = system.default_config ();
node_config.network.max_peers_per_ip = 3;
auto node = system.add_node (node_config, node_flags);

ASSERT_TRUE (node->flags.disable_max_peers_per_ip);

auto server_port = system.get_available_port ();

const auto max_ip_connections = node->config.network.max_peers_per_ip;
ASSERT_GE (max_ip_connections, 1);

// client side connection tracking
std::atomic<size_t> connection_attempts = 0;
auto connect_handler = [&connection_attempts] (boost::system::error_code const & ec_a) {
ASSERT_EQ (ec_a.value (), 0);
++connection_attempts;
};

// start n clients, n-1 will persist but 1 will be dropped, where n == max_ip_connections
std::vector<std::shared_ptr<nano::transport::tcp_socket>> client_list;
client_list.reserve (max_ip_connections + 1);

for (auto idx = 0; idx < max_ip_connections + 1; ++idx)
{
auto client = std::make_shared<nano::transport::tcp_socket> (*node);
client->async_connect (node->network.endpoint (), connect_handler);
client_list.push_back (client);
}

ASSERT_TIMELY_EQ (5s, node->stats.count (nano::stat::type::tcp_listener, nano::stat::detail::accept_success), max_ip_connections + 1);
ASSERT_TIMELY_EQ (5s, node->stats.count (nano::stat::type::tcp_listener_rejected, nano::stat::detail::max_per_ip), 0);
ASSERT_TIMELY_EQ (5s, connection_attempts, max_ip_connections + 1);
}

TEST (socket, disconnection_of_silent_connections)
{
nano::test::system system;
Expand Down
Loading

0 comments on commit c6c1256

Please sign in to comment.