Skip to content

Commit

Permalink
rpcdaemon: refactoring ContextTestBase as infra test utility (#2127)
Browse files Browse the repository at this point in the history
  • Loading branch information
canepat authored Jun 19, 2024
1 parent 7c1720b commit adc984a
Show file tree
Hide file tree
Showing 42 changed files with 217 additions and 141 deletions.
1 change: 1 addition & 0 deletions cmd/benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ add_executable(benchmark_test benchmark_test.cpp ${SILKWORM_BENCHMARK_TESTS})
target_link_libraries(
benchmark_test
silkworm_infra
silkworm_infra_test_util
silkworm_node
silkworm_rpcdaemon
silkworm_rpcdaemon_test_util
Expand Down
2 changes: 2 additions & 0 deletions silkworm/core/common/base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ using BlockNum = uint64_t;
using BlockNumRange = std::pair<BlockNum, BlockNum>;
using BlockTime = uint64_t;

inline constexpr BlockNum kEarliestBlockNumber{0ul};

inline constexpr size_t kAddressLength{20};

inline constexpr size_t kHashLength{32};
Expand Down
35 changes: 35 additions & 0 deletions silkworm/infra/test_util/context_test_base.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
Copyright 2023 The Silkworm Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "context_test_base.hpp"

namespace silkworm::test_util {

ContextTestBase::ContextTestBase()
: log_guard_{log::Level::kNone},
context_{0},
io_context_{*context_.io_context()},
grpc_context_{*context_.grpc_context()},
context_thread_{[&]() { context_.execute_loop(); }} {}

ContextTestBase::~ContextTestBase() {
context_.stop();
if (context_thread_.joinable()) {
context_thread_.join();
}
}

} // namespace silkworm::test_util
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include <silkworm/infra/grpc/client/client_context_pool.hpp>
#include <silkworm/infra/test_util/log.hpp>

namespace silkworm::rpc::test {
namespace silkworm::test_util {

class ContextTestBase {
public:
Expand All @@ -50,10 +50,10 @@ class ContextTestBase {
~ContextTestBase();

silkworm::test_util::SetLogVerbosityGuard log_guard_;
ClientContext context_;
rpc::ClientContext context_;
boost::asio::io_context& io_context_;
agrpc::GrpcContext& grpc_context_;
std::thread context_thread_;
};

} // namespace silkworm::rpc::test
} // namespace silkworm::test_util
4 changes: 3 additions & 1 deletion silkworm/rpc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,6 @@ silkworm_library(
PRIVATE ${SILKWORM_RPCDAEMON_PRIVATE_LIBRARIES}
)

target_link_libraries(silkworm_rpcdaemon_test PRIVATE silkworm_rpcdaemon_test_util GTest::gmock)
target_link_libraries(
silkworm_rpcdaemon_test PRIVATE silkworm_infra_test_util silkworm_rpcdaemon_test_util GTest::gmock
)
6 changes: 3 additions & 3 deletions silkworm/rpc/commands/engine_api_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ class EngineRpcApi_ForTest : public EngineRpcApi {
using testing::_;
using testing::InvokeWithoutArgs;

struct EngineRpcApiTest : public test::JsonApiTestBase<EngineRpcApi_ForTest> {
EngineRpcApiTest() : test::JsonApiTestBase<EngineRpcApi_ForTest>() {
struct EngineRpcApiTest : public test_util::JsonApiTestBase<EngineRpcApi_ForTest> {
EngineRpcApiTest() : test_util::JsonApiTestBase<EngineRpcApi_ForTest>() {
add_private_service<ethdb::Database>(io_context_, std::make_unique<DummyDatabase>(mock_cursor));
add_shared_service<engine::ExecutionEngine>(io_context_, mock_engine);
add_private_service<ethbackend::BackEnd>(io_context_, std::make_unique<test::BackEndMock>());
}

std::shared_ptr<test::ExecutionEngineMock> mock_engine{std::make_shared<test::ExecutionEngineMock>()};
std::shared_ptr<test_util::ExecutionEngineMock> mock_engine{std::make_shared<test_util::ExecutionEngineMock>()};
std::shared_ptr<test::MockCursor> mock_cursor{std::make_shared<test::MockCursor>()};
};

Expand Down
5 changes: 3 additions & 2 deletions silkworm/rpc/commands/erigon_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <intx/intx.hpp>

#include <silkworm/core/common/base.hpp>
#include <silkworm/core/common/util.hpp>
#include <silkworm/core/protocol/ethash_rule_set.hpp>
#include <silkworm/core/types/evmc_bytes32.hpp>
Expand Down Expand Up @@ -127,7 +128,7 @@ Task<void> ErigonRpcApi::handle_erigon_get_block_by_timestamp(const nlohmann::js
const auto chain_storage = tx->create_storage();

// Lookup the first and last block headers
const auto first_header = co_await chain_storage->read_canonical_header(core::kEarliestBlockNumber);
const auto first_header = co_await chain_storage->read_canonical_header(kEarliestBlockNumber);
const auto head_header_hash = co_await core::rawdb::read_head_header_hash(*tx);
const auto header_header_block_number = co_await chain_storage->read_block_number(head_header_hash);
const auto current_header = co_await chain_storage->read_header(*header_header_block_number, head_header_hash);
Expand All @@ -138,7 +139,7 @@ Task<void> ErigonRpcApi::handle_erigon_get_block_by_timestamp(const nlohmann::js
if (current_header->timestamp <= timestamp) {
block_number = current_block_number;
} else if (first_header->timestamp >= timestamp) {
block_number = core::kEarliestBlockNumber;
block_number = kEarliestBlockNumber;
} else {
// Good-old binary search to find the lowest block header matching timestamp
auto matching_block_number = co_await binary_search(current_block_number, [&](uint64_t bn) -> Task<bool> {
Expand Down
2 changes: 1 addition & 1 deletion silkworm/rpc/commands/erigon_api_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ErigonRpcApi_ForTest : public ErigonRpcApi {
}
};

using ErigonRpcApiTest = test::JsonApiTestBase<ErigonRpcApi_ForTest>;
using ErigonRpcApiTest = test_util::JsonApiTestBase<ErigonRpcApi_ForTest>;

#ifndef SILKWORM_SANITIZE
TEST_CASE_METHOD(ErigonRpcApiTest, "ErigonRpcApi::handle_erigon_get_block_by_timestamp", "[rpc][erigon_api]") {
Expand Down
32 changes: 16 additions & 16 deletions silkworm/rpc/commands/eth_api_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,97 +24,97 @@
namespace silkworm::rpc::commands {

#ifndef SILKWORM_SANITIZE
TEST_CASE_METHOD(test::RpcApiE2ETest, "unit: eth_blockNumber succeeds if request well-formed", "[rpc][api]") {
TEST_CASE_METHOD(test_util::RpcApiE2ETest, "unit: eth_blockNumber succeeds if request well-formed", "[rpc][api]") {
const auto request = R"({"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]})"_json;
std::string reply;
run<&test::RequestHandler_ForTest::request_and_create_reply>(request, reply);
run<&test_util::RequestHandler_ForTest::request_and_create_reply>(request, reply);
CHECK(nlohmann::json::parse(reply) == R"({
"jsonrpc":"2.0",
"id":1,
"result":"0x9"
})"_json);
}

TEST_CASE_METHOD(test::RpcApiE2ETest, "unit: eth_blockNumber fails if request empty", "[rpc][api]") {
TEST_CASE_METHOD(test_util::RpcApiE2ETest, "unit: eth_blockNumber fails if request empty", "[rpc][api]") {
const auto request = R"({})"_json;
std::string reply;
run<&test::RequestHandler_ForTest::request_and_create_reply>(request, reply);
run<&test_util::RequestHandler_ForTest::request_and_create_reply>(request, reply);
CHECK(nlohmann::json::parse(reply) == R"({
"jsonrpc":"2.0",
"id":null,
"error":{"code":-32600,"message":"invalid request"}
})"_json);
}

TEST_CASE_METHOD(test::RpcApiE2ETest, "unit: eth_sendRawTransaction fails rlp parsing", "[rpc][api]") {
TEST_CASE_METHOD(test_util::RpcApiE2ETest, "unit: eth_sendRawTransaction fails rlp parsing", "[rpc][api]") {
const auto request = R"({
"jsonrpc": "2.0",
"id": 1,
"method": "eth_sendRawTransaction",
"params": ["0xd46ed67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f0724456"]
})"_json;
std::string reply;
run<&test::RequestHandler_ForTest::request_and_create_reply>(request, reply);
run<&test_util::RequestHandler_ForTest::request_and_create_reply>(request, reply);
CHECK(nlohmann::json::parse(reply) == R"({
"jsonrpc":"2.0",
"id":1,
"error":{"code":-32000,"message":"rlp: input exceeds encoded length"}
})"_json);
}

TEST_CASE_METHOD(test::RpcApiE2ETest, "unit: eth_sendRawTransaction fails wrong number digit", "[rpc][api]") {
TEST_CASE_METHOD(test_util::RpcApiE2ETest, "unit: eth_sendRawTransaction fails wrong number digit", "[rpc][api]") {
const auto request = R"({
"jsonrpc": "2.0",
"id": 1,
"method": "eth_sendRawTransaction",
"params": ["0xd46ed67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445"]
})"_json;
std::string reply;
run<&test::RequestHandler_ForTest::request_and_create_reply>(request, reply);
run<&test_util::RequestHandler_ForTest::request_and_create_reply>(request, reply);
CHECK(nlohmann::json::parse(reply) == R"({
"jsonrpc":"2.0",
"id":1,
"error":{"code":-32000,"message":"rlp: unexpected EIP-2178 serialization"}
})"_json);
}

TEST_CASE_METHOD(test::RpcApiE2ETest, "unit: eth_feeHistory succeeds if request well-formed", "[rpc][api]") {
TEST_CASE_METHOD(test_util::RpcApiE2ETest, "unit: eth_feeHistory succeeds if request well-formed", "[rpc][api]") {
const auto request = R"({"jsonrpc":"2.0","id":1,"method":"eth_feeHistory","params":["0x1","0x867A80",[25,75]]})"_json;
std::string reply;
run<&test::RequestHandler_ForTest::request_and_create_reply>(request, reply);
run<&test_util::RequestHandler_ForTest::request_and_create_reply>(request, reply);
CHECK(nlohmann::json::parse(reply) == R"({
"jsonrpc":"2.0",
"id":1,
"result":{"gasUsedRatio":null,"oldestBlock":"0x0"}
})"_json);
}

TEST_CASE_METHOD(test::RpcApiE2ETest, "fuzzy: eth_call invalid params", "[rpc][api]") {
TEST_CASE_METHOD(test_util::RpcApiE2ETest, "fuzzy: eth_call invalid params", "[rpc][api]") {
const auto request = R"({"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{}, "latest"]})"_json;
std::string reply;
run<&test::RequestHandler_ForTest::request_and_create_reply>(request, reply);
run<&test_util::RequestHandler_ForTest::request_and_create_reply>(request, reply);
CHECK(nlohmann::json::parse(reply) == R"({
"jsonrpc":"2.0",
"id":1,
"error":{"code":-32000,"message":"insufficient funds for gas * price + value: address 0x0000000000000000000000000000000000000000 have 0 want 15240199550000000"}
})"_json);
}

TEST_CASE_METHOD(test::RpcApiE2ETest, "fuzzy: eth_feeHistory sigsegv invalid input", "[rpc][api]") {
TEST_CASE_METHOD(test_util::RpcApiE2ETest, "fuzzy: eth_feeHistory sigsegv invalid input", "[rpc][api]") {
const auto request = R"({"jsonrpc":"2.0","id":1,"method":"eth_feeHistory","params":["5x1","0x2",[95,99]]})"_json;
std::string reply;
run<&test::RequestHandler_ForTest::request_and_create_reply>(request, reply);
run<&test_util::RequestHandler_ForTest::request_and_create_reply>(request, reply);
CHECK(nlohmann::json::parse(reply) == R"({
"jsonrpc":"2.0",
"id":1,
"error":{"code":100,"message":"invalid block_count: 5x1"}
})"_json);
}

TEST_CASE_METHOD(test::RpcApiE2ETest, "fuzzy: eth_feeHistory sigsegv valid input", "[rpc][api]") {
TEST_CASE_METHOD(test_util::RpcApiE2ETest, "fuzzy: eth_feeHistory sigsegv valid input", "[rpc][api]") {
const auto request = R"({"jsonrpc":"2.0","id":1,"method":"eth_feeHistory","params":["0x5","0x2",[95,99]]})"_json;
std::string reply;
run<&test::RequestHandler_ForTest::request_and_create_reply>(request, reply);
run<&test_util::RequestHandler_ForTest::request_and_create_reply>(request, reply);
CHECK(nlohmann::json::parse(reply) == R"({
"jsonrpc":"2.0",
"id":1,
Expand Down
4 changes: 2 additions & 2 deletions silkworm/rpc/commands/parity_api_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
namespace silkworm::rpc::commands {

#ifndef SILKWORM_SANITIZE
TEST_CASE_METHOD(test::RpcApiE2ETest, "parity_getBlockReceipts: misnamed 'params' field", "[rpc][api]") {
TEST_CASE_METHOD(test_util::RpcApiE2ETest, "parity_getBlockReceipts: misnamed 'params' field", "[rpc][api]") {
const auto request = R"({"jsonrpc":"2.0","id":1,"method":"parity_getBlockReceipts","pirams":["0x0"]})";
std::string reply;
run<&test::RequestHandler_ForTest::handle_request>(request, reply);
run<&test_util::RequestHandler_ForTest::handle_request>(request, reply);
CHECK(nlohmann::json::parse(reply) == R"({
"jsonrpc":"2.0",
"id":1,
Expand Down
16 changes: 10 additions & 6 deletions silkworm/rpc/commands/rpc_api_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@

namespace silkworm::rpc::commands {

using silkworm::test_util::SetLogVerbosityGuard;
using test_util::RequestHandler_ForTest;
using test_util::RpcApiTestBase;

// Function to recursively sort JSON arrays
void sort_array(nlohmann::json& jsonObj) { // NOLINT(*-no-recursion)
if (jsonObj.is_array()) {
Expand Down Expand Up @@ -81,7 +85,7 @@ static const std::vector<std::string> subtests_to_ignore = {
// Exclude tests from sanitizer builds due to ASAN/TSAN warnings inside gRPC library
#ifndef SILKWORM_SANITIZE
TEST_CASE("rpc_api io (all files)", "[rpc][rpc_api]") {
test_util::SetLogVerbosityGuard log_guard{log::Level::kNone};
SetLogVerbosityGuard log_guard{log::Level::kNone};
auto tests_dir = db::test_util::get_tests_dir();
for (const auto& test_file : std::filesystem::recursive_directory_iterator(tests_dir)) {
if (!test_file.is_directory() && test_file.path().extension() == ".io") {
Expand All @@ -104,7 +108,7 @@ TEST_CASE("rpc_api io (all files)", "[rpc][rpc_api]") {

SECTION("RPC IO test " + group_name + " | " + test_name) { // NOLINT(*-inefficient-string-concatenation)
auto context = db::test_util::TestDatabaseContext();
test::RpcApiTestBase<test::RequestHandler_ForTest> test_base{context.get_mdbx_env()};
RpcApiTestBase<RequestHandler_ForTest> test_base{context.get_mdbx_env()};

std::string line_out;
std::string line_in;
Expand All @@ -118,7 +122,7 @@ TEST_CASE("rpc_api io (all files)", "[rpc][rpc_api]") {
auto expected = nlohmann::json::parse(line_in.substr(3));

std::string response;
test_base.run<&test::RequestHandler_ForTest::request_and_create_reply>(request, response);
test_base.run<&RequestHandler_ForTest::request_and_create_reply>(request, response);
INFO("Request: " << request.dump());
INFO("Actual response: " << response);
INFO("Expected response: " << expected.dump());
Expand All @@ -135,15 +139,15 @@ TEST_CASE("rpc_api io (all files)", "[rpc][rpc_api]") {
}

TEST_CASE("rpc_api io (individual)", "[rpc][rpc_api][ignore]") {
test_util::SetLogVerbosityGuard log_guard{log::Level::kNone};
SetLogVerbosityGuard log_guard{log::Level::kNone};
auto context = db::test_util::TestDatabaseContext();
test::RpcApiTestBase<test::RequestHandler_ForTest> test_base{context.get_mdbx_env()};
RpcApiTestBase<RequestHandler_ForTest> test_base{context.get_mdbx_env()};

SECTION("sample test") {
auto request = R"({"jsonrpc":"2.0","id":1,"method":"debug_getRawTransaction","params":["0x74e41d593675913d6d5521f46523f1bd396dff1891bdb35f59be47c7e5e0b34b"]})"_json;
std::string response;

test_base.run<&test::RequestHandler_ForTest::request_and_create_reply>(request, response);
test_base.run<&RequestHandler_ForTest::request_and_create_reply>(request, response);
CHECK(nlohmann::json::parse(response) == R"({"jsonrpc":"2.0","id":1,"result":"0xf8678084342770c182520894658bdf435d810c91414ec09147daa6db624063798203e880820a95a0af5fc351b9e457a31f37c84e5cd99dd3c5de60af3de33c6f4160177a2c786a60a0201da7a21046af55837330a2c52fc1543cd4d9ead00ddf178dd96935b607ff9b"})"_json);
}
}
Expand Down
4 changes: 2 additions & 2 deletions silkworm/rpc/common/async_task_benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include <benchmark/benchmark.h>

#include <silkworm/rpc/common/worker_pool.hpp>
#include <silkworm/rpc/test_util/context_test_base.hpp>
#include <silkworm/rpc/test_util/service_context_test_base.hpp>

#include "async_task.hpp"

Expand All @@ -27,7 +27,7 @@ std::size_t recursive_factorial(std::size_t n) {
return n == 0 ? 1 : n * recursive_factorial(n - 1);
}

struct AsyncTaskBenchTest : test::ContextTestBase {
struct AsyncTaskBenchTest : test_util::ServiceContextTestBase {
};

template <typename Executor>
Expand Down
4 changes: 2 additions & 2 deletions silkworm/rpc/common/async_task_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
#include <catch2/catch_test_macros.hpp>

#include <silkworm/rpc/common/worker_pool.hpp>
#include <silkworm/rpc/test_util/context_test_base.hpp>
#include <silkworm/rpc/test_util/service_context_test_base.hpp>

namespace silkworm::rpc {

struct AsyncTaskTest : test::ContextTestBase {
struct AsyncTaskTest : test_util::ServiceContextTestBase {
};

const static std::vector<std::pair<std::size_t, std::size_t>> kTestData = {
Expand Down
4 changes: 2 additions & 2 deletions silkworm/rpc/common/binary_search_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@

#include <catch2/catch_test_macros.hpp>

#include <silkworm/rpc/test_util/context_test_base.hpp>
#include <silkworm/rpc/test_util/service_context_test_base.hpp>

namespace silkworm::rpc {

struct BinarySearchTest : test::ContextTestBase {
struct BinarySearchTest : test_util::ServiceContextTestBase {
};

struct BinaryTestData {
Expand Down
2 changes: 0 additions & 2 deletions silkworm/rpc/core/blocks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ constexpr const char* kFinalizedBlockId{"finalized"};
constexpr const char* kSafeBlockId{"safe"};
constexpr const char* kLatestExecutedBlockId{"latestExecuted"};

constexpr BlockNum kEarliestBlockNumber{0ul};

// TODO(canepat) migrate to ChainStorage?

Task<bool> is_latest_block_number(BlockNum block_number, ethdb::Transaction& tx);
Expand Down
2 changes: 1 addition & 1 deletion silkworm/rpc/core/estimate_gas_oracle_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

namespace silkworm::rpc {

struct RemoteDatabaseTest : test::KVTestBase {
struct RemoteDatabaseTest : test_util::KVTestBase {
public:
// RemoteDatabase holds the KV stub by std::unique_ptr, so we cannot rely on mock stub from base class
StrictMockKVStub* kv_stub_ = new StrictMockKVStub;
Expand Down
Loading

0 comments on commit adc984a

Please sign in to comment.