Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/monitor/AgentsStatusProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ void AgentsStatusProvider::observe(const AgentInformation& info)
.toStdString();

AgentConnection agentConn;
agentConn.connection = cpp_restapi::createQtConnection(
m_nam, address, {});
agentConn.connection = cpp_restapi::createQtConnection(m_nam, address, {});

m_connections.insert(info, std::move(agentConn));

Expand Down Expand Up @@ -112,14 +111,17 @@ void AgentsStatusProvider::fetchAgentInfo(const AgentInformation& info)
if (it == m_connections.end() || !it->connection)
return;

const std::string url = it->connection->url() + "/api/v1/info";
std::cout << "Fetching info from agent " << info.name().toStdString() << "\n";

QPointer<AgentsStatusProvider> self(this);
it->connection->fetch(url,
it->connection->fetch("api/v1/info",
[self, info](cpp_restapi::Response response)
{
if (!self)
return;

std::cout << "Got info response from agent " << info.name().toStdString() << "\n";

try
{
nlohmann::json j = nlohmann::json::parse(response.body);
Expand Down Expand Up @@ -168,6 +170,8 @@ void AgentsStatusProvider::handleSseEvent(const AgentInformation& info, const cp
if (it == m_connections.end())
return;

std::cout << "Got SSE event from agent " << info.name().toStdString() << "\n";

it->reconnectDelay = std::chrono::milliseconds{1000};
it->lastEventTime = std::chrono::steady_clock::now();
it->connected = true;
Expand Down
2 changes: 1 addition & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ if(BUILD_AGENT)
endif()

if(BUILD_MONITOR)
list(APPEND _test_deps monitorTests)
list(APPEND _test_deps monitorTests monitorIntegrationTests)
endif()

add_custom_target(RunUnitTests ALL
Expand Down
5 changes: 5 additions & 0 deletions tests/agent/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@

add_executable(agentTests
DiscStatusCalculatorTests.cpp
DiskTests.cpp
DmesgParserTests.cpp
LinuxDiskCollectorTests.cpp
LsblkOutputParserTests.cpp
OutputParsersUtilsTests.cpp
SmartCtlOutputParserTests.cpp
SmartHealthAnalyzerTests.cpp
VendorProfileTests.cpp
${PROJECT_SOURCE_DIR}/src/agent/Disk.cpp
${PROJECT_SOURCE_DIR}/src/agent/DiscStatusCalculator.cpp
${PROJECT_SOURCE_DIR}/src/agent/OutputParsersUtils.cpp
${PROJECT_SOURCE_DIR}/src/agent/SmartHealthAnalyzer.cpp
${PROJECT_SOURCE_DIR}/src/agent/linux/DmesgParser.cpp
${PROJECT_SOURCE_DIR}/src/agent/linux/LinuxDiskCollector.cpp
${PROJECT_SOURCE_DIR}/src/agent/linux/LsblkOutputParser.cpp
${PROJECT_SOURCE_DIR}/src/agent/linux/SmartCtlOutputParser.cpp
IPartitionsManagerMock.h
Expand Down
49 changes: 49 additions & 0 deletions tests/agent/DiskTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <gmock/gmock.h>

#include "Disk.h"


TEST(DiskTest, exposesConstructorValues)
{
Disk disk("sda", "Samsung SSD 870", 1024, "SSD");

EXPECT_EQ(disk.GetDeviceId(), "sda");
EXPECT_EQ(disk.GetModel(), "Samsung SSD 870");
EXPECT_EQ(disk.GetVendor(), "Samsung");
EXPECT_EQ(disk.GetCapacity(), 1024);
EXPECT_EQ(disk.GetDriveType(), "SSD");
}


TEST(DiskTest, detectsKnownVendorsFromModel)
{
const std::vector<std::pair<std::string, std::string>> cases = {
{"Samsung SSD 870", "Samsung"},
{"WDC WD10EFRX", "WDC"},
{"Western Digital Blue", "WDC"},
{"ST4000DM004", "Seagate"},
{"Seagate IronWolf", "Seagate"},
{"TOSHIBA HDWD110", "Toshiba"},
{"HGST HUS724040", "HGST"},
{"Hitachi HDS721010", "HGST"},
{"Intel SSDSC2", "Intel"},
{"Crucial MX500", "Micron"},
{"Micron 1100", "Micron"},
{"Kingston SA400", "Kingston"},
{"SanDisk SDSSDA", "SanDisk"},
};

for (const auto& [model, expectedVendor] : cases)
{
const Disk disk("disk", model);
EXPECT_EQ(disk.GetVendor(), expectedVendor) << model;
}
}


TEST(DiskTest, returnsEmptyVendorForUnknownOrShortModel)
{
EXPECT_TRUE(Disk("disk", "Generic Model").GetVendor().empty());
EXPECT_TRUE(Disk("disk", "S").GetVendor().empty());
EXPECT_TRUE(Disk("disk", "").GetVendor().empty());
}
57 changes: 57 additions & 0 deletions tests/agent/LinuxDiskCollectorTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <gmock/gmock.h>

#include "linux/LinuxDiskCollector.h"


using testing::ElementsAre;


TEST(LinuxDiskCollectorTest, detectsPartitionsFromLsblkEntries)
{
const std::vector<LsblkOutputParser::LsblkEntry> entries = {
{"sda", "disk", 1000, {"sda1", "sda2"}, 8, 0},
{"nvme0n1", "disk", 2000, {"nvme0n1p1"}, 259, 0},
};

LinuxDiskCollector collector(entries);

EXPECT_TRUE(collector.isPartition("sda1"));
EXPECT_TRUE(collector.isPartition("sda2"));
EXPECT_TRUE(collector.isPartition("nvme0n1p1"));
EXPECT_FALSE(collector.isPartition("sda"));
EXPECT_FALSE(collector.isPartition("missing"));
}


TEST(LinuxDiskCollectorTest, mapsPartitionToParentDisk)
{
const std::vector<LsblkOutputParser::LsblkEntry> entries = {
{"sda", "disk", 1000, {"sda1", "sda2"}, 8, 0},
{"sdb", "disk", 2000, {"sdb1"}, 8, 16},
};

LinuxDiskCollector collector(entries);

EXPECT_EQ(collector.diskForPartition("sda1"), "sda");
EXPECT_EQ(collector.diskForPartition("sda2"), "sda");
EXPECT_EQ(collector.diskForPartition("sdb1"), "sdb");
EXPECT_TRUE(collector.diskForPartition("sdc1").empty());
}


TEST(LinuxDiskCollectorTest, buildsDiskListFromEntries)
{
const std::vector<LsblkOutputParser::LsblkEntry> entries = {
{"unit-test-disk-a", "disk", 1000, {}, 8, 0},
{"unit-test-disk-b", "disk", 2000, {}, 8, 16},
};

LinuxDiskCollector collector(entries);
const auto disks = collector.GetDisksList();

ASSERT_EQ(disks.size(), 2);
EXPECT_EQ(disks[0].GetDeviceId(), "unit-test-disk-a");
EXPECT_EQ(disks[0].GetCapacity(), 1000);
EXPECT_EQ(disks[1].GetDeviceId(), "unit-test-disk-b");
EXPECT_EQ(disks[1].GetCapacity(), 2000);
}
29 changes: 29 additions & 0 deletions tests/agent/OutputParsersUtilsTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <gmock/gmock.h>

#include "OutputParsersUtils.h"


using testing::ElementsAre;


TEST(OutputParsersUtilsTest, trimsLinesAndDropsOuterEmptyLines)
{
const auto result = ParsersUtils::clean("\n header \n\tvalue\t\n\n tail \n\n");

EXPECT_THAT(result, ElementsAre("header", "value", "", "tail"));
}


TEST(OutputParsersUtilsTest, preservesInnerEmptyLines)
{
const auto result = ParsersUtils::clean("first\n\nsecond");

EXPECT_THAT(result, ElementsAre("first", "", "second"));
}


TEST(OutputParsersUtilsTest, returnsEmptyListForWhitespaceOnlyInput)
{
EXPECT_TRUE(ParsersUtils::clean(" \n\t\n\r\n").empty());
EXPECT_TRUE(ParsersUtils::clean("").empty());
}
33 changes: 33 additions & 0 deletions tests/agent/VendorProfileTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <gmock/gmock.h>

#include "VendorProfile.h"


TEST(VendorProfileTest, genericProfileReturnsRawValue)
{
GenericProfile profile;

EXPECT_EQ(profile.interpretRawValue(0x01, 0x112233445566LL), 0x112233445566LL);
EXPECT_EQ(profile.interpretRawValue(0xC3, -10), -10);
}


TEST(VendorProfileTest, samsungProfileUsesLower32BitsForPackedAttributes)
{
SamsungProfile profile;

EXPECT_EQ(profile.interpretRawValue(0x01, 0x112233445566LL), 0x33445566LL);
EXPECT_EQ(profile.interpretRawValue(0x07, 0x112233445566LL), 0x33445566LL);
EXPECT_EQ(profile.interpretRawValue(0x05, 0x112233445566LL), 0x112233445566LL);
}


TEST(VendorProfileTest, seagateProfileUsesLower32BitsForPackedAttributes)
{
SeagateProfile profile;

EXPECT_EQ(profile.interpretRawValue(0x01, 0x112233445566LL), 0x33445566LL);
EXPECT_EQ(profile.interpretRawValue(0x07, 0x112233445566LL), 0x33445566LL);
EXPECT_EQ(profile.interpretRawValue(0xC3, 0x112233445566LL), 0x33445566LL);
EXPECT_EQ(profile.interpretRawValue(0x05, 0x112233445566LL), 0x112233445566LL);
}
2 changes: 2 additions & 0 deletions tests/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@

add_executable(commonTests
ProbeStatusTests.cpp
SmartDataTests.cpp
SerializationTests.cpp
UtilsTests.cpp
)

target_include_directories(commonTests
Expand Down
19 changes: 19 additions & 0 deletions tests/common/SmartDataTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <gmock/gmock.h>

#include "SmartData.h"


TEST(SmartDataTest, returnsCanonicalNameForKnownAttribute)
{
EXPECT_EQ(SmartData::GetCanonicalName(0x01), "Raw_Read_Error_Rate");
EXPECT_EQ(SmartData::GetCanonicalName(0x05), "Reallocated_Sector_Ct");
EXPECT_EQ(SmartData::GetCanonicalName(0xC5), "Current_Pending_Sector");
EXPECT_EQ(SmartData::GetCanonicalName(0xFE), "Free_Fall_Sensor");
}


TEST(SmartDataTest, returnsStableUnknownNameForUnknownAttribute)
{
EXPECT_EQ(SmartData::GetCanonicalName(0x80), "Unknown_Attribute_128");
EXPECT_EQ(SmartData::GetCanonicalName(0xFF), "Unknown_Attribute_255");
}
36 changes: 36 additions & 0 deletions tests/common/UtilsTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <gmock/gmock.h>

#include "Utils.h"


TEST(UtilsTest, formatsBytesUsingBinaryUnits)
{
EXPECT_EQ(formatBytes(0), "0 B");
EXPECT_EQ(formatBytes(1023), "1023 B");
EXPECT_EQ(formatBytes(1024), "1.00 KiB");
EXPECT_EQ(formatBytes(1536), "1.50 KiB");
EXPECT_EQ(formatBytes(1024ULL * 1024ULL * 1024ULL), "1.00 GiB");
}


TEST(UtilsTest, returnsEmptyTableForNoRows)
{
std::vector<std::vector<std::string>> rows;

EXPECT_TRUE(formatTable(rows).empty());
}


TEST(UtilsTest, formatsRowsIntoPaddedColumns)
{
std::vector<std::vector<std::string>> rows = {
{"Name", "Health"},
{"sda", "GOOD"},
{"nvme0n1", "BAD"},
};

EXPECT_EQ(formatTable(rows),
"Name Health \n"
"sda GOOD \n"
"nvme0n1 BAD \n");
}
49 changes: 49 additions & 0 deletions tests/monitor/AgentInformationTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <gmock/gmock.h>

#include <QSet>

#include "AgentInformation.hpp"


TEST(AgentInformationTest, exposesConstructorValues)
{
const AgentInformation info("agent", QHostAddress("192.168.1.10"), 1630,
AgentInformation::DetectionSource::Hardcoded);

EXPECT_EQ(info.name(), "agent");
EXPECT_EQ(info.host(), QHostAddress("192.168.1.10"));
EXPECT_EQ(info.port(), 1630);
EXPECT_EQ(info.detectionSource(), AgentInformation::DetectionSource::Hardcoded);
}


TEST(AgentInformationTest, equalityAndHashUseEndpointIdentity)
{
const AgentInformation zeroConf("agent", QHostAddress("192.168.1.10"), 1630,
AgentInformation::DetectionSource::ZeroConf);
const AgentInformation hardcoded("agent", QHostAddress("192.168.1.10"), 1630,
AgentInformation::DetectionSource::Hardcoded);

EXPECT_EQ(zeroConf, hardcoded);
EXPECT_EQ(qHash(zeroConf, 0), qHash(hardcoded, 0));

QSet<AgentInformation> uniqueAgents;
uniqueAgents.insert(zeroConf);
uniqueAgents.insert(hardcoded);

EXPECT_EQ(uniqueAgents.size(), 1);
}


TEST(AgentInformationTest, endpointDifferencesMakeAgentsDifferent)
{
const AgentInformation base("agent", QHostAddress("192.168.1.10"), 1630,
AgentInformation::DetectionSource::Hardcoded);

EXPECT_FALSE(base == AgentInformation("other", QHostAddress("192.168.1.10"), 1630,
AgentInformation::DetectionSource::Hardcoded));
EXPECT_FALSE(base == AgentInformation("agent", QHostAddress("192.168.1.11"), 1630,
AgentInformation::DetectionSource::Hardcoded));
EXPECT_FALSE(base == AgentInformation("agent", QHostAddress("192.168.1.10"), 1631,
AgentInformation::DetectionSource::Hardcoded));
}
2 changes: 1 addition & 1 deletion tests/monitor/AgentsListTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ TEST(AgentsListTest, listofAvailableRoles)
listOfRoles.append(it.value());

EXPECT_THAT(listOfRoles, IsSupersetOf( {"agentName", "agentHealth", "agentDetectionType",
"agentHost", "agentPort", "agentConnectionState"} ));
"agentHost", "agentPort", "agentConnectionState"} ));
}


Expand Down
Loading
Loading