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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
|
#include <gtest/gtest.h>
#include "LogEntry.hpp"
#include <vector>
#include <iostream>
#include <chrono>
// Test default constructor
TEST(LogEntryTest1, DefaultConstructor_InitializesCorrectly)
{
LogEntry entry;
EXPECT_EQ(entry.getActionType(), LogEntry::ActionType::CREATE);
EXPECT_EQ(entry.getDataLocation(), "");
EXPECT_EQ(entry.getDataControllerId(), "");
EXPECT_EQ(entry.getDataProcessorId(), "");
EXPECT_EQ(entry.getDataSubjectId(), "");
EXPECT_EQ(entry.getPayload().size(), 0);
auto now = std::chrono::system_clock::now();
EXPECT_NEAR(std::chrono::system_clock::to_time_t(entry.getTimestamp()),
std::chrono::system_clock::to_time_t(now), 1);
}
// Test parameterized constructor
TEST(LogEntryTest2, ParameterizedConstructor_SetsFieldsCorrectly)
{
std::vector<uint8_t> testPayload(128, 0xAA); // 128 bytes of 0xAA
LogEntry entry(LogEntry::ActionType::UPDATE, "database/users", "controller123", "processor789", "subject456", testPayload);
EXPECT_EQ(entry.getActionType(), LogEntry::ActionType::UPDATE);
EXPECT_EQ(entry.getDataLocation(), "database/users");
EXPECT_EQ(entry.getDataControllerId(), "controller123");
EXPECT_EQ(entry.getDataProcessorId(), "processor789");
EXPECT_EQ(entry.getDataSubjectId(), "subject456");
EXPECT_EQ(entry.getPayload().size(), testPayload.size());
// Check content matches
const auto &payload = entry.getPayload();
bool contentMatches = true;
for (size_t i = 0; i < payload.size(); ++i)
{
if (payload[i] != testPayload[i])
{
contentMatches = false;
break;
}
}
EXPECT_TRUE(contentMatches);
auto now = std::chrono::system_clock::now();
EXPECT_NEAR(std::chrono::system_clock::to_time_t(entry.getTimestamp()),
std::chrono::system_clock::to_time_t(now), 1);
}
// Test serialization and deserialization with empty payload
TEST(LogEntryTest4, SerializationDeserialization_WorksCorrectly)
{
LogEntry entry(LogEntry::ActionType::READ, "storage/files", "controllerABC", "processorDEF", "subjectXYZ");
std::vector<uint8_t> serializedData = entry.serialize();
LogEntry newEntry;
bool success = newEntry.deserialize(std::move(serializedData));
EXPECT_TRUE(success);
EXPECT_EQ(newEntry.getActionType(), LogEntry::ActionType::READ);
EXPECT_EQ(newEntry.getDataLocation(), "storage/files");
EXPECT_EQ(newEntry.getDataControllerId(), "controllerABC");
EXPECT_EQ(newEntry.getDataProcessorId(), "processorDEF");
EXPECT_EQ(newEntry.getDataSubjectId(), "subjectXYZ");
EXPECT_EQ(newEntry.getPayload().size(), 0); // Payload should still be empty
std::vector<uint8_t> serializedData2 = entry.serialize();
success = newEntry.deserialize(std::move(serializedData2));
EXPECT_TRUE(success);
EXPECT_EQ(newEntry.getActionType(), LogEntry::ActionType::READ);
EXPECT_EQ(newEntry.getDataLocation(), "storage/files");
EXPECT_EQ(newEntry.getDataControllerId(), "controllerABC");
EXPECT_EQ(newEntry.getDataSubjectId(), "subjectXYZ");
EXPECT_NEAR(std::chrono::system_clock::to_time_t(newEntry.getTimestamp()),
std::chrono::system_clock::to_time_t(entry.getTimestamp()), 1);
}
// Test serialization and deserialization with payload
TEST(LogEntryTest4A, SerializationDeserializationWithPayload_WorksCorrectly)
{
// Create test payload
std::vector<uint8_t> testPayload(64);
for (size_t i = 0; i < testPayload.size(); ++i)
{
testPayload[i] = static_cast<uint8_t>(i & 0xFF);
}
LogEntry entry(LogEntry::ActionType::READ, "storage/files", "controllerABC", "processorDEF", "subjectXYZ", testPayload);
// Serialize and deserialize
std::vector<uint8_t> serializedData = entry.serialize();
LogEntry newEntry;
bool success = newEntry.deserialize(std::move(serializedData));
// Verify deserialization worked
EXPECT_TRUE(success);
EXPECT_EQ(newEntry.getActionType(), LogEntry::ActionType::READ);
EXPECT_EQ(newEntry.getDataLocation(), "storage/files");
EXPECT_EQ(newEntry.getDataControllerId(), "controllerABC");
EXPECT_EQ(newEntry.getDataProcessorId(), "processorDEF");
EXPECT_EQ(newEntry.getDataSubjectId(), "subjectXYZ");
// Verify payload
EXPECT_EQ(newEntry.getPayload().size(), testPayload.size());
// Check payload content
const auto &recoveredPayload = newEntry.getPayload();
bool payloadMatches = true;
for (size_t i = 0; i < testPayload.size(); ++i)
{
if (recoveredPayload[i] != testPayload[i])
{
payloadMatches = false;
break;
}
}
EXPECT_TRUE(payloadMatches);
}
// Test batch serialization and deserialization with payloads
TEST(LogEntryTest5, BatchSerializationDeserialization_WorksCorrectly)
{
// Create a batch of log entries
std::vector<LogEntry> originalEntries;
// Entry with no payload
originalEntries.push_back(LogEntry(LogEntry::ActionType::CREATE, "db/users", "controller1", "processor1", "subject1"));
// Entry with small payload
std::vector<uint8_t> payload2(16, 0x22); // 16 bytes of 0x22
originalEntries.push_back(LogEntry(LogEntry::ActionType::READ, "files/documents", "controller2", "processor2", "subject2", payload2));
// Entry with medium payload
std::vector<uint8_t> payload3(128, 0x33); // 128 bytes of 0x33
originalEntries.push_back(LogEntry(LogEntry::ActionType::UPDATE, "cache/profiles", "controller3", "processor3", "subject3", payload3));
// Entry with large payload
std::vector<uint8_t> payload4(1024, 0x44); // 1024 bytes of 0x44
originalEntries.push_back(LogEntry(LogEntry::ActionType::DELETE, "archive/logs", "controller4", "processor4", "subject4", payload4));
// Serialize the batch
std::vector<uint8_t> batchData = LogEntry::serializeBatch(std::move(originalEntries));
// Check that the batch has reasonable size
EXPECT_GT(batchData.size(), sizeof(uint32_t)); // At least space for entry count
// Deserialize the batch
std::vector<LogEntry> recoveredEntries = LogEntry::deserializeBatch(std::move(batchData));
// Verify the number of entries
EXPECT_EQ(recoveredEntries.size(), originalEntries.size());
// Verify each entry's data
for (size_t i = 0; i < originalEntries.size() && i < recoveredEntries.size(); ++i)
{
EXPECT_EQ(recoveredEntries[i].getActionType(), originalEntries[i].getActionType());
EXPECT_EQ(recoveredEntries[i].getDataLocation(), originalEntries[i].getDataLocation());
EXPECT_EQ(recoveredEntries[i].getDataControllerId(), originalEntries[i].getDataControllerId());
EXPECT_EQ(recoveredEntries[i].getDataProcessorId(), originalEntries[i].getDataProcessorId());
EXPECT_EQ(recoveredEntries[i].getDataSubjectId(), originalEntries[i].getDataSubjectId());
// Verify payload size
EXPECT_EQ(recoveredEntries[i].getPayload().size(), originalEntries[i].getPayload().size());
// Check payload content if it's not empty
if (!originalEntries[i].getPayload().empty())
{
const auto &originalPayload = originalEntries[i].getPayload();
const auto &recoveredPayload = recoveredEntries[i].getPayload();
bool payloadMatches = true;
for (size_t j = 0; j < originalPayload.size(); ++j)
{
if (recoveredPayload[j] != originalPayload[j])
{
payloadMatches = false;
break;
}
}
EXPECT_TRUE(payloadMatches) << "Payload mismatch at entry " << i;
}
// Compare timestamps (allowing 1 second difference for potential precision issues)
EXPECT_NEAR(
std::chrono::system_clock::to_time_t(recoveredEntries[i].getTimestamp()),
std::chrono::system_clock::to_time_t(originalEntries[i].getTimestamp()),
1);
}
}
|