about summary refs log tree commit diff stats
path: root/archive/2025/summer/bsc_karidas/tests/unit/test_Logger.cpp
diff options
context:
space:
mode:
authorDimitris <dimstav23@gmail.com>2025-07-15 15:11:36 +0200
committerGitHub <noreply@github.com>2025-07-15 15:11:36 +0200
commit73e505f04d17eba36c41fce7b48bc4d6884b8fd0 (patch)
tree44b5f4627309a48d6f22b54bb2ad9a2976e8601b /archive/2025/summer/bsc_karidas/tests/unit/test_Logger.cpp
parentca92e7ad181a02890496872012ecc6c1d08b1658 (diff)
parentd8c365681a41961ebe2daea5701a4d56f5400d1d (diff)
downloadresearch-work-archive-artifacts-73e505f04d17eba36c41fce7b48bc4d6884b8fd0.tar.gz
research-work-archive-artifacts-73e505f04d17eba36c41fce7b48bc4d6884b8fd0.zip
Merge pull request #6 from chriskari/upload-artifacts
Add bsc_karidas
Diffstat (limited to 'archive/2025/summer/bsc_karidas/tests/unit/test_Logger.cpp')
-rw-r--r--archive/2025/summer/bsc_karidas/tests/unit/test_Logger.cpp294
1 files changed, 294 insertions, 0 deletions
diff --git a/archive/2025/summer/bsc_karidas/tests/unit/test_Logger.cpp b/archive/2025/summer/bsc_karidas/tests/unit/test_Logger.cpp
new file mode 100644
index 000000000..1cc147836
--- /dev/null
+++ b/archive/2025/summer/bsc_karidas/tests/unit/test_Logger.cpp
@@ -0,0 +1,294 @@
+#include <gtest/gtest.h>
+#include "Logger.hpp"
+#include "BufferQueue.hpp"
+#include <chrono>
+#include <thread>
+
+class LoggerTest : public ::testing::Test
+{
+protected:
+    void SetUp() override
+    {
+        // Create a fresh instance for each test
+        Logger::s_instance.reset();
+
+        // Create a BufferQueue instance
+        queue = std::make_shared<BufferQueue>(1024, 10);
+    }
+
+    void TearDown() override
+    {
+        // Clean up the singleton
+        Logger::s_instance.reset();
+    }
+
+    std::shared_ptr<BufferQueue> queue;
+};
+
+// Test getInstance returns the same instance
+TEST_F(LoggerTest, GetInstanceReturnsSingleton)
+{
+    Logger &instance1 = Logger::getInstance();
+    Logger &instance2 = Logger::getInstance();
+
+    EXPECT_EQ(&instance1, &instance2);
+}
+
+// Test initialization with valid queue
+TEST_F(LoggerTest, InitializeWithValidQueue)
+{
+    Logger &logger = Logger::getInstance();
+
+    EXPECT_TRUE(logger.initialize(queue));
+    EXPECT_TRUE(logger.reset());
+}
+
+// Test initialization with null queue
+TEST_F(LoggerTest, InitializeWithNullQueue)
+{
+    Logger &logger = Logger::getInstance();
+
+    EXPECT_FALSE(logger.initialize(nullptr));
+}
+
+// Test double initialization
+TEST_F(LoggerTest, DoubleInitialization)
+{
+    Logger &logger = Logger::getInstance();
+
+    EXPECT_TRUE(logger.initialize(queue));
+    EXPECT_FALSE(logger.initialize(queue));
+
+    EXPECT_TRUE(logger.reset());
+}
+
+// Test creating producer token
+TEST_F(LoggerTest, CreateProducerToken)
+{
+    Logger &logger = Logger::getInstance();
+
+    // Should throw when not initialized
+    EXPECT_THROW(logger.createProducerToken(), std::runtime_error);
+
+    EXPECT_TRUE(logger.initialize(queue));
+
+    // Should not throw when initialized
+    EXPECT_NO_THROW({
+        BufferQueue::ProducerToken token = logger.createProducerToken();
+    });
+
+    EXPECT_TRUE(logger.reset());
+}
+
+// Test appending log entry after initialization
+TEST_F(LoggerTest, AppendAfterInitialization)
+{
+    Logger &logger = Logger::getInstance();
+    EXPECT_TRUE(logger.initialize(queue));
+
+    BufferQueue::ProducerToken token = logger.createProducerToken();
+    LogEntry entry(LogEntry::ActionType::READ, "location", "controller", "processor", "subject");
+
+    EXPECT_TRUE(logger.append(std::move(entry), token));
+    EXPECT_TRUE(logger.reset());
+}
+
+// Test blocking append with queue eventually emptying
+TEST_F(LoggerTest, BlockingAppendWithConsumption)
+{
+    Logger &logger = Logger::getInstance();
+    auto smallQueue = std::make_shared<BufferQueue>(2, 1);
+    EXPECT_TRUE(logger.initialize(smallQueue, std::chrono::milliseconds(1000)));
+
+    BufferQueue::ProducerToken token = logger.createProducerToken();
+
+    // Since queue grows dynamically, we'll test timeout instead
+    LogEntry entry1(LogEntry::ActionType::READ, "location1", "controller1", "processor1", "subject1");
+    EXPECT_TRUE(logger.append(std::move(entry1), token));
+
+    LogEntry entry2(LogEntry::ActionType::READ, "location2", "controller2", "processor2", "subject2");
+    // With dynamic queue, this will succeed immediately
+    auto start = std::chrono::steady_clock::now();
+    EXPECT_TRUE(logger.append(std::move(entry2), token));
+    auto end = std::chrono::steady_clock::now();
+
+    // Verify it doesn't block since queue can grow
+    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
+    EXPECT_LT(duration, 100); // Should be very fast
+
+    // Verify both items are in the queue
+    EXPECT_EQ(smallQueue->size(), 2);
+
+    EXPECT_TRUE(logger.reset());
+}
+
+// Test append timeout behavior (new test)
+TEST_F(LoggerTest, AppendTimeoutBehavior)
+{
+    Logger &logger = Logger::getInstance();
+    auto queue = std::make_shared<BufferQueue>(1024, 1);
+
+    // Initialize with a very short timeout
+    EXPECT_TRUE(logger.initialize(queue, std::chrono::milliseconds(50)));
+
+    BufferQueue::ProducerToken token = logger.createProducerToken();
+    LogEntry entry(LogEntry::ActionType::READ, "location", "controller", "processor", "subject");
+
+    auto start = std::chrono::steady_clock::now();
+    EXPECT_TRUE(logger.append(std::move(entry), token)); // Should succeed immediately since queue grows
+    auto end = std::chrono::steady_clock::now();
+
+    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
+    EXPECT_LT(duration, 10); // Very fast operation
+
+    EXPECT_TRUE(logger.reset());
+}
+
+// Test batch append functionality
+TEST_F(LoggerTest, AppendBatch)
+{
+    Logger &logger = Logger::getInstance();
+    EXPECT_TRUE(logger.initialize(queue));
+
+    BufferQueue::ProducerToken token = logger.createProducerToken();
+
+    std::vector<LogEntry> entries;
+    for (int i = 0; i < 5; i++)
+    {
+        entries.emplace_back(
+            LogEntry::ActionType::READ,
+            "location_" + std::to_string(i),
+            "controller",
+            "processor",
+            "subject_" + std::to_string(i));
+    }
+
+    EXPECT_TRUE(logger.appendBatch(std::move(entries), token));
+    EXPECT_EQ(queue->size(), 5);
+
+    // Test empty batch
+    std::vector<LogEntry> emptyEntries;
+    EXPECT_TRUE(logger.appendBatch(std::move(emptyEntries), token));
+
+    EXPECT_TRUE(logger.reset());
+}
+
+// Test shutdown without initialization
+TEST_F(LoggerTest, ShutdownWithoutInitialization)
+{
+    Logger &logger = Logger::getInstance();
+
+    EXPECT_FALSE(logger.reset());
+}
+
+// Test shutdown with wait for completion
+TEST_F(LoggerTest, ShutdownWithWait)
+{
+    Logger &logger = Logger::getInstance();
+    EXPECT_TRUE(logger.initialize(queue));
+
+    BufferQueue::ProducerToken token = logger.createProducerToken();
+    LogEntry entry(LogEntry::ActionType::READ, "location", "controller", "processor", "subject");
+    EXPECT_TRUE(logger.append(std::move(entry), token));
+
+    // Launch an asynchronous consumer that waits briefly before draining the queue.
+    std::thread consumer([this]()
+                         {
+        std::this_thread::sleep_for(std::chrono::milliseconds(500)); // simulate delay
+        BufferQueue::ConsumerToken consumerToken = queue->createConsumerToken();
+        QueueItem dummyItem;
+        while (queue->tryDequeue(dummyItem, consumerToken))
+        {
+        } });
+
+    EXPECT_TRUE(logger.reset());
+    consumer.join();
+    EXPECT_TRUE(queue->size() == 0);
+}
+
+// Test export logs without initialization
+TEST_F(LoggerTest, ExportLogsWithoutInitialization)
+{
+    Logger &logger = Logger::getInstance();
+
+    auto now = std::chrono::system_clock::now();
+    EXPECT_FALSE(logger.exportLogs("output.log", now, now));
+}
+
+// Test export logs after initialization (unimplemented)
+TEST_F(LoggerTest, ExportLogsAfterInitialization)
+{
+    Logger &logger = Logger::getInstance();
+    EXPECT_TRUE(logger.initialize(queue));
+
+    auto now = std::chrono::system_clock::now();
+    EXPECT_FALSE(logger.exportLogs("output.log", now, now));
+
+    EXPECT_TRUE(logger.reset());
+}
+
+// Test thread safety of singleton
+TEST_F(LoggerTest, ThreadSafetySingleton)
+{
+    std::vector<std::thread> threads;
+    std::vector<Logger *> instances(10);
+
+    for (int i = 0; i < 10; i++)
+    {
+        threads.emplace_back([i, &instances]()
+                             { instances[i] = &Logger::getInstance(); });
+    }
+
+    for (auto &t : threads)
+    {
+        t.join();
+    }
+
+    // All threads should get the same instance
+    for (int i = 1; i < 10; i++)
+    {
+        EXPECT_EQ(instances[0], instances[i]);
+    }
+}
+
+// Test thread safety of API operations
+TEST_F(LoggerTest, ThreadSafetyOperations)
+{
+    Logger &logger = Logger::getInstance();
+    EXPECT_TRUE(logger.initialize(queue));
+
+    std::vector<std::thread> threads;
+    for (int i = 0; i < 10; i++)
+    {
+        threads.emplace_back([&logger, i]()
+                             {
+                                 // Create producer token for this thread
+                                 BufferQueue::ProducerToken token = logger.createProducerToken();
+
+                                 // Each thread appends 10 entries
+                                 for (int j = 0; j < 10; j++) {
+                                     LogEntry entry(
+                                         LogEntry::ActionType::READ,
+                                         "location_" + std::to_string(i),
+                                         "controller_" + std::to_string(i),
+                                         "processor_" + std::to_string(i),
+                                         "subject_" + std::to_string(j)
+                                        );
+                                     EXPECT_TRUE(logger.append(std::move(entry), token));
+                                 } });
+    }
+
+    for (auto &t : threads)
+    {
+        t.join();
+    }
+
+    EXPECT_EQ(queue->size(), 100);
+}
+
+// Main function that runs all the tests
+int main(int argc, char **argv)
+{
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file