From a3ce384951f0257b7bf0addd170d194b59901a9f Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Wed, 9 Oct 2024 15:23:43 -0300 Subject: [PATCH 01/12] feat: adds the capability to AgentInfo to persist agent_group information in the agent_info.db database (inside a new table, the agent_group table). --- src/agent/agent_info/include/agent_info.hpp | 4 + src/agent/agent_info/src/agent_info.cpp | 13 +++ .../agent_info/src/agent_info_persistance.cpp | 92 ++++++++++++++++++- .../agent_info/src/agent_info_persistance.hpp | 8 +- .../tests/agent_info_persistance_test.cpp | 7 ++ .../agent_info/tests/agent_info_test.cpp | 12 +++ 6 files changed, 131 insertions(+), 5 deletions(-) diff --git a/src/agent/agent_info/include/agent_info.hpp b/src/agent/agent_info/include/agent_info.hpp index 0d3cecedbb..4c3e914796 100644 --- a/src/agent/agent_info/include/agent_info.hpp +++ b/src/agent/agent_info/include/agent_info.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include class AgentInfo { @@ -11,13 +12,16 @@ class AgentInfo std::string GetName() const; std::string GetKey() const; std::string GetUUID() const; + std::vector GetGroups() const; void SetName(const std::string& name); void SetKey(const std::string& key); void SetUUID(const std::string& uuid); + void SetGroups(const std::vector& group_list); private: std::string m_name; std::string m_key; std::string m_uuid; + std::vector m_groups; }; diff --git a/src/agent/agent_info/src/agent_info.cpp b/src/agent/agent_info/src/agent_info.cpp index 7a9a8b66fb..e0b071659d 100644 --- a/src/agent/agent_info/src/agent_info.cpp +++ b/src/agent/agent_info/src/agent_info.cpp @@ -13,6 +13,7 @@ AgentInfo::AgentInfo() m_name = agentInfoPersistance.GetName(); m_key = agentInfoPersistance.GetKey(); m_uuid = agentInfoPersistance.GetUUID(); + m_groups = agentInfoPersistance.GetGroups(); if (m_uuid.empty()) { @@ -47,6 +48,11 @@ std::string AgentInfo::GetUUID() const return m_uuid; } +std::vector AgentInfo::GetGroups() const +{ + return m_groups; +} + void AgentInfo::SetName(const std::string& name) { AgentInfoPersistance agentInfoPersistance; @@ -67,3 +73,10 @@ void AgentInfo::SetUUID(const std::string& uuid) agentInfoPersistance.SetUUID(uuid); m_uuid = uuid; } + +void AgentInfo::SetGroups(const std::vector& group_list) +{ + AgentInfoPersistance agentInfoPersistance; + agentInfoPersistance.SetGroups(group_list); + m_groups = group_list; +} diff --git a/src/agent/agent_info/src/agent_info_persistance.cpp b/src/agent/agent_info/src/agent_info_persistance.cpp index 6b200a3b28..3633ecd7df 100644 --- a/src/agent/agent_info/src/agent_info_persistance.cpp +++ b/src/agent/agent_info/src/agent_info_persistance.cpp @@ -3,17 +3,28 @@ #include #include +namespace +{ + const std::string AGENT_INFO_TABLE_NAME = "agent_info"; + const std::string AGENT_GROUP_TABLE_NAME = "agent_group"; +} // namespace + AgentInfoPersistance::AgentInfoPersistance(const std::string& dbPath) { try { m_db = std::make_unique(dbPath, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); - if (!AgentInfoTableExists()) + if (!TableExists(AGENT_INFO_TABLE_NAME)) { CreateAgentInfoTable(); } + if (!TableExists(AGENT_GROUP_TABLE_NAME)) + { + CreateAgentGroupTable(); + } + if (AgentInfoIsEmpty()) { InsertDefaultAgentInfo(); @@ -28,11 +39,11 @@ AgentInfoPersistance::AgentInfoPersistance(const std::string& dbPath) AgentInfoPersistance::~AgentInfoPersistance() = default; -bool AgentInfoPersistance::AgentInfoTableExists() const +bool AgentInfoPersistance::TableExists(const std::string& table) const { try { - SQLite::Statement query(*m_db, "SELECT name FROM sqlite_master WHERE type='table' AND name='agent_info';"); + SQLite::Statement query(*m_db, "SELECT name FROM sqlite_master WHERE type='table' AND name='" + table + "';"); return query.executeStep(); } catch (const std::exception& e) @@ -75,6 +86,22 @@ void AgentInfoPersistance::CreateAgentInfoTable() } } +void AgentInfoPersistance::CreateAgentGroupTable() +{ + try + { + m_db->exec("CREATE TABLE IF NOT EXISTS " + AGENT_GROUP_TABLE_NAME + + " (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "name TEXT NOT NULL UNIQUE" + ");"); + } + catch (const std::exception& e) + { + LogError("Error creating table: {}.", e.what()); + } +} + void AgentInfoPersistance::InsertDefaultAgentInfo() { try @@ -127,6 +154,52 @@ std::string AgentInfoPersistance::GetAgentInfoValue(const std::string& column) c return value; } +void AgentInfoPersistance::SetAgentGroups(const std::vector& group_list) +{ + try + { + SQLite::Transaction transaction(*m_db); + + m_db->exec("DELETE FROM " + AGENT_GROUP_TABLE_NAME + ";"); + + SQLite::Statement query(*m_db, "INSERT INTO " + AGENT_GROUP_TABLE_NAME + " (name) VALUES (?);"); + + for (const std::string& group : group_list) + { + query.bind(1, group); + query.exec(); + query.reset(); + } + + transaction.commit(); + } + catch (const std::exception& e) + { + LogError("Error inserting group: {}.", e.what()); + } +} + +std::vector AgentInfoPersistance::GetAgentGroupList() const +{ + std::vector group_list; + + try + { + SQLite::Statement query(*m_db, "SELECT name FROM " + AGENT_GROUP_TABLE_NAME + " ORDER BY id ASC;"); + + while (query.executeStep()) + { + group_list.push_back(query.getColumn(0).getString()); + } + } + catch (const std::exception& e) + { + LogError("Error getting agent group list: {}.", e.what()); + } + + return group_list; +} + std::string AgentInfoPersistance::GetName() const { return GetAgentInfoValue("name"); @@ -142,6 +215,11 @@ std::string AgentInfoPersistance::GetUUID() const return GetAgentInfoValue("uuid"); } +std::vector AgentInfoPersistance::GetGroups() const +{ + return GetAgentGroupList(); +} + void AgentInfoPersistance::SetName(const std::string& name) { SetAgentInfoValue("name", name); @@ -157,11 +235,17 @@ void AgentInfoPersistance::SetUUID(const std::string& uuid) SetAgentInfoValue("uuid", uuid); } +void AgentInfoPersistance::SetGroups(const std::vector& group_list) +{ + SetAgentGroups(group_list); +} + void AgentInfoPersistance::ResetToDefault() { try { - m_db->exec("DELETE FROM agent_info;"); + m_db->exec("DELETE FROM " + AGENT_INFO_TABLE_NAME + ";"); + m_db->exec("DELETE FROM " + AGENT_GROUP_TABLE_NAME + ";"); InsertDefaultAgentInfo(); } catch (const std::exception& e) diff --git a/src/agent/agent_info/src/agent_info_persistance.hpp b/src/agent/agent_info/src/agent_info_persistance.hpp index c3b3b99e2f..f3121b7a9a 100644 --- a/src/agent/agent_info/src/agent_info_persistance.hpp +++ b/src/agent/agent_info/src/agent_info_persistance.hpp @@ -2,6 +2,7 @@ #include #include +#include static constexpr char sqlitedb_path[] = "agent_info.db"; @@ -24,20 +25,25 @@ class AgentInfoPersistance std::string GetName() const; std::string GetKey() const; std::string GetUUID() const; + std::vector GetGroups() const; void SetName(const std::string& name); void SetKey(const std::string& key); void SetUUID(const std::string& uuid); + void SetGroups(const std::vector& group_list); void ResetToDefault(); private: - bool AgentInfoTableExists() const; + bool TableExists(const std::string& table) const; bool AgentInfoIsEmpty() const; void CreateAgentInfoTable(); + void CreateAgentGroupTable(); void InsertDefaultAgentInfo(); void SetAgentInfoValue(const std::string& column, const std::string& value); std::string GetAgentInfoValue(const std::string& column) const; + void SetAgentGroups(const std::vector& group_list); + std::vector GetAgentGroupList() const; std::unique_ptr m_db; }; diff --git a/src/agent/agent_info/tests/agent_info_persistance_test.cpp b/src/agent/agent_info/tests/agent_info_persistance_test.cpp index 2356f4674c..1516e4dade 100644 --- a/src/agent/agent_info/tests/agent_info_persistance_test.cpp +++ b/src/agent/agent_info/tests/agent_info_persistance_test.cpp @@ -50,6 +50,13 @@ TEST_F(AgentInfoPersistanceTest, TestSetUUID) EXPECT_EQ(persistance->GetUUID(), newUUID); } +TEST_F(AgentInfoPersistanceTest, TestSetGroups) +{ + const std::vector newGroups = {"group_1", "group_2"}; + persistance->SetGroups(newGroups); + EXPECT_EQ(persistance->GetGroups(), newGroups); +} + TEST_F(AgentInfoPersistanceTest, TestResetToDefault) { const std::string newName = "new_name"; diff --git a/src/agent/agent_info/tests/agent_info_test.cpp b/src/agent/agent_info/tests/agent_info_test.cpp index 85f7f5f6dc..3c3d4ea602 100644 --- a/src/agent/agent_info/tests/agent_info_test.cpp +++ b/src/agent/agent_info/tests/agent_info_test.cpp @@ -84,6 +84,18 @@ TEST_F(AgentInfoTest, TestSetUUID) EXPECT_EQ(agentInfoReloaded.GetUUID(), newUUID); } +TEST_F(AgentInfoTest, TestSetGroups) +{ + AgentInfo agentInfo; + const std::vector newGroups = {"t_group_1", "t_group_2"}; + + agentInfo.SetGroups(newGroups); + EXPECT_EQ(agentInfo.GetGroups(), newGroups); + + const AgentInfo agentInfoReloaded; + EXPECT_EQ(agentInfoReloaded.GetGroups(), newGroups); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); From 5e3d0ba41a03d1f51c4bced005303dfb6818fddf Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Tue, 15 Oct 2024 19:56:03 -0300 Subject: [PATCH 02/12] feat: adds the ReadToFile method in the HttpSocket and HttpsSocket classes to read the request response and store it in a file. --- .../communicator/include/ihttp_socket.hpp | 3 ++ src/agent/communicator/src/http_socket.hpp | 52 +++++++++++++++++++ src/agent/communicator/src/https_socket.hpp | 50 ++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/src/agent/communicator/include/ihttp_socket.hpp b/src/agent/communicator/include/ihttp_socket.hpp index 3f46e3f98c..4ea6c46ce5 100644 --- a/src/agent/communicator/include/ihttp_socket.hpp +++ b/src/agent/communicator/include/ihttp_socket.hpp @@ -23,6 +23,9 @@ namespace http_client virtual void Read(boost::beast::http::response& res) = 0; + virtual void ReadToFile(boost::beast::http::response_parser& res, + const std::string& output_file) = 0; + virtual boost::asio::awaitable AsyncRead(boost::beast::http::response& res, boost::beast::error_code& ec) = 0; diff --git a/src/agent/communicator/src/http_socket.hpp b/src/agent/communicator/src/http_socket.hpp index 786bfa9e38..d91ba772e5 100644 --- a/src/agent/communicator/src/http_socket.hpp +++ b/src/agent/communicator/src/http_socket.hpp @@ -3,6 +3,8 @@ #include #include +#include + namespace http_client { class HttpSocket : public IHttpSocket @@ -43,6 +45,56 @@ namespace http_client boost::beast::http::read(m_socket, buffer, res); } + void ReadToFile(boost::beast::http::response_parser& res, + const std::string& output_file) override + { + res.body_limit(std::numeric_limits::max()); + boost::beast::flat_buffer buffer; + boost::system::error_code error; + + boost::beast::http::read_header(m_socket, buffer, res, error); + + if (error && error != boost::beast::http::error::need_buffer) + { + throw boost::system::system_error(error); + } + + unsigned int status_code = res.get().result_int(); + if (status_code != 200) + { + return; + } + + std::ofstream file(output_file, std::ios::binary); + if (!file) + { + throw std::runtime_error("The file could not be opened for writing: " + output_file); + } + + while (!res.is_done()) + { + boost::beast::http::read(m_socket, buffer, res, error); + + if (error && error != boost::beast::http::error::need_buffer && error != boost::asio::error::eof) + { + file.close(); + throw boost::system::system_error(error); + } + + auto body_data = res.get().body().data(); + + for (auto const& buffer_seq : body_data) + { + std::streamsize chunk_size = static_cast(buffer_seq.size()); + file.write(static_cast(buffer_seq.data()), chunk_size); + } + + res.get().body().consume(res.get().body().size()); + } + + file.close(); + } + boost::asio::awaitable AsyncRead(boost::beast::http::response& res, boost::beast::error_code& ec) override { diff --git a/src/agent/communicator/src/https_socket.hpp b/src/agent/communicator/src/https_socket.hpp index a565b32ed5..3f6fa6019f 100644 --- a/src/agent/communicator/src/https_socket.hpp +++ b/src/agent/communicator/src/https_socket.hpp @@ -51,6 +51,56 @@ namespace http_client boost::beast::http::read(m_ssl_socket, buffer, res); } + void ReadToFile(boost::beast::http::response_parser& res, + const std::string& output_file) override + { + res.body_limit(std::numeric_limits::max()); + boost::beast::flat_buffer buffer; + boost::system::error_code error; + + boost::beast::http::read_header(m_ssl_socket, buffer, res, error); + + if (error && error != boost::beast::http::error::need_buffer) + { + throw boost::system::system_error(error); + } + + unsigned int status_code = res.get().result_int(); + if (status_code != 200) + { + return; + } + + std::ofstream file(output_file, std::ios::binary); + if (!file) + { + throw std::runtime_error("The file could not be opened for writing: " + output_file); + } + + while (!res.is_done()) + { + boost::beast::http::read(m_ssl_socket, buffer, res, error); + + if (error && error != boost::beast::http::error::need_buffer && error != boost::asio::error::eof) + { + file.close(); + throw boost::system::system_error(error); + } + + auto body_data = res.get().body().data(); + + for (auto const& buffer_seq : body_data) + { + std::streamsize chunk_size = static_cast(buffer_seq.size()); + file.write(static_cast(buffer_seq.data()), chunk_size); + } + + res.get().body().consume(res.get().body().size()); + } + + file.close(); + } + boost::asio::awaitable AsyncRead(boost::beast::http::response& res, boost::beast::error_code& ec) override { From 58ffcc7e7fe70a5e5ea85fcfc1472d132853b788 Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Tue, 15 Oct 2024 20:01:23 -0300 Subject: [PATCH 03/12] feat: adds the PerformHttpRequestDownload method in the HttpClient class to make a request and download a file. --- .../communicator/include/http_client.hpp | 3 ++ .../communicator/include/ihttp_client.hpp | 3 ++ src/agent/communicator/src/http_client.cpp | 33 +++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/src/agent/communicator/include/http_client.hpp b/src/agent/communicator/include/http_client.hpp index cd62764c2c..dc218f9d55 100644 --- a/src/agent/communicator/include/http_client.hpp +++ b/src/agent/communicator/include/http_client.hpp @@ -47,6 +47,9 @@ namespace http_client const std::string& password, const bool useHttps) override; + boost::beast::http::response + PerformHttpRequestDownload(const HttpRequestParams& params, const std::string& output_file) override; + private: std::shared_ptr m_resolverFactory; std::shared_ptr m_socketFactory; diff --git a/src/agent/communicator/include/ihttp_client.hpp b/src/agent/communicator/include/ihttp_client.hpp index e4a245c6a0..27c14da398 100644 --- a/src/agent/communicator/include/ihttp_client.hpp +++ b/src/agent/communicator/include/ihttp_client.hpp @@ -80,5 +80,8 @@ namespace http_client const std::string& user, const std::string& password, const bool useHttps) = 0; + + virtual boost::beast::http::response + PerformHttpRequestDownload(const HttpRequestParams& params, const std::string& output_file) = 0; }; } // namespace http_client diff --git a/src/agent/communicator/src/http_client.cpp b/src/agent/communicator/src/http_client.cpp index 72d70c8709..4a5f60d7c3 100644 --- a/src/agent/communicator/src/http_client.cpp +++ b/src/agent/communicator/src/http_client.cpp @@ -246,4 +246,37 @@ namespace http_client .at("token") .get_ref(); } + + boost::beast::http::response + HttpClient::PerformHttpRequestDownload(const HttpRequestParams& params, const std::string& output_file) + { + boost::beast::http::response_parser res_parser; + + try + { + boost::asio::io_context io_context; + auto resolver = m_resolverFactory->Create(io_context.get_executor()); + + const auto results = resolver->Resolve(params.Host, params.Port); + + auto socket = m_socketFactory->Create(io_context.get_executor(), params.Use_Https); + socket->Connect(results); + + const auto req = CreateHttpRequest(params); + socket->Write(req); + socket->ReadToFile(res_parser, output_file); + + LogDebug("Response code: {}.", res_parser.get().result_int()); + } + catch (std::exception const& e) + { + LogError("Error: {}.", e.what()); + + auto& res = res_parser.get(); + res.result(boost::beast::http::status::internal_server_error); + boost::beast::ostream(res.body()) << "Internal server error: " << e.what(); + } + + return res_parser.release(); + } } // namespace http_client From 76cf91514ac0d76d5fc81cabe25fa2c14fa17c09 Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Tue, 15 Oct 2024 22:07:15 -0300 Subject: [PATCH 04/12] test: fix test, adds mocks for added methods (ReadToFile and PerformHttpRequestDownload) --- src/agent/communicator/tests/mocks/mock_http_client.hpp | 5 +++++ src/agent/communicator/tests/mocks/mock_http_socket.hpp | 6 ++++++ src/agent/tests/register_test.cpp | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/src/agent/communicator/tests/mocks/mock_http_client.hpp b/src/agent/communicator/tests/mocks/mock_http_client.hpp index bd110eccaa..dc2cbdbc59 100644 --- a/src/agent/communicator/tests/mocks/mock_http_client.hpp +++ b/src/agent/communicator/tests/mocks/mock_http_client.hpp @@ -42,4 +42,9 @@ class MockHttpClient : public http_client::IHttpClient const std::string& password, const bool useHttps), (override)); + + MOCK_METHOD(boost::beast::http::response, + PerformHttpRequestDownload, + (const http_client::HttpRequestParams& params, const std::string& output_file), + (override)); }; diff --git a/src/agent/communicator/tests/mocks/mock_http_socket.hpp b/src/agent/communicator/tests/mocks/mock_http_socket.hpp index 341a7c624a..b70ed0d3f9 100644 --- a/src/agent/communicator/tests/mocks/mock_http_socket.hpp +++ b/src/agent/communicator/tests/mocks/mock_http_socket.hpp @@ -21,6 +21,12 @@ class MockHttpSocket : public http_client::IHttpSocket MOCK_METHOD(void, Read, (boost::beast::http::response & res), (override)); + MOCK_METHOD(void, + ReadToFile, + (boost::beast::http::response_parser & res, + const std::string& output_file), + (override)); + MOCK_METHOD(boost::asio::awaitable, AsyncRead, (boost::beast::http::response & res, boost::beast::error_code& ec), diff --git a/src/agent/tests/register_test.cpp b/src/agent/tests/register_test.cpp index 64904148e7..ab4867a860 100644 --- a/src/agent/tests/register_test.cpp +++ b/src/agent/tests/register_test.cpp @@ -54,6 +54,11 @@ class MockHttpClient : public http_client::IHttpClient const std::string& password, const bool useHttps), (override)); + + MOCK_METHOD(boost::beast::http::response, + PerformHttpRequestDownload, + (const http_client::HttpRequestParams& params, const std::string& output_file), + (override)); }; class RegisterTest : public ::testing::Test From 1557bc909be8559523cb3410caaf5891b2236bc3 Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Tue, 15 Oct 2024 22:33:24 -0300 Subject: [PATCH 05/12] test: adds tests for PerformHttpRequestDownload method --- .../communicator/tests/http_client_test.cpp | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/agent/communicator/tests/http_client_test.cpp b/src/agent/communicator/tests/http_client_test.cpp index 858cd9fdb4..20ed7db426 100644 --- a/src/agent/communicator/tests/http_client_test.cpp +++ b/src/agent/communicator/tests/http_client_test.cpp @@ -481,6 +481,40 @@ TEST_F(HttpClientTest, AuthenticateWithUserPassword_Failure) EXPECT_FALSE(token.has_value()); } +TEST_F(HttpClientTest, PerformHttpRequestDownload_Success) +{ + SetupMockResolverFactory(); + SetupMockSocketFactory(); + + EXPECT_CALL(*mockResolver, Resolve(_, _)).WillOnce(Return(boost::asio::ip::tcp::resolver::results_type {})); + EXPECT_CALL(*mockSocket, Connect(_)).Times(1); + EXPECT_CALL(*mockSocket, Write(_)).Times(1); + EXPECT_CALL(*mockSocket, ReadToFile(_, _)) + .WillOnce([](auto& res, [[maybe_unused]] auto& output_file) + { res.get().result(boost::beast::http::status::ok); }); + + const http_client::HttpRequestParams params(boost::beast::http::verb::get, "localhost", "80", "/", true); + const std::string output_file = "output_file"; + const auto response = client->PerformHttpRequestDownload(params, output_file); + + EXPECT_EQ(response.result(), boost::beast::http::status::ok); +} + +TEST_F(HttpClientTest, PerformHttpRequestDownload_ExceptionThrown) +{ + SetupMockResolverFactory(); + + EXPECT_CALL(*mockResolver, Resolve(_, _)).WillOnce(Throw(std::runtime_error("Simulated resolution failure"))); + + const http_client::HttpRequestParams params(boost::beast::http::verb::get, "localhost", "80", "/", true); + const std::string output_file = "output_file"; + const auto response = client->PerformHttpRequestDownload(params, output_file); + + EXPECT_EQ(response.result(), boost::beast::http::status::internal_server_error); + EXPECT_TRUE(boost::beast::buffers_to_string(response.body().data()).find("Simulated resolution failure") != + std::string::npos); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); From 5e06b02ea6396581261bd4ee78a49bb5548d6172 Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Wed, 16 Oct 2024 11:43:53 -0300 Subject: [PATCH 06/12] fix: change the variable name style to groupList variable --- src/agent/agent_info/include/agent_info.hpp | 2 +- src/agent/agent_info/src/agent_info.cpp | 6 +++--- .../agent_info/src/agent_info_persistance.cpp | 14 +++++++------- .../agent_info/src/agent_info_persistance.hpp | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/agent/agent_info/include/agent_info.hpp b/src/agent/agent_info/include/agent_info.hpp index 4c3e914796..2d9dcbd524 100644 --- a/src/agent/agent_info/include/agent_info.hpp +++ b/src/agent/agent_info/include/agent_info.hpp @@ -17,7 +17,7 @@ class AgentInfo void SetName(const std::string& name); void SetKey(const std::string& key); void SetUUID(const std::string& uuid); - void SetGroups(const std::vector& group_list); + void SetGroups(const std::vector& groupList); private: std::string m_name; diff --git a/src/agent/agent_info/src/agent_info.cpp b/src/agent/agent_info/src/agent_info.cpp index e0b071659d..ae852e00f0 100644 --- a/src/agent/agent_info/src/agent_info.cpp +++ b/src/agent/agent_info/src/agent_info.cpp @@ -74,9 +74,9 @@ void AgentInfo::SetUUID(const std::string& uuid) m_uuid = uuid; } -void AgentInfo::SetGroups(const std::vector& group_list) +void AgentInfo::SetGroups(const std::vector& groupList) { AgentInfoPersistance agentInfoPersistance; - agentInfoPersistance.SetGroups(group_list); - m_groups = group_list; + agentInfoPersistance.SetGroups(groupList); + m_groups = groupList; } diff --git a/src/agent/agent_info/src/agent_info_persistance.cpp b/src/agent/agent_info/src/agent_info_persistance.cpp index 3633ecd7df..9d841b8bc8 100644 --- a/src/agent/agent_info/src/agent_info_persistance.cpp +++ b/src/agent/agent_info/src/agent_info_persistance.cpp @@ -154,7 +154,7 @@ std::string AgentInfoPersistance::GetAgentInfoValue(const std::string& column) c return value; } -void AgentInfoPersistance::SetAgentGroups(const std::vector& group_list) +void AgentInfoPersistance::SetAgentGroups(const std::vector& groupList) { try { @@ -164,7 +164,7 @@ void AgentInfoPersistance::SetAgentGroups(const std::vector& group_ SQLite::Statement query(*m_db, "INSERT INTO " + AGENT_GROUP_TABLE_NAME + " (name) VALUES (?);"); - for (const std::string& group : group_list) + for (const std::string& group : groupList) { query.bind(1, group); query.exec(); @@ -181,7 +181,7 @@ void AgentInfoPersistance::SetAgentGroups(const std::vector& group_ std::vector AgentInfoPersistance::GetAgentGroupList() const { - std::vector group_list; + std::vector groupList; try { @@ -189,7 +189,7 @@ std::vector AgentInfoPersistance::GetAgentGroupList() const while (query.executeStep()) { - group_list.push_back(query.getColumn(0).getString()); + groupList.push_back(query.getColumn(0).getString()); } } catch (const std::exception& e) @@ -197,7 +197,7 @@ std::vector AgentInfoPersistance::GetAgentGroupList() const LogError("Error getting agent group list: {}.", e.what()); } - return group_list; + return groupList; } std::string AgentInfoPersistance::GetName() const @@ -235,9 +235,9 @@ void AgentInfoPersistance::SetUUID(const std::string& uuid) SetAgentInfoValue("uuid", uuid); } -void AgentInfoPersistance::SetGroups(const std::vector& group_list) +void AgentInfoPersistance::SetGroups(const std::vector& groupList) { - SetAgentGroups(group_list); + SetAgentGroups(groupList); } void AgentInfoPersistance::ResetToDefault() diff --git a/src/agent/agent_info/src/agent_info_persistance.hpp b/src/agent/agent_info/src/agent_info_persistance.hpp index f3121b7a9a..f1a5b8c1b6 100644 --- a/src/agent/agent_info/src/agent_info_persistance.hpp +++ b/src/agent/agent_info/src/agent_info_persistance.hpp @@ -30,7 +30,7 @@ class AgentInfoPersistance void SetName(const std::string& name); void SetKey(const std::string& key); void SetUUID(const std::string& uuid); - void SetGroups(const std::vector& group_list); + void SetGroups(const std::vector& groupList); void ResetToDefault(); @@ -42,7 +42,7 @@ class AgentInfoPersistance void InsertDefaultAgentInfo(); void SetAgentInfoValue(const std::string& column, const std::string& value); std::string GetAgentInfoValue(const std::string& column) const; - void SetAgentGroups(const std::vector& group_list); + void SetAgentGroups(const std::vector& groupList); std::vector GetAgentGroupList() const; std::unique_ptr m_db; From fa6b0317db807a336848aba516d40c69d8c390bb Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Wed, 16 Oct 2024 12:19:57 -0300 Subject: [PATCH 07/12] fix: unifies the functions for saving and retrieving groups in the AgentInfoPersistance class. --- .../agent_info/src/agent_info_persistance.cpp | 74 ++++++++----------- .../agent_info/src/agent_info_persistance.hpp | 2 - 2 files changed, 32 insertions(+), 44 deletions(-) diff --git a/src/agent/agent_info/src/agent_info_persistance.cpp b/src/agent/agent_info/src/agent_info_persistance.cpp index 9d841b8bc8..53ffaca85c 100644 --- a/src/agent/agent_info/src/agent_info_persistance.cpp +++ b/src/agent/agent_info/src/agent_info_persistance.cpp @@ -154,32 +154,22 @@ std::string AgentInfoPersistance::GetAgentInfoValue(const std::string& column) c return value; } -void AgentInfoPersistance::SetAgentGroups(const std::vector& groupList) +std::string AgentInfoPersistance::GetName() const { - try - { - SQLite::Transaction transaction(*m_db); - - m_db->exec("DELETE FROM " + AGENT_GROUP_TABLE_NAME + ";"); - - SQLite::Statement query(*m_db, "INSERT INTO " + AGENT_GROUP_TABLE_NAME + " (name) VALUES (?);"); + return GetAgentInfoValue("name"); +} - for (const std::string& group : groupList) - { - query.bind(1, group); - query.exec(); - query.reset(); - } +std::string AgentInfoPersistance::GetKey() const +{ + return GetAgentInfoValue("key"); +} - transaction.commit(); - } - catch (const std::exception& e) - { - LogError("Error inserting group: {}.", e.what()); - } +std::string AgentInfoPersistance::GetUUID() const +{ + return GetAgentInfoValue("uuid"); } -std::vector AgentInfoPersistance::GetAgentGroupList() const +std::vector AgentInfoPersistance::GetGroups() const { std::vector groupList; @@ -200,26 +190,6 @@ std::vector AgentInfoPersistance::GetAgentGroupList() const return groupList; } -std::string AgentInfoPersistance::GetName() const -{ - return GetAgentInfoValue("name"); -} - -std::string AgentInfoPersistance::GetKey() const -{ - return GetAgentInfoValue("key"); -} - -std::string AgentInfoPersistance::GetUUID() const -{ - return GetAgentInfoValue("uuid"); -} - -std::vector AgentInfoPersistance::GetGroups() const -{ - return GetAgentGroupList(); -} - void AgentInfoPersistance::SetName(const std::string& name) { SetAgentInfoValue("name", name); @@ -237,7 +207,27 @@ void AgentInfoPersistance::SetUUID(const std::string& uuid) void AgentInfoPersistance::SetGroups(const std::vector& groupList) { - SetAgentGroups(groupList); + try + { + SQLite::Transaction transaction(*m_db); + + m_db->exec("DELETE FROM " + AGENT_GROUP_TABLE_NAME + ";"); + + SQLite::Statement query(*m_db, "INSERT INTO " + AGENT_GROUP_TABLE_NAME + " (name) VALUES (?);"); + + for (const std::string& group : groupList) + { + query.bind(1, group); + query.exec(); + query.reset(); + } + + transaction.commit(); + } + catch (const std::exception& e) + { + LogError("Error inserting group: {}.", e.what()); + } } void AgentInfoPersistance::ResetToDefault() diff --git a/src/agent/agent_info/src/agent_info_persistance.hpp b/src/agent/agent_info/src/agent_info_persistance.hpp index f1a5b8c1b6..b4425bb33c 100644 --- a/src/agent/agent_info/src/agent_info_persistance.hpp +++ b/src/agent/agent_info/src/agent_info_persistance.hpp @@ -42,8 +42,6 @@ class AgentInfoPersistance void InsertDefaultAgentInfo(); void SetAgentInfoValue(const std::string& column, const std::string& value); std::string GetAgentInfoValue(const std::string& column) const; - void SetAgentGroups(const std::vector& groupList); - std::vector GetAgentGroupList() const; std::unique_ptr m_db; }; From 695290047e099e1889788be29ba0af679b01c0c2 Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Wed, 16 Oct 2024 16:10:26 -0300 Subject: [PATCH 08/12] fix: create a function to avoid duplicate code in the ReadToFile methods of the HttpSocket and HttpsSocket classes. --- .../communicator/include/http_client.hpp | 2 +- .../communicator/include/ihttp_client.hpp | 2 +- .../communicator/include/ihttp_socket.hpp | 2 +- src/agent/communicator/src/http_client.cpp | 4 +- .../communicator/src/http_client_utils.hpp | 62 +++++++++++++++++++ src/agent/communicator/src/http_socket.hpp | 49 +-------------- src/agent/communicator/src/https_socket.hpp | 48 +------------- .../communicator/tests/http_client_test.cpp | 10 +-- .../tests/mocks/mock_http_client.hpp | 2 +- .../tests/mocks/mock_http_socket.hpp | 2 +- src/agent/tests/register_test.cpp | 2 +- 11 files changed, 80 insertions(+), 105 deletions(-) create mode 100644 src/agent/communicator/src/http_client_utils.hpp diff --git a/src/agent/communicator/include/http_client.hpp b/src/agent/communicator/include/http_client.hpp index dc218f9d55..b56c83d779 100644 --- a/src/agent/communicator/include/http_client.hpp +++ b/src/agent/communicator/include/http_client.hpp @@ -48,7 +48,7 @@ namespace http_client const bool useHttps) override; boost::beast::http::response - PerformHttpRequestDownload(const HttpRequestParams& params, const std::string& output_file) override; + PerformHttpRequestDownload(const HttpRequestParams& params, const std::string& dstFilePath) override; private: std::shared_ptr m_resolverFactory; diff --git a/src/agent/communicator/include/ihttp_client.hpp b/src/agent/communicator/include/ihttp_client.hpp index 27c14da398..fa21375741 100644 --- a/src/agent/communicator/include/ihttp_client.hpp +++ b/src/agent/communicator/include/ihttp_client.hpp @@ -82,6 +82,6 @@ namespace http_client const bool useHttps) = 0; virtual boost::beast::http::response - PerformHttpRequestDownload(const HttpRequestParams& params, const std::string& output_file) = 0; + PerformHttpRequestDownload(const HttpRequestParams& params, const std::string& dstFilePath) = 0; }; } // namespace http_client diff --git a/src/agent/communicator/include/ihttp_socket.hpp b/src/agent/communicator/include/ihttp_socket.hpp index 4ea6c46ce5..3fc50c1696 100644 --- a/src/agent/communicator/include/ihttp_socket.hpp +++ b/src/agent/communicator/include/ihttp_socket.hpp @@ -24,7 +24,7 @@ namespace http_client virtual void Read(boost::beast::http::response& res) = 0; virtual void ReadToFile(boost::beast::http::response_parser& res, - const std::string& output_file) = 0; + const std::string& dstFilePath) = 0; virtual boost::asio::awaitable AsyncRead(boost::beast::http::response& res, diff --git a/src/agent/communicator/src/http_client.cpp b/src/agent/communicator/src/http_client.cpp index 4a5f60d7c3..04531d87c9 100644 --- a/src/agent/communicator/src/http_client.cpp +++ b/src/agent/communicator/src/http_client.cpp @@ -248,7 +248,7 @@ namespace http_client } boost::beast::http::response - HttpClient::PerformHttpRequestDownload(const HttpRequestParams& params, const std::string& output_file) + HttpClient::PerformHttpRequestDownload(const HttpRequestParams& params, const std::string& dstFilePath) { boost::beast::http::response_parser res_parser; @@ -264,7 +264,7 @@ namespace http_client const auto req = CreateHttpRequest(params); socket->Write(req); - socket->ReadToFile(res_parser, output_file); + socket->ReadToFile(res_parser, dstFilePath); LogDebug("Response code: {}.", res_parser.get().result_int()); } diff --git a/src/agent/communicator/src/http_client_utils.hpp b/src/agent/communicator/src/http_client_utils.hpp new file mode 100644 index 0000000000..7ac8a46b34 --- /dev/null +++ b/src/agent/communicator/src/http_client_utils.hpp @@ -0,0 +1,62 @@ +#include + +#include +#include + +#include +#include + +namespace http_client_utils +{ + template + void ReadToFile(SocketType& socket, + boost::beast::http::response_parser& res, + const std::string& dstFilePath) + { + res.body_limit(std::numeric_limits::max()); + boost::beast::flat_buffer buffer; + boost::system::error_code error; + + boost::beast::http::read_header(socket, buffer, res, error); + + if (error && error != boost::beast::http::error::need_buffer) + { + throw boost::system::system_error(error); + } + + unsigned int statusCode = res.get().result_int(); + if (statusCode != 200) + { + return; + } + + std::ofstream file(dstFilePath, std::ios::binary); + if (!file) + { + throw std::runtime_error("The file could not be opened for writing: " + dstFilePath); + } + + while (!res.is_done()) + { + boost::beast::http::read(socket, buffer, res, error); + + if (error && error != boost::beast::http::error::need_buffer && error != boost::asio::error::eof) + { + file.close(); + throw boost::system::system_error(error); + } + + auto bodyData = res.get().body().data(); + + for (auto const& bufferSeq : bodyData) + { + std::streamsize chunkSize = static_cast(bufferSeq.size()); + file.write(static_cast(bufferSeq.data()), chunkSize); + } + + res.get().body().consume(res.get().body().size()); + } + + file.close(); + } +} // namespace http_client_utils diff --git a/src/agent/communicator/src/http_socket.hpp b/src/agent/communicator/src/http_socket.hpp index d91ba772e5..d6bd79e048 100644 --- a/src/agent/communicator/src/http_socket.hpp +++ b/src/agent/communicator/src/http_socket.hpp @@ -1,3 +1,4 @@ +#include "http_client_utils.hpp" #include #include @@ -46,53 +47,9 @@ namespace http_client } void ReadToFile(boost::beast::http::response_parser& res, - const std::string& output_file) override + const std::string& dstFilePath) override { - res.body_limit(std::numeric_limits::max()); - boost::beast::flat_buffer buffer; - boost::system::error_code error; - - boost::beast::http::read_header(m_socket, buffer, res, error); - - if (error && error != boost::beast::http::error::need_buffer) - { - throw boost::system::system_error(error); - } - - unsigned int status_code = res.get().result_int(); - if (status_code != 200) - { - return; - } - - std::ofstream file(output_file, std::ios::binary); - if (!file) - { - throw std::runtime_error("The file could not be opened for writing: " + output_file); - } - - while (!res.is_done()) - { - boost::beast::http::read(m_socket, buffer, res, error); - - if (error && error != boost::beast::http::error::need_buffer && error != boost::asio::error::eof) - { - file.close(); - throw boost::system::system_error(error); - } - - auto body_data = res.get().body().data(); - - for (auto const& buffer_seq : body_data) - { - std::streamsize chunk_size = static_cast(buffer_seq.size()); - file.write(static_cast(buffer_seq.data()), chunk_size); - } - - res.get().body().consume(res.get().body().size()); - } - - file.close(); + http_client_utils::ReadToFile(m_socket, res, dstFilePath); } boost::asio::awaitable AsyncRead(boost::beast::http::response& res, diff --git a/src/agent/communicator/src/https_socket.hpp b/src/agent/communicator/src/https_socket.hpp index 3f6fa6019f..75490e0d5b 100644 --- a/src/agent/communicator/src/https_socket.hpp +++ b/src/agent/communicator/src/https_socket.hpp @@ -52,53 +52,9 @@ namespace http_client } void ReadToFile(boost::beast::http::response_parser& res, - const std::string& output_file) override + const std::string& dstFilePath) override { - res.body_limit(std::numeric_limits::max()); - boost::beast::flat_buffer buffer; - boost::system::error_code error; - - boost::beast::http::read_header(m_ssl_socket, buffer, res, error); - - if (error && error != boost::beast::http::error::need_buffer) - { - throw boost::system::system_error(error); - } - - unsigned int status_code = res.get().result_int(); - if (status_code != 200) - { - return; - } - - std::ofstream file(output_file, std::ios::binary); - if (!file) - { - throw std::runtime_error("The file could not be opened for writing: " + output_file); - } - - while (!res.is_done()) - { - boost::beast::http::read(m_ssl_socket, buffer, res, error); - - if (error && error != boost::beast::http::error::need_buffer && error != boost::asio::error::eof) - { - file.close(); - throw boost::system::system_error(error); - } - - auto body_data = res.get().body().data(); - - for (auto const& buffer_seq : body_data) - { - std::streamsize chunk_size = static_cast(buffer_seq.size()); - file.write(static_cast(buffer_seq.data()), chunk_size); - } - - res.get().body().consume(res.get().body().size()); - } - - file.close(); + http_client_utils::ReadToFile(m_ssl_socket, res, dstFilePath); } boost::asio::awaitable AsyncRead(boost::beast::http::response& res, diff --git a/src/agent/communicator/tests/http_client_test.cpp b/src/agent/communicator/tests/http_client_test.cpp index 20ed7db426..082ba760f4 100644 --- a/src/agent/communicator/tests/http_client_test.cpp +++ b/src/agent/communicator/tests/http_client_test.cpp @@ -490,12 +490,12 @@ TEST_F(HttpClientTest, PerformHttpRequestDownload_Success) EXPECT_CALL(*mockSocket, Connect(_)).Times(1); EXPECT_CALL(*mockSocket, Write(_)).Times(1); EXPECT_CALL(*mockSocket, ReadToFile(_, _)) - .WillOnce([](auto& res, [[maybe_unused]] auto& output_file) + .WillOnce([](auto& res, [[maybe_unused]] auto& dstFilePath) { res.get().result(boost::beast::http::status::ok); }); const http_client::HttpRequestParams params(boost::beast::http::verb::get, "localhost", "80", "/", true); - const std::string output_file = "output_file"; - const auto response = client->PerformHttpRequestDownload(params, output_file); + const std::string dstFilePath = "dstFilePath"; + const auto response = client->PerformHttpRequestDownload(params, dstFilePath); EXPECT_EQ(response.result(), boost::beast::http::status::ok); } @@ -507,8 +507,8 @@ TEST_F(HttpClientTest, PerformHttpRequestDownload_ExceptionThrown) EXPECT_CALL(*mockResolver, Resolve(_, _)).WillOnce(Throw(std::runtime_error("Simulated resolution failure"))); const http_client::HttpRequestParams params(boost::beast::http::verb::get, "localhost", "80", "/", true); - const std::string output_file = "output_file"; - const auto response = client->PerformHttpRequestDownload(params, output_file); + const std::string dstFilePath = "dstFilePath"; + const auto response = client->PerformHttpRequestDownload(params, dstFilePath); EXPECT_EQ(response.result(), boost::beast::http::status::internal_server_error); EXPECT_TRUE(boost::beast::buffers_to_string(response.body().data()).find("Simulated resolution failure") != diff --git a/src/agent/communicator/tests/mocks/mock_http_client.hpp b/src/agent/communicator/tests/mocks/mock_http_client.hpp index dc2cbdbc59..3ddc1c4ef9 100644 --- a/src/agent/communicator/tests/mocks/mock_http_client.hpp +++ b/src/agent/communicator/tests/mocks/mock_http_client.hpp @@ -45,6 +45,6 @@ class MockHttpClient : public http_client::IHttpClient MOCK_METHOD(boost::beast::http::response, PerformHttpRequestDownload, - (const http_client::HttpRequestParams& params, const std::string& output_file), + (const http_client::HttpRequestParams& params, const std::string& dstFilePath), (override)); }; diff --git a/src/agent/communicator/tests/mocks/mock_http_socket.hpp b/src/agent/communicator/tests/mocks/mock_http_socket.hpp index b70ed0d3f9..1408bafef0 100644 --- a/src/agent/communicator/tests/mocks/mock_http_socket.hpp +++ b/src/agent/communicator/tests/mocks/mock_http_socket.hpp @@ -24,7 +24,7 @@ class MockHttpSocket : public http_client::IHttpSocket MOCK_METHOD(void, ReadToFile, (boost::beast::http::response_parser & res, - const std::string& output_file), + const std::string& dstFilePath), (override)); MOCK_METHOD(boost::asio::awaitable, diff --git a/src/agent/tests/register_test.cpp b/src/agent/tests/register_test.cpp index ab4867a860..8cdd536c64 100644 --- a/src/agent/tests/register_test.cpp +++ b/src/agent/tests/register_test.cpp @@ -57,7 +57,7 @@ class MockHttpClient : public http_client::IHttpClient MOCK_METHOD(boost::beast::http::response, PerformHttpRequestDownload, - (const http_client::HttpRequestParams& params, const std::string& output_file), + (const http_client::HttpRequestParams& params, const std::string& dstFilePath), (override)); }; From b4ff61a8e1bc3e7602a7fee6d5075740e1978ea1 Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Wed, 16 Oct 2024 18:04:40 -0300 Subject: [PATCH 09/12] feat: change to use a constant for the agent_info table name --- .../agent_info/src/agent_info_persistance.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/agent/agent_info/src/agent_info_persistance.cpp b/src/agent/agent_info/src/agent_info_persistance.cpp index 53ffaca85c..60b62c0560 100644 --- a/src/agent/agent_info/src/agent_info_persistance.cpp +++ b/src/agent/agent_info/src/agent_info_persistance.cpp @@ -57,7 +57,7 @@ bool AgentInfoPersistance::AgentInfoIsEmpty() const { try { - SQLite::Statement query(*m_db, "SELECT COUNT(*) FROM agent_info;"); + SQLite::Statement query(*m_db, "SELECT COUNT(*) FROM " + AGENT_INFO_TABLE_NAME + ";"); query.executeStep(); const auto count = query.getColumn(0).getInt(); return count == 0; @@ -74,7 +74,8 @@ void AgentInfoPersistance::CreateAgentInfoTable() { try { - m_db->exec("CREATE TABLE IF NOT EXISTS agent_info (" + m_db->exec("CREATE TABLE IF NOT EXISTS " + AGENT_INFO_TABLE_NAME + + " (" "name TEXT, " "key TEXT, " "uuid TEXT" @@ -106,13 +107,14 @@ void AgentInfoPersistance::InsertDefaultAgentInfo() { try { - SQLite::Statement query(*m_db, "SELECT COUNT(*) FROM agent_info;"); + SQLite::Statement query(*m_db, "SELECT COUNT(*) FROM " + AGENT_INFO_TABLE_NAME + ";"); query.executeStep(); const auto count = query.getColumn(0).getInt(); if (count == 0) { - SQLite::Statement insert(*m_db, "INSERT INTO agent_info (name, key, uuid) VALUES (?, ?, ?);"); + SQLite::Statement insert(*m_db, + "INSERT INTO " + AGENT_INFO_TABLE_NAME + " (name, key, uuid) VALUES (?, ?, ?);"); insert.exec(); } } @@ -126,7 +128,7 @@ void AgentInfoPersistance::SetAgentInfoValue(const std::string& column, const st { try { - SQLite::Statement query(*m_db, "UPDATE agent_info SET " + column + " = ?;"); + SQLite::Statement query(*m_db, "UPDATE " + AGENT_INFO_TABLE_NAME + " SET " + column + " = ?;"); query.bind(1, value); query.exec(); } @@ -141,7 +143,7 @@ std::string AgentInfoPersistance::GetAgentInfoValue(const std::string& column) c std::string value; try { - SQLite::Statement query(*m_db, "SELECT " + column + " FROM agent_info LIMIT 1;"); + SQLite::Statement query(*m_db, "SELECT " + column + " FROM " + AGENT_INFO_TABLE_NAME + " LIMIT 1;"); if (query.executeStep()) { value = query.getColumn(0).getText(); From e6976c11b1d01e094e06420f1cb6075c0b103fdb Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Wed, 16 Oct 2024 18:12:47 -0300 Subject: [PATCH 10/12] test: add a test to check the delete in the SetGroups method --- .../agent_info/tests/agent_info_persistance_test.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/agent/agent_info/tests/agent_info_persistance_test.cpp b/src/agent/agent_info/tests/agent_info_persistance_test.cpp index 1516e4dade..924ee494b8 100644 --- a/src/agent/agent_info/tests/agent_info_persistance_test.cpp +++ b/src/agent/agent_info/tests/agent_info_persistance_test.cpp @@ -57,6 +57,16 @@ TEST_F(AgentInfoPersistanceTest, TestSetGroups) EXPECT_EQ(persistance->GetGroups(), newGroups); } +TEST_F(AgentInfoPersistanceTest, TestSetGroupsDelete) +{ + const std::vector oldGroups = {"group_1", "group_2"}; + const std::vector newGroups = {"group_3", "group_4"}; + persistance->SetGroups(oldGroups); + EXPECT_EQ(persistance->GetGroups(), oldGroups); + persistance->SetGroups(newGroups); + EXPECT_EQ(persistance->GetGroups(), newGroups); +} + TEST_F(AgentInfoPersistanceTest, TestResetToDefault) { const std::string newName = "new_name"; From 8dfcd92841f649394d5a1fb0568e2e454d911473 Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Thu, 17 Oct 2024 15:16:48 -0300 Subject: [PATCH 11/12] feat: adds the GetGroupConfigurationFromManager method to the Communicator class to perform group file download requests. --- .../communicator/include/communicator.hpp | 1 + src/agent/communicator/src/communicator.cpp | 16 +++++++ .../communicator/tests/communicator_test.cpp | 42 +++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/src/agent/communicator/include/communicator.hpp b/src/agent/communicator/include/communicator.hpp index 074c3e029a..45109c2d5d 100644 --- a/src/agent/communicator/include/communicator.hpp +++ b/src/agent/communicator/include/communicator.hpp @@ -31,6 +31,7 @@ namespace communicator boost::asio::awaitable StatelessMessageProcessingTask(std::function()> getMessages, std::function onSuccess); + bool GetGroupConfigurationFromManager(const std::string& groupName, const std::string& dstFilePath); void Stop(); diff --git a/src/agent/communicator/src/communicator.cpp b/src/agent/communicator/src/communicator.cpp index 89b7b2411b..02efd86244 100644 --- a/src/agent/communicator/src/communicator.cpp +++ b/src/agent/communicator/src/communicator.cpp @@ -209,6 +209,22 @@ namespace communicator } } + bool Communicator::GetGroupConfigurationFromManager(const std::string& groupName, const std::string& dstFilePath) + { + const auto reqParams = http_client::HttpRequestParams(boost::beast::http::verb::get, + m_managerIp, + m_port, + "/api/v1/files?file_name=" + groupName + ".conf", + m_useHttps, + *m_token, + "", + ""); + + const auto result = m_httpClient->PerformHttpRequestDownload(reqParams, dstFilePath); + + return result.result() == boost::beast::http::status::ok; + } + void Communicator::Stop() { m_keepRunning.store(false); diff --git a/src/agent/communicator/tests/communicator_test.cpp b/src/agent/communicator/tests/communicator_test.cpp index 946a49dbb1..6d419d15cc 100644 --- a/src/agent/communicator/tests/communicator_test.cpp +++ b/src/agent/communicator/tests/communicator_test.cpp @@ -179,6 +179,48 @@ TEST(CommunicatorTest, StatelessMessageProcessingTask_CallsWithValidToken) EXPECT_EQ(capturedToken, mockedToken); } +TEST(CommunicatorTest, GetGroupConfigurationFromManager_Success) +{ + auto mockHttpClient = std::make_unique(); + auto mockHttpClientPtr = mockHttpClient.get(); + + // not really a leak, as its lifetime is managed by the Communicator + testing::Mock::AllowLeak(mockHttpClientPtr); + auto communicatorPtr = + std::make_shared(std::move(mockHttpClient), "uuid", "key", nullptr); + + std::string groupName = "group1"; + std::string dstFilePath = "/path/to/file"; + + boost::beast::http::response mockResponse; + mockResponse.result(boost::beast::http::status::ok); + + EXPECT_CALL(*mockHttpClientPtr, PerformHttpRequestDownload(_, dstFilePath)).WillOnce(Return(mockResponse)); + + EXPECT_TRUE(communicatorPtr->GetGroupConfigurationFromManager(groupName, dstFilePath)); +} + +TEST(CommunicatorTest, GetGroupConfigurationFromManager_Error) +{ + auto mockHttpClient = std::make_unique(); + auto mockHttpClientPtr = mockHttpClient.get(); + + // not really a leak, as its lifetime is managed by the Communicator + testing::Mock::AllowLeak(mockHttpClientPtr); + auto communicatorPtr = + std::make_shared(std::move(mockHttpClient), "uuid", "key", nullptr); + + std::string groupName = "group1"; + std::string dstFilePath = "/path/to/file"; + + boost::beast::http::response mockResponse; + mockResponse.result(boost::beast::http::status::internal_server_error); + + EXPECT_CALL(*mockHttpClientPtr, PerformHttpRequestDownload(_, dstFilePath)).WillOnce(Return(mockResponse)); + + EXPECT_FALSE(communicatorPtr->GetGroupConfigurationFromManager(groupName, dstFilePath)); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); From 277505b7ccdb7806b0c28d812c0f4e514676b778 Mon Sep 17 00:00:00 2001 From: Nicolas Gomez Palacios Date: Thu, 17 Oct 2024 15:48:24 -0300 Subject: [PATCH 12/12] fix: fixes the runner for coverage check --- .github/workflows/coverage_check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage_check.yml b/.github/workflows/coverage_check.yml index 1f62736d7c..139177fd22 100644 --- a/.github/workflows/coverage_check.yml +++ b/.github/workflows/coverage_check.yml @@ -12,7 +12,7 @@ env: jobs: coverage: - runs-on: ubuntu-24 + runs-on: ubuntu-24.04 steps: - name: Checkout code