Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit 36de557

Browse files
committed
Add Connection mock and refactor client
1 parent af86ff5 commit 36de557

9 files changed

+116
-26
lines changed

CMakeHelpers.cmake

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ endmacro()
2626

2727
# Helper macro to find google test library
2828
macro(helper_FIND_GTEST_LIBS)
29-
find_package(GTest REQUIRED)
30-
if(NOT GTest_FOUND)
31-
message("Gtets not found. Tests won`t compile.")
32-
else()
33-
include_directories(${GTEST_INCLUDE_DIRS})
34-
endif()
29+
include(FetchContent)
30+
FetchContent_Declare(
31+
googletest
32+
URL https://github.com/google/googletest/archive/refs/heads/main.zip
33+
)
34+
# Download and make gtest/gmock available
35+
FetchContent_MakeAvailable(googletest)
3536
endmacro()

test/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ set( SOURCES
77
TestXStationClientStream.cpp
88
)
99

10+
add_subdirectory(mocks)
1011
add_executable( tests
1112
${SOURCES}
1213
)
@@ -20,13 +21,16 @@ target_compile_options(tests PRIVATE
2021
-Wno-missing-field-initializers
2122
)
2223

24+
target_include_directories(tests PRIVATE mocks)
2325
target_link_libraries(tests PRIVATE
2426
${GTEST_LIBRARIES}
2527
Boost::system
2628
Boost::url
2729
Boost::json
2830
Xapi
29-
GTest::gtest_main
31+
gtest
32+
gtest_main
33+
test_mocks
3034
)
3135

3236
include(GoogleTest)

test/mocks/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
set (TEST_MOCK_LIB test_mocks)
2+
3+
set (TEST_MOCK_LIB_PUBLIC_H
4+
MockConnection.hpp
5+
)
6+
7+
add_library(${TEST_MOCK_LIB} INTERFACE ${TEST_MOCK_LIB_PUBLIC_H})
8+
target_link_libraries(${TEST_MOCK_LIB} INTERFACE gmock gmock_main)

test/mocks/MockConnection.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
3+
#include <gmock/gmock.h>
4+
#include <boost/asio.hpp>
5+
#include <boost/json.hpp>
6+
#include <boost/url.hpp>
7+
#include "xapi/IConnection.hpp"
8+
9+
class MockConnection : public xapi::internals::IConnection
10+
{
11+
public:
12+
// Mock the connect method
13+
MOCK_METHOD((boost::asio::awaitable<void>), connect, (const boost::url &url), (override));
14+
15+
// Mock the disconnect method
16+
MOCK_METHOD((boost::asio::awaitable<void>), disconnect, (), (override));
17+
18+
// Mock the makeRequest method
19+
MOCK_METHOD((boost::asio::awaitable<void>), makeRequest, (const boost::json::object &command), (override));
20+
21+
// Mock the waitResponse method
22+
MOCK_METHOD((boost::asio::awaitable<boost::json::object>), waitResponse, (), (override));
23+
};

xapi/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
set(XAPI_PUBLIC_H
22
Enums.hpp
33
Exceptions.hpp
4+
IConnection.hpp
45
Connection.hpp
56
XStationClient.hpp
67
XStationClientStream.hpp

xapi/Connection.hpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@
88
* establishing and managing connections, making requests, and handling responses.
99
*/
1010

11-
#include <boost/asio.hpp>
12-
#include <boost/asio/cancellation_signal.hpp>
11+
#include "IConnection.hpp"
1312
#include <boost/beast.hpp>
1413
#include <boost/beast/websocket/ssl.hpp>
15-
#include <boost/json.hpp>
16-
#include <boost/url.hpp>
1714
#include <chrono>
1815
#include <string>
1916

@@ -29,7 +26,7 @@ namespace internals
2926
* The Connection class encapsulates the functionality for establishing an SSL connection,
3027
* sending requests, and receiving responses.
3128
*/
32-
class Connection
29+
class Connection : public IConnection
3330
{
3431
public:
3532
Connection() = delete;
@@ -47,42 +44,41 @@ class Connection
4744
*/
4845
explicit Connection(boost::asio::io_context &ioContext);
4946

50-
virtual ~Connection();
47+
virtual ~Connection() override;
5148

5249
/**
5350
* @brief Asynchronously establishes secure WebSocket connection to the server.
5451
* @param url The URL to connect to.
5552
* @return An awaitable void.
5653
* @throw xapi::exception::ConnectionClosed if the connection fails.
5754
*/
58-
boost::asio::awaitable<void> connect(const boost::url &url);
55+
boost::asio::awaitable<void> connect(const boost::url &url) override;
5956

6057
/**
6158
* @brief Asynchronously disconnects from the server.
6259
* @return An awaitable void.
6360
*/
64-
boost::asio::awaitable<void> disconnect();
61+
boost::asio::awaitable<void> disconnect() override;
6562

6663
/**
6764
* @brief Makes an asynchronous request to the server.
6865
* @param command The command to send as a JSON value.
6966
* @return An awaitable void.
7067
* @throw xapi::exception::ConnectionClosed if the request fails.
7168
*/
72-
boost::asio::awaitable<void> makeRequest(const boost::json::object &command);
69+
boost::asio::awaitable<void> makeRequest(const boost::json::object &command) override;
7370

7471
/**
7572
* @brief Waits for a response from the server.
7673
* @return An awaitable boost::json::object with response from the server.
7774
* @throw xapi::exception::ConnectionClosed if the response fails.
7875
*/
79-
boost::asio::awaitable<boost::json::object> waitResponse();
76+
boost::asio::awaitable<boost::json::object> waitResponse() override;
8077

81-
protected:
78+
private:
8279
// The IO context for asynchronous operations.
8380
boost::asio::io_context &m_ioContext;
8481

85-
private:
8682
/**
8783
* @brief Establishes an SSL connection asynchronously.
8884
* @param results The resolved endpoints to attempt to connect to.

xapi/IConnection.hpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#pragma once
2+
3+
/**
4+
* @file IConnection.hpp
5+
* @brief Declaration of the Connection interface.
6+
*/
7+
8+
#include <boost/asio.hpp>
9+
#include <boost/asio/cancellation_signal.hpp>
10+
#include <boost/json.hpp>
11+
#include <boost/url.hpp>
12+
13+
namespace xapi
14+
{
15+
namespace internals
16+
{
17+
18+
class IConnection
19+
{
20+
public:
21+
virtual ~IConnection() = default;
22+
23+
/**
24+
* @brief Asynchronously establishes secure WebSocket connection to the server.
25+
* @param url The URL to connect to.
26+
* @return An awaitable void.
27+
* @throw xapi::exception::ConnectionClosed if the connection fails.
28+
*/
29+
virtual boost::asio::awaitable<void> connect(const boost::url &url) = 0;
30+
31+
/**
32+
* @brief Asynchronously disconnects from the server.
33+
* @return An awaitable void.
34+
*/
35+
virtual boost::asio::awaitable<void> disconnect() = 0;
36+
37+
/**
38+
* @brief Makes an asynchronous request to the server.
39+
* @param command The command to send as a JSON value.
40+
* @return An awaitable void.
41+
* @throw xapi::exception::ConnectionClosed if the request fails.
42+
*/
43+
virtual boost::asio::awaitable<void> makeRequest(const boost::json::object &command) = 0;
44+
45+
/**
46+
* @brief Waits for a response from the server.
47+
* @return An awaitable boost::json::object with response from the server.
48+
* @throw xapi::exception::ConnectionClosed if the response fails.
49+
*/
50+
virtual boost::asio::awaitable<boost::json::object> waitResponse() = 0;
51+
};
52+
53+
} // namespace internals
54+
} // namespace xapi

xapi/XStationClient.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const std::unordered_set<std::string> XStationClient::m_knownAccountTypes = {"de
88

99
XStationClient::XStationClient(boost::asio::io_context &ioContext, const std::string &accountId,
1010
const std::string &password, const std::string &accountType)
11-
: Connection(ioContext), m_accountId(accountId), m_password(password),
11+
: m_ioContext(ioContext), m_connection(std::make_unique<internals::Connection>(ioContext)), m_accountId(accountId), m_password(password),
1212
m_accountType(accountType), m_safeMode(true), m_streamSessionId("")
1313
{
1414
}
@@ -25,7 +25,7 @@ boost::asio::awaitable<void> XStationClient::login() {
2525
validateAccountType(m_accountType);
2626

2727
const boost::url socketUrl = boost::urls::format("wss://ws.xtb.com/{}", m_accountType);
28-
co_await connect(socketUrl);
28+
co_await m_connection->connect(socketUrl);
2929

3030
boost::json::object command = {
3131
{"command", "login"},
@@ -48,7 +48,7 @@ boost::asio::awaitable<void> XStationClient::logout() {
4848
{"command", "logout"}
4949
};
5050
co_await request(command);
51-
co_await disconnect();
51+
co_await m_connection->disconnect();
5252

5353
}
5454

@@ -366,8 +366,8 @@ boost::asio::awaitable<boost::json::object> XStationClient::tradeTransactionStat
366366

367367
boost::asio::awaitable<boost::json::object> XStationClient::request(const boost::json::object &command)
368368
{
369-
co_await makeRequest(command);
370-
auto result = co_await waitResponse();
369+
co_await m_connection->makeRequest(command);
370+
auto result = co_await m_connection->waitResponse();
371371
co_return result;
372372
}
373373

xapi/XStationClient.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace xapi
2323
* from xAPI. It is built on top of the Connection class, which handles the
2424
* low-level details of establishing and maintaining a connection.
2525
*/
26-
class XStationClient : protected internals::Connection
26+
class XStationClient final
2727
{
2828
public:
2929
XStationClient() = delete;
@@ -67,7 +67,7 @@ class XStationClient : protected internals::Connection
6767
*/
6868
explicit XStationClient(boost::asio::io_context &ioContext, const boost::json::object &accountCredentials);
6969

70-
~XStationClient() override = default;
70+
~XStationClient() = default;
7171

7272
/**
7373
* @brief Opens connection to the server and logs in.
@@ -153,6 +153,9 @@ class XStationClient : protected internals::Connection
153153

154154
protected:
155155

156+
boost::asio::io_context &m_ioContext;
157+
std::unique_ptr<internals::IConnection> m_connection;
158+
156159
const std::string m_accountId;
157160
const std::string m_password;
158161
const std::string m_accountType;

0 commit comments

Comments
 (0)