dncurrency/nano/core_test/ipc.cpp
Dimitrios Siganos 78631a6b1c
Move test code into namespace nano::test (#3890)
* Move nano::establish_tcp into nano::test namespace
* Move system.hpp declarations into namespace nano::test
* Move telemetry test code to namespace nano::test
* Move testutil declarations into namespace nano::test
2022-08-10 20:48:31 +01:00

207 lines
No EOL
6.5 KiB
C++

#include <nano/lib/ipc_client.hpp>
#include <nano/lib/tomlconfig.hpp>
#include <nano/node/ipc/ipc_access_config.hpp>
#include <nano/node/ipc/ipc_server.hpp>
#include <nano/rpc/rpc.hpp>
#include <nano/test_common/system.hpp>
#include <nano/test_common/testutil.hpp>
#include <gtest/gtest.h>
#include <boost/property_tree/json_parser.hpp>
#include <chrono>
#include <memory>
#include <sstream>
#include <vector>
using namespace std::chrono_literals;
TEST (ipc, asynchronous)
{
nano::test::system system (1);
system.nodes[0]->config.ipc_config.transport_tcp.enabled = true;
system.nodes[0]->config.ipc_config.transport_tcp.port = 24077;
nano::node_rpc_config node_rpc_config;
nano::ipc::ipc_server ipc (*system.nodes[0], node_rpc_config);
nano::ipc::ipc_client client (system.nodes[0]->io_ctx);
auto req (nano::ipc::prepare_request (nano::ipc::payload_encoding::json_v1, std::string (R"({"action": "block_count"})")));
auto res (std::make_shared<std::vector<uint8_t>> ());
std::atomic<bool> call_completed{ false };
client.async_connect ("::1", 24077, [&client, &req, &res, &call_completed] (nano::error err) {
client.async_write (req, [&client, &req, &res, &call_completed] (nano::error err_a, size_t size_a) {
ASSERT_NO_ERROR (static_cast<std::error_code> (err_a));
ASSERT_EQ (size_a, req.size ());
// Read length
client.async_read (res, sizeof (uint32_t), [&client, &res, &call_completed] (nano::error err_read_a, size_t size_read_a) {
ASSERT_NO_ERROR (static_cast<std::error_code> (err_read_a));
ASSERT_EQ (size_read_a, sizeof (uint32_t));
uint32_t payload_size_l = boost::endian::big_to_native (*reinterpret_cast<uint32_t *> (res->data ()));
// Read json payload
client.async_read (res, payload_size_l, [&res, &call_completed] (nano::error err_read_a, size_t size_read_a) {
std::string payload (res->begin (), res->end ());
std::stringstream ss;
ss << payload;
// Make sure the response is valid json
boost::property_tree::ptree blocks;
boost::property_tree::read_json (ss, blocks);
ASSERT_EQ (blocks.get<int> ("count"), 1);
call_completed = true;
});
});
});
});
ASSERT_TIMELY (5s, call_completed);
ipc.stop ();
}
TEST (ipc, synchronous)
{
nano::test::system system (1);
system.nodes[0]->config.ipc_config.transport_tcp.enabled = true;
system.nodes[0]->config.ipc_config.transport_tcp.port = 24077;
nano::node_rpc_config node_rpc_config;
nano::ipc::ipc_server ipc (*system.nodes[0], node_rpc_config);
nano::ipc::ipc_client client (system.nodes[0]->io_ctx);
// Start blocking IPC client in a separate thread
std::atomic<bool> call_completed{ false };
std::thread client_thread ([&client, &call_completed] () {
client.connect ("::1", 24077);
std::string response (nano::ipc::request (nano::ipc::payload_encoding::json_v1, client, std::string (R"({"action": "block_count"})")));
std::stringstream ss;
ss << response;
// Make sure the response is valid json
boost::property_tree::ptree blocks;
boost::property_tree::read_json (ss, blocks);
ASSERT_EQ (blocks.get<int> ("count"), 1);
call_completed = true;
});
client_thread.detach ();
ASSERT_TIMELY (5s, call_completed);
ipc.stop ();
}
TEST (ipc, permissions_default_user)
{
// Test empty/nonexistant access config. The default user still exists with default permissions.
std::stringstream ss;
ss << R"toml(
)toml";
nano::tomlconfig toml;
toml.read (ss);
nano::ipc::access access;
access.deserialize_toml (toml);
ASSERT_TRUE (access.has_access ("", nano::ipc::access_permission::api_account_weight));
}
TEST (ipc, permissions_deny_default)
{
// All users have api_account_weight permissions by default. This removes the permission for a specific user.
std::stringstream ss;
ss << R"toml(
[[user]]
id = "user1"
deny = "api_account_weight"
)toml";
nano::tomlconfig toml;
toml.read (ss);
nano::ipc::access access;
access.deserialize_toml (toml);
ASSERT_FALSE (access.has_access ("user1", nano::ipc::access_permission::api_account_weight));
}
TEST (ipc, permissions_groups)
{
// Make sure role permissions are adopted by user
std::stringstream ss;
ss << R"toml(
[[role]]
id = "mywalletadmin"
allow = "wallet_read, wallet_write"
[[user]]
id = "user1"
roles = "mywalletadmin"
deny = "api_account_weight"
)toml";
nano::tomlconfig toml;
toml.read (ss);
nano::ipc::access access;
access.deserialize_toml (toml);
ASSERT_FALSE (access.has_access ("user1", nano::ipc::access_permission::api_account_weight));
ASSERT_TRUE (access.has_access_to_all ("user1", { nano::ipc::access_permission::wallet_read, nano::ipc::access_permission::wallet_write }));
}
TEST (ipc, permissions_oneof)
{
// Test one of two permissions
std::stringstream ss;
ss << R"toml(
[[user]]
id = "user1"
allow = "api_account_weight"
[[user]]
id = "user2"
allow = "api_account_weight, account_query"
[[user]]
id = "user3"
deny = "api_account_weight, account_query"
)toml";
nano::tomlconfig toml;
toml.read (ss);
nano::ipc::access access;
access.deserialize_toml (toml);
ASSERT_TRUE (access.has_access ("user1", nano::ipc::access_permission::api_account_weight));
ASSERT_TRUE (access.has_access ("user2", nano::ipc::access_permission::api_account_weight));
ASSERT_FALSE (access.has_access ("user3", nano::ipc::access_permission::api_account_weight));
ASSERT_TRUE (access.has_access_to_oneof ("user1", { nano::ipc::access_permission::account_query, nano::ipc::access_permission::api_account_weight }));
ASSERT_TRUE (access.has_access_to_oneof ("user2", { nano::ipc::access_permission::account_query, nano::ipc::access_permission::api_account_weight }));
ASSERT_FALSE (access.has_access_to_oneof ("user3", { nano::ipc::access_permission::account_query, nano::ipc::access_permission::api_account_weight }));
}
TEST (ipc, permissions_default_user_order)
{
// If changing the default user, it must come first
std::stringstream ss;
ss << R"toml(
[[user]]
id = "user1"
[[user]]
id = ""
)toml";
nano::tomlconfig toml;
toml.read (ss);
nano::ipc::access access;
ASSERT_TRUE (access.deserialize_toml (toml));
}
TEST (ipc, invalid_endpoint)
{
nano::test::system system (1);
system.nodes[0]->config.ipc_config.transport_tcp.enabled = true;
system.nodes[0]->config.ipc_config.transport_tcp.port = 24077;
nano::node_rpc_config node_rpc_config;
nano::ipc::ipc_client client (system.nodes[0]->io_ctx);
std::atomic<bool> call_completed{ false };
client.async_connect ("::-1", 24077, [&client, &call_completed] (nano::error err) {
ASSERT_IS_ERROR (static_cast<std::error_code> (err));
call_completed = true;
});
ASSERT_TIMELY (5s, call_completed);
}