Skip to content

Commit ddc899c

Browse files
committed
Adding logger tests
1 parent 9088d9f commit ddc899c

File tree

2 files changed

+296
-0
lines changed

2 files changed

+296
-0
lines changed

projects/aqlprofile/src/core/tests/CMakeLists.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,30 @@ gtest_add_tests(
149149
set_tests_properties(
150150
${pm4-factory-test_TESTS} PROPERTIES TIMEOUT 45 LABELS "unittests" FAIL_REGULAR_EXPRESSION
151151
"${AQLPROFILE_DEFAULT_FAIL_REGEX}")
152+
153+
# Add tests for logger
154+
add_executable(logger-test)
155+
SET(AQLPROFILE_LOGGER_SOURCES
156+
${CMAKE_CURRENT_SOURCE_DIR}/logger_tests.cpp
157+
)
158+
target_sources(logger-test PRIVATE ${AQLPROFILE_LOGGER_SOURCES})
159+
target_include_directories(logger-test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${LIB_DIR} ${LIB_DIR}/core/include)
160+
target_link_libraries(
161+
logger-test
162+
PRIVATE
163+
GTest::gtest
164+
GTest::gtest_main
165+
GTest::gmock
166+
GTest::gmock_main
167+
${CMAKE_DL_LIBS})
168+
169+
gtest_add_tests(
170+
TARGET logger-test
171+
SOURCES ${AQLPROFILE_LOGGER_SOURCES}
172+
TEST_LIST logger-test_TESTS
173+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
174+
175+
set_tests_properties(
176+
${logger-test_TESTS} PROPERTIES TIMEOUT 45 LABELS "unittests" FAIL_REGULAR_EXPRESSION
177+
"${AQLPROFILE_DEFAULT_FAIL_REGEX}")
178+
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
#include <gtest/gtest.h>
2+
#include <gmock/gmock.h>
3+
#include <fstream>
4+
#include <filesystem>
5+
#include <thread>
6+
#include <chrono>
7+
#include <sstream>
8+
#include <cstdlib>
9+
#include <unistd.h>
10+
11+
#include "../logger.h"
12+
13+
// Define static members for Logger class
14+
namespace aql_profile {
15+
Logger::mutex_t Logger::mutex_;
16+
Logger* Logger::instance_ = nullptr;
17+
}
18+
19+
namespace aql_profile {
20+
21+
class LoggerTest : public ::testing::Test {
22+
protected:
23+
void SetUp() override {
24+
// Clean up any existing instance
25+
Logger::Destroy();
26+
27+
// Remove any existing log file
28+
if (std::filesystem::exists(log_file_path_)) {
29+
std::filesystem::remove(log_file_path_);
30+
}
31+
32+
// Clear environment variable
33+
unsetenv("HSA_VEN_AMD_AQLPROFILE_LOG");
34+
}
35+
36+
void TearDown() override {
37+
// Clean up after each test
38+
Logger::Destroy();
39+
unsetenv("HSA_VEN_AMD_AQLPROFILE_LOG");
40+
41+
// Remove test log file
42+
if (std::filesystem::exists(log_file_path_)) {
43+
std::filesystem::remove(log_file_path_);
44+
}
45+
}
46+
47+
const std::string log_file_path_ = "/tmp/aql_profile_log.txt";
48+
49+
// Helper function to read log file content
50+
std::string ReadLogFile() {
51+
std::ifstream file(log_file_path_);
52+
if (!file.is_open()) return "";
53+
54+
std::stringstream buffer;
55+
buffer << file.rdbuf();
56+
return buffer.str();
57+
}
58+
59+
// Helper function to enable file logging
60+
void EnableFileLogging() {
61+
setenv("HSA_VEN_AMD_AQLPROFILE_LOG", "1", 1);
62+
}
63+
};
64+
65+
// Test singleton pattern
66+
TEST_F(LoggerTest, SingletonPattern) {
67+
Logger& logger1 = Logger::Instance();
68+
Logger& logger2 = Logger::Instance();
69+
70+
// Should be the same instance
71+
EXPECT_EQ(&logger1, &logger2);
72+
}
73+
74+
// Test basic logging without file output
75+
TEST_F(LoggerTest, BasicLoggingWithoutFile) {
76+
Logger& logger = Logger::Instance();
77+
78+
// Should not crash when logging without file
79+
logger << "Test message";
80+
81+
// Verify log file doesn't exist
82+
EXPECT_FALSE(std::filesystem::exists(log_file_path_));
83+
}
84+
85+
// Test basic logging with file output
86+
TEST_F(LoggerTest, BasicLoggingWithFile) {
87+
EnableFileLogging();
88+
89+
Logger& logger = Logger::Instance();
90+
logger << "Test message";
91+
92+
// Give some time for file operations
93+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
94+
95+
// Verify log file exists and contains content
96+
EXPECT_TRUE(std::filesystem::exists(log_file_path_));
97+
98+
std::string content = ReadLogFile();
99+
EXPECT_FALSE(content.empty());
100+
EXPECT_THAT(content, testing::HasSubstr("Test message"));
101+
EXPECT_THAT(content, testing::HasSubstr("pid"));
102+
EXPECT_THAT(content, testing::HasSubstr("tid"));
103+
}
104+
105+
// Test streaming operations
106+
TEST_F(LoggerTest, StreamingOperations) {
107+
EnableFileLogging();
108+
109+
Logger& logger = Logger::Instance();
110+
logger << "Number: " << 42 << " String: " << "test" << " Float: " << 3.14;
111+
112+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
113+
114+
std::string content = ReadLogFile();
115+
EXPECT_THAT(content, testing::HasSubstr("Number: 42"));
116+
EXPECT_THAT(content, testing::HasSubstr("String: test"));
117+
EXPECT_THAT(content, testing::HasSubstr("Float: 3.14"));
118+
}
119+
120+
// Test endl manipulator
121+
TEST_F(LoggerTest, EndlManipulator) {
122+
EnableFileLogging();
123+
124+
Logger& logger = Logger::Instance();
125+
logger << "First line" << Logger::endl << "Second line";
126+
127+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
128+
129+
std::string content = ReadLogFile();
130+
EXPECT_THAT(content, testing::HasSubstr("First line"));
131+
EXPECT_THAT(content, testing::HasSubstr("Second line"));
132+
133+
// Should have multiple log entries with timestamps
134+
size_t pid_count = 0;
135+
size_t pos = 0;
136+
while ((pos = content.find("pid", pos)) != std::string::npos) {
137+
pid_count++;
138+
pos += 3;
139+
}
140+
EXPECT_GE(pid_count, 2); // At least 2 log entries
141+
}
142+
143+
144+
// Test concurrent logging from multiple threads
145+
TEST_F(LoggerTest, ConcurrentLogging) {
146+
EnableFileLogging();
147+
148+
const int num_threads = 4;
149+
const int messages_per_thread = 10;
150+
151+
std::vector<std::thread> threads;
152+
153+
for (int i = 0; i < num_threads; ++i) {
154+
threads.emplace_back([i, messages_per_thread]() {
155+
Logger& logger = Logger::Instance();
156+
for (int j = 0; j < messages_per_thread; ++j) {
157+
logger << "Thread " << i << " Message " << j;
158+
}
159+
});
160+
}
161+
162+
// Wait for all threads to complete
163+
for (auto& thread : threads) {
164+
thread.join();
165+
}
166+
167+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
168+
169+
// Verify log file contains messages from all threads
170+
std::string content = ReadLogFile();
171+
EXPECT_FALSE(content.empty());
172+
173+
// Count messages from each thread
174+
for (int i = 0; i < num_threads; ++i) {
175+
std::string thread_pattern = "Thread " + std::to_string(i);
176+
EXPECT_THAT(content, testing::HasSubstr(thread_pattern));
177+
}
178+
}
179+
180+
// Test logging with special characters
181+
TEST_F(LoggerTest, SpecialCharacters) {
182+
EnableFileLogging();
183+
184+
Logger& logger = Logger::Instance();
185+
std::string special_msg = "Special chars: !@#$%^&*()_+-=[]{}|;':\",./<>?";
186+
logger << special_msg;
187+
188+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
189+
190+
std::string content = ReadLogFile();
191+
EXPECT_THAT(content, testing::HasSubstr(special_msg));
192+
}
193+
194+
// Test large message logging
195+
TEST_F(LoggerTest, LargeMessage) {
196+
EnableFileLogging();
197+
198+
Logger& logger = Logger::Instance();
199+
std::string large_msg(1000, 'A'); // 1000 character message
200+
logger << large_msg;
201+
202+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
203+
204+
std::string content = ReadLogFile();
205+
EXPECT_THAT(content, testing::HasSubstr(large_msg));
206+
}
207+
208+
209+
// Test timestamp format in logs
210+
TEST_F(LoggerTest, TimestampFormat) {
211+
EnableFileLogging();
212+
213+
Logger& logger = Logger::Instance();
214+
logger << "Timestamp test";
215+
216+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
217+
218+
std::string content = ReadLogFile();
219+
220+
// Check for timestamp pattern (YYYY-MM-DD HH:MM:SS)
221+
EXPECT_THAT(content, testing::MatchesRegex(".*[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.*"));
222+
}
223+
224+
// Test PID and TID in logs
225+
TEST_F(LoggerTest, PidTidInLogs) {
226+
EnableFileLogging();
227+
228+
Logger& logger = Logger::Instance();
229+
logger << "PID/TID test";
230+
231+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
232+
233+
std::string content = ReadLogFile();
234+
235+
// Check for PID and TID patterns
236+
EXPECT_THAT(content, testing::HasSubstr("pid"));
237+
EXPECT_THAT(content, testing::HasSubstr("tid"));
238+
239+
// Verify they contain numbers
240+
EXPECT_THAT(content, testing::MatchesRegex(".*pid[0-9]+.*"));
241+
EXPECT_THAT(content, testing::MatchesRegex(".*tid[0-9]+.*"));
242+
}
243+
244+
// Test empty message handling
245+
TEST_F(LoggerTest, EmptyMessage) {
246+
Logger& logger = Logger::Instance();
247+
248+
Logger::begm();
249+
Logger::endl();
250+
251+
const std::string& msg = Logger::LastMessage();
252+
EXPECT_EQ(msg, "");
253+
}
254+
255+
// Test multiple consecutive endl calls
256+
TEST_F(LoggerTest, MultipleEndl) {
257+
EnableFileLogging();
258+
259+
Logger& logger = Logger::Instance();
260+
logger << "Test" << Logger::endl << Logger::endl << "After multiple endl";
261+
262+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
263+
264+
std::string content = ReadLogFile();
265+
EXPECT_THAT(content, testing::HasSubstr("Test"));
266+
EXPECT_THAT(content, testing::HasSubstr("After multiple endl"));
267+
}
268+
269+
} // namespace aql_profile

0 commit comments

Comments
 (0)