Skip to content

Commit e135aa4

Browse files
Create generate free port class to avoid conflicting ports (#1439)
Fixes #1317
1 parent 5ba08b1 commit e135aa4

14 files changed

+313
-149
lines changed

tests/common/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_library(clio_testing_common)
22

33
target_sources(
44
clio_testing_common PRIVATE util/StringUtils.cpp util/TestHttpServer.cpp util/TestWsServer.cpp util/TestObject.cpp
5+
util/AssignRandomPort.cpp
56
)
67

78
include(deps/gtest)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//------------------------------------------------------------------------------
2+
/*
3+
This file is part of clio: https://github.com/XRPLF/clio
4+
Copyright (c) 2024, the clio developers.
5+
6+
Permission to use, copy, modify, and distribute this software for any
7+
purpose with or without fee is hereby granted, provided that the above
8+
copyright notice and this permission notice appear in all copies.
9+
10+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17+
*/
18+
//==============================================================================
19+
20+
#include "util/AssignRandomPort.hpp"
21+
22+
#include <boost/asio/io_context.hpp>
23+
#include <boost/asio/ip/tcp.hpp>
24+
25+
#include <cstdint>
26+
27+
using tcp = boost::asio::ip::tcp;
28+
29+
namespace tests::util {
30+
31+
uint32_t
32+
generateFreePort()
33+
{
34+
boost::asio::io_context io_context;
35+
tcp::acceptor acceptor(io_context);
36+
tcp::endpoint const endpoint(tcp::v4(), 0);
37+
38+
acceptor.open(endpoint.protocol());
39+
acceptor.set_option(tcp::acceptor::reuse_address(true));
40+
acceptor.bind(endpoint);
41+
42+
return acceptor.local_endpoint().port();
43+
}
44+
45+
} // namespace tests::util
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//------------------------------------------------------------------------------
2+
/*
3+
This file is part of clio: https://github.com/XRPLF/clio
4+
Copyright (c) 2024, the clio developers.
5+
6+
Permission to use, copy, modify, and distribute this software for any
7+
purpose with or without fee is hereby granted, provided that the above
8+
copyright notice and this permission notice appear in all copies.
9+
10+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17+
*/
18+
//==============================================================================
19+
20+
#pragma once
21+
22+
#include <cstdint>
23+
24+
namespace tests::util {
25+
26+
uint32_t
27+
generateFreePort();
28+
29+
} // namespace tests::util

tests/common/util/MockXrpLedgerAPIService.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ struct WithMockXrpLedgerAPIService : virtual ::testing::Test {
8282
WithMockXrpLedgerAPIService(std::string serverAddress)
8383
{
8484
grpc::ServerBuilder builder;
85-
builder.AddListeningPort(serverAddress, grpc::InsecureServerCredentials());
85+
builder.AddListeningPort(serverAddress, grpc::InsecureServerCredentials(), &port_);
8686
builder.RegisterService(&mockXrpLedgerAPIService);
8787
server_ = builder.BuildAndStart();
8888
serverThread_ = std::thread([this] { server_->Wait(); });
@@ -94,11 +94,17 @@ struct WithMockXrpLedgerAPIService : virtual ::testing::Test {
9494
serverThread_.join();
9595
}
9696

97+
int
98+
getXRPLMockPort() const
99+
{
100+
return port_;
101+
}
97102
MockXrpLedgerAPIService mockXrpLedgerAPIService;
98103

99104
private:
100105
std::unique_ptr<grpc::Server> server_;
101106
std::thread serverThread_;
107+
int port_{};
102108
};
103109

104110
} // namespace tests::util

tests/common/util/TestHttpServer.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ doSession(
105105

106106
} // namespace
107107

108-
TestHttpServer::TestHttpServer(boost::asio::io_context& context, std::string host, int const port) : acceptor_(context)
108+
TestHttpServer::TestHttpServer(boost::asio::io_context& context, std::string host) : acceptor_(context)
109109
{
110-
boost::asio::ip::tcp::endpoint const endpoint(boost::asio::ip::make_address(host), port);
110+
boost::asio::ip::tcp::endpoint const endpoint(boost::asio::ip::make_address(host), 0);
111111
acceptor_.open(endpoint.protocol());
112112
acceptor_.set_option(asio::socket_base::reuse_address(true));
113113
acceptor_.bind(endpoint);
@@ -134,3 +134,9 @@ TestHttpServer::handleRequest(TestHttpServer::RequestHandler handler, bool const
134134
boost::asio::detached
135135
);
136136
}
137+
138+
std::string
139+
TestHttpServer::port() const
140+
{
141+
return std::to_string(acceptor_.local_endpoint().port());
142+
}

tests/common/util/TestHttpServer.hpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,8 @@ class TestHttpServer {
4141
*
4242
* @param context boost::asio::io_context to use for networking
4343
* @param host host to bind to
44-
* @param port port to bind to
4544
*/
46-
TestHttpServer(boost::asio::io_context& context, std::string host, int port);
45+
TestHttpServer(boost::asio::io_context& context, std::string host);
4746

4847
/**
4948
* @brief Start the server
@@ -56,6 +55,14 @@ class TestHttpServer {
5655
void
5756
handleRequest(RequestHandler handler, bool allowToFail = false);
5857

58+
/**
59+
* @brief Return the port HTTP server is connected to
60+
*
61+
* @return string port number
62+
*/
63+
std::string
64+
port() const;
65+
5966
private:
6067
boost::asio::ip::tcp::acceptor acceptor_;
6168
};

tests/common/util/TestWsServer.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,20 @@ TestWsConnection::headers() const
105105
return headers_;
106106
}
107107

108-
TestWsServer::TestWsServer(asio::io_context& context, std::string const& host, int port) : acceptor_(context)
108+
TestWsServer::TestWsServer(asio::io_context& context, std::string const& host) : acceptor_(context)
109109
{
110-
auto endpoint = asio::ip::tcp::endpoint(boost::asio::ip::make_address(host), port);
110+
auto endpoint = asio::ip::tcp::endpoint(boost::asio::ip::make_address(host), 0);
111111
acceptor_.open(endpoint.protocol());
112112
acceptor_.set_option(asio::socket_base::reuse_address(true));
113113
acceptor_.bind(endpoint);
114114
}
115115

116+
std::string
117+
TestWsServer::port() const
118+
{
119+
return std::to_string(this->acceptor_.local_endpoint().port());
120+
}
121+
116122
std::expected<TestWsConnection, util::requests::RequestError>
117123
TestWsServer::acceptConnection(asio::yield_context yield)
118124
{

tests/common/util/TestWsServer.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ class TestWsServer {
7070
boost::asio::ip::tcp::acceptor acceptor_;
7171

7272
public:
73-
TestWsServer(boost::asio::io_context& context, std::string const& host, int port);
73+
TestWsServer(boost::asio::io_context& context, std::string const& host);
74+
75+
std::string
76+
port() const;
7477

7578
std::expected<TestWsConnection, util::requests::RequestError>
7679
acceptConnection(boost::asio::yield_context yield);

tests/unit/etl/ForwardingSourceTests.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,13 @@
3737
using namespace etl::impl;
3838

3939
struct ForwardingSourceTests : SyncAsioContextTest {
40-
TestWsServer server_{ctx, "0.0.0.0", 11114};
41-
ForwardingSource forwardingSource{"127.0.0.1", "11114", std::chrono::milliseconds{1}, std::chrono::milliseconds{1}};
40+
TestWsServer server_{ctx, "0.0.0.0"};
41+
ForwardingSource forwardingSource{
42+
"127.0.0.1",
43+
server_.port(),
44+
std::chrono::milliseconds{1},
45+
std::chrono::milliseconds{1}
46+
};
4247
};
4348

4449
TEST_F(ForwardingSourceTests, ConnectionFailed)

tests/unit/etl/GrpcSourceTests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ using namespace etl::impl;
4242

4343
struct GrpcSourceTests : NoLoggerFixture, util::prometheus::WithPrometheus, tests::util::WithMockXrpLedgerAPIService {
4444
GrpcSourceTests()
45-
: WithMockXrpLedgerAPIService("localhost:55051")
45+
: WithMockXrpLedgerAPIService("localhost:0")
4646
, mockBackend_(std::make_shared<testing::StrictMock<MockBackend>>(util::Config{}))
47-
, grpcSource_("127.0.0.1", "55051", mockBackend_)
47+
, grpcSource_("127.0.0.1", std::to_string(getXRPLMockPort()), mockBackend_)
4848
{
4949
}
5050

0 commit comments

Comments
 (0)