about summary refs log tree commit diff stats
path: root/archive/2025/summer/bsc_karidas/tests/unit/test_Compression.cpp
blob: d81718d6e4d5df090abfac257be227b85e0d45e9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <gtest/gtest.h>
#include "Compression.hpp"
#include "LogEntry.hpp"
#include <vector>
#include <string>
#include <algorithm>

class CompressionTest : public ::testing::Test
{
protected:
    void SetUp() override
    {
        // Create a few sample log entries for testing
        entry1 = LogEntry(LogEntry::ActionType::CREATE, "/data/records/1", "controller123", "processor123", "subject456");
        entry2 = LogEntry(LogEntry::ActionType::READ, "/data/records/2", "controller789", "processor789", "subject456");
        entry3 = LogEntry(LogEntry::ActionType::UPDATE, "/data/records/3", "controller123", "processor123", "subject789");
        entry4 = LogEntry(LogEntry::ActionType::DELETE, "/data/records/4", "controller789", "processor789", "subject123");
    }

    LogEntry entry1, entry2, entry3, entry4;
};

// Helper function to compare two LogEntry objects
bool LogEntriesEqual(const LogEntry &a, const LogEntry &b)
{
    // Compare serialized representations to check equality
    auto serializedA = a.serialize();
    auto serializedB = b.serialize();

    return serializedA == serializedB;
}

// Test compressing and decompressing a batch of log entries
TEST_F(CompressionTest, CompressDecompressBatch)
{
    std::vector<LogEntry> batch = {entry1, entry2, entry3, entry4};
    std::vector<uint8_t> serializedBatch = LogEntry::serializeBatch(std::move(batch));
    std::vector<uint8_t> compressed = Compression::compress(std::move(serializedBatch));

    // Make sure compression produced data
    ASSERT_GT(compressed.size(), 0);

    std::vector<uint8_t> decompressed = Compression::decompress(std::move(compressed));
    std::vector<LogEntry> recoveredBatch = LogEntry::deserializeBatch(std::move(decompressed));

    // Verify we got back the same number of entries
    ASSERT_EQ(batch.size(), recoveredBatch.size());

    // Verify each entry matches
    for (size_t i = 0; i < batch.size(); i++)
    {
        EXPECT_TRUE(LogEntriesEqual(batch[i], recoveredBatch[i]))
            << "Entries at index " << i << " don't match";
    }
}

// Test with an empty batch
TEST_F(CompressionTest, EmptyBatch)
{
    // Create an empty batch
    std::vector<LogEntry> emptyBatch;
    std::vector<uint8_t> serializedBatch = LogEntry::serializeBatch(std::move(emptyBatch));
    std::vector<uint8_t> compressed = Compression::compress(std::move(serializedBatch));

    std::vector<uint8_t> decompressed = Compression::decompress(std::move(compressed));
    std::vector<LogEntry> recoveredBatch = LogEntry::deserializeBatch(std::move(decompressed));

    // Verify we still have an empty vector
    EXPECT_TRUE(recoveredBatch.empty());
}

// Test with invalid compressed data
TEST_F(CompressionTest, InvalidCompressedData)
{
    // Create some invalid compressed data
    std::vector<uint8_t> invalidData = {0x01, 0x02, 0x03, 0x04};

    // Verify that decompression failed
    EXPECT_THROW(
        Compression::decompress(std::move(invalidData)),
        std::runtime_error);
}

// Test batch compression ratio
TEST_F(CompressionTest, BatchCompressionRatio)
{
    // Create a batch of log entries with repetitive data which should compress well
    const int batchSize = 50;
    std::string repetitiveData(1000, 'X');
    LogEntry repetitiveEntry(LogEntry::ActionType::CREATE, repetitiveData, repetitiveData, repetitiveData, repetitiveData);

    std::vector<LogEntry> repetitiveBatch(batchSize, repetitiveEntry);
    std::vector<uint8_t> serializedBatch = LogEntry::serializeBatch(std::move(repetitiveBatch));
    std::vector<uint8_t> compressed = Compression::compress(std::move(serializedBatch));

    // Check that batch compression significantly reduced the size
    double compressionRatio = static_cast<double>(compressed.size()) / static_cast<double>(serializedBatch.size());
    EXPECT_LT(compressionRatio, 0.05); // Expect at least 95% compression for batch

    std::vector<uint8_t> decompressed = Compression::decompress(std::move(compressed));
    std::vector<LogEntry> recoveredBatch = LogEntry::deserializeBatch(std::move(decompressed));
    // Verify the correct number of entries and their content
    ASSERT_EQ(repetitiveBatch.size(), recoveredBatch.size());
    for (size_t i = 0; i < repetitiveBatch.size(); i++)
    {
        EXPECT_TRUE(LogEntriesEqual(repetitiveBatch[i], recoveredBatch[i]));
    }
}

// Test with a large batch of entries
TEST_F(CompressionTest, LargeBatch)
{
    std::vector<LogEntry> largeBatch(100, entry1);
    std::vector<uint8_t> serializedBatch = LogEntry::serializeBatch(std::move(largeBatch));
    std::vector<uint8_t> compressed = Compression::compress(std::move(serializedBatch));
    std::vector<uint8_t> decompressed = Compression::decompress(std::move(compressed));
    std::vector<LogEntry> recoveredBatch = LogEntry::deserializeBatch(std::move(decompressed));

    // Verify the correct number of entries
    ASSERT_EQ(largeBatch.size(), recoveredBatch.size());

    // Verify the entries match
    for (size_t i = 0; i < largeBatch.size(); i++)
    {
        EXPECT_TRUE(LogEntriesEqual(largeBatch[i], recoveredBatch[i]));
    }
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}