1use rkyv::{Archive, Deserialize, Serialize};
4
5#[derive(Archive, Deserialize, Serialize, Debug, PartialEq, Clone)]
23pub struct CacheEntry {
24 pub tenant_id: u64,
26 pub context_hash: u64,
28 pub timestamp: i64,
30 pub embedding: Vec<u8>,
32 pub payload_blob: Vec<u8>,
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39 use rkyv::rancor::Error;
40 use rkyv::{access, from_bytes, to_bytes};
41
42 const TEST_PAYLOAD_BYTES: usize = 1024;
43 const SMALL_ENTRY_MAX_SERIALIZED_BYTES: usize = 1024;
44
45 fn create_test_entry() -> CacheEntry {
46 CacheEntry {
47 tenant_id: 12345678901234567890_u64,
48 context_hash: 9876543210987654321_u64,
49 timestamp: 1702500000_i64,
50 embedding: vec![0x01, 0x02, 0x03, 0x04],
51 payload_blob: vec![0xDE, 0xAD, 0xBE, 0xEF],
52 }
53 }
54
55 fn create_full_embedding_entry() -> CacheEntry {
56 CacheEntry {
57 tenant_id: 1,
58 context_hash: 2,
59 timestamp: 1702500000,
60 embedding: (0..crate::constants::EMBEDDING_F16_BYTES)
61 .map(|i| (i % 256) as u8)
62 .collect(),
63 payload_blob: vec![0x00; TEST_PAYLOAD_BYTES],
64 }
65 }
66
67 #[test]
68 fn test_cache_entry_field_initialization() {
69 let entry = create_test_entry();
70
71 assert_eq!(entry.tenant_id, 12345678901234567890_u64);
72 assert_eq!(entry.context_hash, 9876543210987654321_u64);
73 assert_eq!(entry.timestamp, 1702500000_i64);
74 assert_eq!(entry.embedding, vec![0x01, 0x02, 0x03, 0x04]);
75 assert_eq!(entry.payload_blob, vec![0xDE, 0xAD, 0xBE, 0xEF]);
76 }
77
78 #[test]
79 fn test_cache_entry_debug_trait() {
80 let entry = create_test_entry();
81 let debug_str = format!("{:?}", entry);
82
83 assert!(debug_str.contains("CacheEntry"));
84 assert!(debug_str.contains("tenant_id"));
85 assert!(debug_str.contains("12345678901234567890"));
86 }
87
88 #[test]
89 fn test_cache_entry_clone() {
90 let entry = create_test_entry();
91 let cloned = entry.clone();
92
93 assert_eq!(entry, cloned);
94 }
95
96 #[test]
97 fn test_cache_entry_equality() {
98 let entry1 = create_test_entry();
99 let entry2 = create_test_entry();
100 let entry3 = CacheEntry {
101 tenant_id: 999,
102 ..create_test_entry()
103 };
104
105 assert_eq!(entry1, entry2);
106 assert_ne!(entry1, entry3);
107 }
108
109 #[test]
110 fn test_serialization_roundtrip_basic() {
111 let original = create_test_entry();
112
113 let bytes = to_bytes::<Error>(&original).expect("serialization should succeed");
114
115 let deserialized: CacheEntry =
116 from_bytes::<CacheEntry, Error>(&bytes).expect("deserialization should succeed");
117
118 assert_eq!(original, deserialized);
119 }
120
121 #[test]
122 fn test_serialization_roundtrip_full_embedding() {
123 let original = create_full_embedding_entry();
124
125 let bytes = to_bytes::<Error>(&original).expect("serialization should succeed");
126 let deserialized: CacheEntry =
127 from_bytes::<CacheEntry, Error>(&bytes).expect("deserialization should succeed");
128
129 assert_eq!(original, deserialized);
130 assert_eq!(
131 deserialized.embedding.len(),
132 crate::constants::EMBEDDING_F16_BYTES
133 );
134 }
135
136 #[test]
137 fn test_archived_zero_copy_access() {
138 let original = create_test_entry();
139
140 let bytes = to_bytes::<Error>(&original).expect("serialization should succeed");
141
142 let archived =
143 access::<ArchivedCacheEntry, Error>(&bytes).expect("archive access should succeed");
144
145 assert_eq!(archived.tenant_id, original.tenant_id);
146 assert_eq!(archived.context_hash, original.context_hash);
147 assert_eq!(archived.timestamp, original.timestamp);
148 assert_eq!(archived.embedding.as_slice(), original.embedding.as_slice());
149 assert_eq!(
150 archived.payload_blob.as_slice(),
151 original.payload_blob.as_slice()
152 );
153 }
154
155 #[test]
156 fn test_archived_embedding_slice_access() {
157 let original = create_full_embedding_entry();
158
159 let bytes = to_bytes::<Error>(&original).expect("serialization should succeed");
160 let archived =
161 access::<ArchivedCacheEntry, Error>(&bytes).expect("archive access should succeed");
162
163 assert_eq!(
164 archived.embedding.len(),
165 crate::constants::EMBEDDING_F16_BYTES
166 );
167 assert_eq!(archived.embedding[0], 0);
168 assert_eq!(archived.embedding[255], 255);
169 assert_eq!(archived.embedding[256], 0);
170 }
171
172 #[test]
173 fn test_empty_vectors() {
174 let entry = CacheEntry {
175 tenant_id: 1,
176 context_hash: 2,
177 timestamp: 3,
178 embedding: vec![],
179 payload_blob: vec![],
180 };
181
182 let bytes = to_bytes::<Error>(&entry).expect("serialization should succeed");
183 let deserialized: CacheEntry =
184 from_bytes::<CacheEntry, Error>(&bytes).expect("deserialization should succeed");
185
186 assert!(deserialized.embedding.is_empty());
187 assert!(deserialized.payload_blob.is_empty());
188 }
189
190 #[test]
191 fn test_boundary_values_max() {
192 let entry = CacheEntry {
193 tenant_id: u64::MAX,
194 context_hash: u64::MAX,
195 timestamp: i64::MAX,
196 embedding: vec![0xFF],
197 payload_blob: vec![0xFF],
198 };
199
200 let bytes = to_bytes::<Error>(&entry).expect("serialization should succeed");
201 let deserialized: CacheEntry =
202 from_bytes::<CacheEntry, Error>(&bytes).expect("deserialization should succeed");
203
204 assert_eq!(deserialized.tenant_id, u64::MAX);
205 assert_eq!(deserialized.context_hash, u64::MAX);
206 assert_eq!(deserialized.timestamp, i64::MAX);
207 }
208
209 #[test]
210 fn test_boundary_values_min() {
211 let entry = CacheEntry {
212 tenant_id: u64::MIN,
213 context_hash: u64::MIN,
214 timestamp: i64::MIN,
215 embedding: vec![0x00],
216 payload_blob: vec![0x00],
217 };
218
219 let bytes = to_bytes::<Error>(&entry).expect("serialization should succeed");
220 let deserialized: CacheEntry =
221 from_bytes::<CacheEntry, Error>(&bytes).expect("deserialization should succeed");
222
223 assert_eq!(deserialized.tenant_id, u64::MIN);
224 assert_eq!(deserialized.context_hash, u64::MIN);
225 assert_eq!(deserialized.timestamp, i64::MIN);
226 }
227
228 #[test]
229 fn test_negative_timestamp() {
230 let entry = CacheEntry {
231 tenant_id: 1,
232 context_hash: 2,
233 timestamp: -1000000000_i64,
234 embedding: vec![],
235 payload_blob: vec![],
236 };
237
238 let bytes = to_bytes::<Error>(&entry).expect("serialization should succeed");
239 let deserialized: CacheEntry =
240 from_bytes::<CacheEntry, Error>(&bytes).expect("deserialization should succeed");
241
242 assert_eq!(deserialized.timestamp, -1000000000_i64);
243 }
244
245 #[test]
246 fn test_large_payload_blob() {
247 let large_payload: Vec<u8> = (0..1_000_000).map(|i| (i % 256) as u8).collect();
248
249 let entry = CacheEntry {
250 tenant_id: 1,
251 context_hash: 2,
252 timestamp: 3,
253 embedding: vec![],
254 payload_blob: large_payload.clone(),
255 };
256
257 let bytes = to_bytes::<Error>(&entry).expect("serialization should succeed");
258 let deserialized: CacheEntry =
259 from_bytes::<CacheEntry, Error>(&bytes).expect("deserialization should succeed");
260
261 assert_eq!(deserialized.payload_blob.len(), 1_000_000);
262 assert_eq!(deserialized.payload_blob, large_payload);
263 }
264
265 #[test]
266 fn test_serialized_size_is_reasonable() {
267 let entry = create_test_entry();
268
269 let bytes = to_bytes::<Error>(&entry).expect("serialization should succeed");
270
271 assert!(bytes.len() >= 32);
272 assert!(bytes.len() < SMALL_ENTRY_MAX_SERIALIZED_BYTES);
273 }
274
275 #[test]
276 fn test_full_embedding_serialized_size() {
277 let entry = create_full_embedding_entry();
278
279 let bytes = to_bytes::<Error>(&entry).expect("serialization should succeed");
280
281 assert!(bytes.len() >= crate::constants::EMBEDDING_F16_BYTES + TEST_PAYLOAD_BYTES);
282 }
283}