1use log;
3use serde::{Deserialize, Serialize};
4use std::collections::VecDeque;
5
6use super::{error::CacheError, Cache};
7use pdk_core::classy::shared_data::concurrent_shared_data::TransactionStatus;
8
9cfg_if::cfg_if! {
10 if #[cfg(test)] {
11 use crate::mocks::MockConcurrentSharedData as ConcurrentSharedData;
12 } else {
13 use pdk_core::classy::shared_data::concurrent_shared_data::ConcurrentSharedData;
14 }
15}
16
17enum OperationType {
18 Insert,
19 Remove,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23struct InternalData {
24 max_entries_size: usize,
25 fifo: VecDeque<String>,
26 last_modified_item_key: String,
27}
28
29impl InternalData {
30 fn new(max_entries_size: usize, fifo: VecDeque<String>, last_modified_item_key: &str) -> Self {
31 Self {
32 max_entries_size,
33 fifo,
34 last_modified_item_key: last_modified_item_key.to_string(),
35 }
36 }
37}
38
39pub struct FifoCache {
44 cache_id: String,
45 cache_id_internal_data: String,
46 concurrent_shared_data: ConcurrentSharedData,
47 max_entries_size: usize,
48}
49
50impl FifoCache {
51 pub(crate) fn new(
52 cache_id: String,
53 max_entries_size: usize,
54 concurrent_shared_data: ConcurrentSharedData,
55 ) -> Self {
56 Self {
57 cache_id_internal_data: format!("{}-internal_data", &cache_id),
58 cache_id,
59 max_entries_size,
60 concurrent_shared_data,
61 }
62 }
63
64 pub fn max_entries_size(&self) -> usize {
66 self.max_entries_size
67 }
68
69 pub fn cache_id(&self) -> &str {
71 self.cache_id.as_str()
72 }
73
74 fn cache_id_internal_data(&self) -> &str {
76 self.cache_id_internal_data.as_ref()
77 }
78
79 fn cache_key(&self, item_key: &str) -> String {
81 format!("{}-{}", self.cache_id(), item_key)
82 }
83
84 fn new_internal_data(
85 &self,
86 fifo: VecDeque<String>,
87 last_modified_item_key: &str,
88 ) -> InternalData {
89 InternalData::new(self.max_entries_size(), fifo, last_modified_item_key)
90 }
91
92 fn get_stored_internal_data(&self) -> Option<InternalData> {
93 self.concurrent_shared_data
94 .get::<InternalData>(self.cache_id_internal_data())
95 }
96
97 fn update_internal_data(&self, last_in: String, is_update: bool) {
98 log::trace!(
99 "Updating cache state data for key: {} (updated: {})",
100 &last_in,
101 is_update
102 );
103
104 if is_update {
105 self.remove_item_from_internal_data(&last_in);
106 }
107
108 let mut internal_data: InternalData;
110 if let Some(stored_internal_data) = self.get_stored_internal_data() {
111 internal_data = stored_internal_data;
112 } else {
113 internal_data =
114 self.new_internal_data(VecDeque::with_capacity(self.max_entries_size()), &last_in);
115 }
116
117 internal_data.fifo.push_back(last_in.clone());
119 internal_data.last_modified_item_key = last_in;
120
121 self.save_internal_data(&internal_data, OperationType::Insert);
123
124 self.check_eviction(&mut internal_data);
126 }
127
128 fn check_eviction(&self, internal_data: &mut InternalData) {
129 let mut is_evicted = false;
130 while internal_data.fifo.len() > self.max_entries_size() {
131 let first_in = internal_data.fifo.pop_front().unwrap();
132
133 self.evict(&first_in);
134 internal_data.last_modified_item_key = first_in;
135 is_evicted = true;
136 }
137
138 if is_evicted {
139 self.save_internal_data(internal_data, OperationType::Remove);
140 log::trace!("Cache evicted");
141 }
142 }
143
144 fn evict(&self, key: &str) {
145 let _deleted: Option<Vec<u8>> = self.concurrent_shared_data.remove(key);
146 }
147
148 fn save_internal_data(&self, new_internal_data: &InternalData, operation_type: OperationType) {
149 let insert_result: (TransactionStatus, InternalData) = match operation_type {
153 OperationType::Insert => self.concurrent_shared_data.insert(
154 self.cache_id_internal_data().to_string(),
155 new_internal_data.to_owned(),
156 handle_cache_state_consistency_when_insert,
157 ),
158 OperationType::Remove => self.concurrent_shared_data.insert(
159 self.cache_id_internal_data().to_string(),
160 new_internal_data.to_owned(),
161 handle_cache_state_consistency_when_remove_or_evict,
162 ),
163 };
164
165 if !matches!(insert_result.0, TransactionStatus::Complete) {
166 log::error!(
167 "Error updating internal cache state {}: {:?}",
168 self.cache_id(),
169 insert_result.0
170 );
171 }
172 }
173
174 fn remove_item_from_internal_data(&self, deleted_key: &str) {
175 if let Some(mut stored_internal_data) = self.get_stored_internal_data() {
176 if let Some(found_index) =
178 stored_internal_data
179 .fifo
180 .iter()
181 .enumerate()
182 .find_map(|(index, key)| {
183 if key.as_str() == deleted_key {
184 Some(index)
185 } else {
186 None
187 }
188 })
189 {
190 stored_internal_data.fifo.remove(found_index);
191 stored_internal_data.last_modified_item_key = deleted_key.to_string();
192
193 self.save_internal_data(&stored_internal_data, OperationType::Remove);
195 }
196 } else {
197 log::trace!("Stored cache state data not found, nothing to clean from cache state");
198 }
199 }
200}
201
202fn handle_cache_value_consistency(
204 _stored_value: Vec<u8>,
205 candidate_value: Vec<u8>,
206) -> Option<Vec<u8>> {
207 Some(candidate_value)
208}
209
210fn handle_cache_state_consistency_when_insert(
212 stored_state: InternalData,
213 candidate_state: InternalData,
214) -> Option<InternalData> {
215 let mut new_fifo: VecDeque<String> = stored_state.fifo;
216
217 if let Some(index) = new_fifo.iter().enumerate().find_map(|(index, key)| {
218 if key.as_str() == candidate_state.last_modified_item_key.as_str() {
219 Some(index)
220 } else {
221 None
222 }
223 }) {
224 new_fifo.remove(index);
225 }
226 new_fifo.push_back(candidate_state.last_modified_item_key.clone());
227
228 Some(InternalData::new(
229 stored_state.max_entries_size,
230 new_fifo,
231 candidate_state.last_modified_item_key.as_str(),
232 ))
233}
234
235fn handle_cache_state_consistency_when_remove_or_evict(
237 stored_state: InternalData,
238 candidate_state: InternalData,
239) -> Option<InternalData> {
240 let mut new_fifo: VecDeque<String> = stored_state.fifo;
241 new_fifo.retain(|key| key.as_str() != candidate_state.last_modified_item_key.as_str());
242
243 Some(InternalData::new(
244 stored_state.max_entries_size,
245 new_fifo,
246 candidate_state.last_modified_item_key.as_str(),
247 ))
248}
249
250impl Cache for FifoCache {
251 fn save(&self, key: &str, value: Vec<u8>) -> Result<(), CacheError> {
252 let cache_key = self.cache_key(key);
254
255 let is_update = self
258 .concurrent_shared_data
259 .get::<Vec<u8>>(cache_key.as_str())
260 .is_some();
261
262 let (tx_status, _saved_data) =
264 self.concurrent_shared_data
265 .insert(cache_key, value, handle_cache_value_consistency);
266
267 match tx_status {
268 TransactionStatus::Complete => {
269 self.update_internal_data(self.cache_key(key), is_update);
270 }
271 _ => {
272 return Err(CacheError::SaveError {
273 status: format!("{:?}", tx_status),
274 cache_id: String::from(self.cache_id()),
275 })
276 }
277 }
278 Ok(())
279 }
280
281 fn get(&self, key: &str) -> Option<Vec<u8>> {
282 let cache_key = self.cache_key(key);
283 self.concurrent_shared_data
284 .get::<Vec<u8>>(cache_key.as_str())
285 }
286
287 fn delete(&self, key: &str) -> Option<Vec<u8>> {
288 log::trace!("Delete item '{}' from cache", key);
289 let delete_key = self.cache_key(key);
290 let deleted = self.concurrent_shared_data.remove(&delete_key);
291 self.remove_item_from_internal_data(&delete_key);
292 deleted
293 }
294
295 fn purge(&self) {
296 if let Some(cache_internal_data) = self.get_stored_internal_data() {
297 cache_internal_data.fifo.iter().for_each(|cache_key| {
299 let _removed: Option<Vec<u8>> = self.concurrent_shared_data.remove(cache_key);
300 });
301 let _internal_data: Option<InternalData> = self
303 .concurrent_shared_data
304 .remove(self.cache_id_internal_data());
305 }
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use std::collections::VecDeque;
312
313 use mockall::{
314 predicate::{always, eq},
315 Sequence,
316 };
317 use serde::{Deserialize, Serialize};
318
319 use super::Cache;
320 use super::ConcurrentSharedData as MockConcurrentSharedData;
321 use super::{
322 handle_cache_state_consistency_when_insert,
323 handle_cache_state_consistency_when_remove_or_evict, handle_cache_value_consistency,
324 FifoCache, InternalData,
325 };
326 use pdk_core::classy::shared_data::concurrent_shared_data::TransactionStatus;
327
328 #[derive(Debug, Serialize, Deserialize, PartialEq, Copy, Clone)]
329 struct SerializableObject {
330 property_one: u64,
331 property_two: u64,
332 }
333
334 #[test]
335 fn save_in_cache_first_time() {
336 let obj = SerializableObject {
337 property_one: 1,
338 property_two: 10,
339 };
340 let serialized_obj = bincode::serialize(&obj).unwrap();
341
342 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
343 let mut sequence = Sequence::new();
344
345 mock_concurrent_shared_data
346 .expect_get::<Vec<u8>>()
347 .with(eq("test-cache-key1"))
348 .times(1)
349 .in_sequence(&mut sequence)
350 .returning(move |_x: &str| None);
351
352 mock_concurrent_shared_data
353 .expect_insert()
354 .times(1)
355 .in_sequence(&mut sequence)
356 .returning(move |_x, value: Vec<u8>, _handle_consistency| {
357 (TransactionStatus::Complete, value)
358 });
359
360 mock_concurrent_shared_data
361 .expect_get::<InternalData>()
362 .with(eq("test-cache-internal_data"))
363 .times(1)
364 .in_sequence(&mut sequence)
365 .returning(move |_x: &str| None);
366
367 mock_concurrent_shared_data
368 .expect_insert()
369 .times(1)
370 .in_sequence(&mut sequence)
371 .returning(move |_x, value: InternalData, _handle_consistency| {
372 (TransactionStatus::Complete, value)
373 });
374
375 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
376 let value = serialized_obj.as_slice().to_vec();
377 assert!(cache.save("key1", value).is_ok());
378 }
379
380 #[test]
381 fn save_in_cache_already_exists() {
382 let obj = SerializableObject {
383 property_one: 1,
384 property_two: 10,
385 };
386 let serialized_obj = bincode::serialize(&obj).unwrap();
387
388 let stored_obj = SerializableObject {
389 property_one: 1,
390 property_two: 10,
391 };
392 let serialized_stored_obj = bincode::serialize(&stored_obj).unwrap();
393
394 let stored_fifo = VecDeque::from([String::from("test-cache-key1")]);
395 let stored_internal_data = InternalData::new(3, stored_fifo, "test-cache-key1");
396
397 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
398 let mut sequence = Sequence::new();
399
400 mock_concurrent_shared_data
401 .expect_get::<Vec<u8>>()
402 .with(eq("test-cache-key1"))
403 .times(1)
404 .in_sequence(&mut sequence)
405 .returning(move |_x: &str| Some(serialized_stored_obj.clone()));
406
407 mock_concurrent_shared_data
408 .expect_insert()
409 .times(1)
410 .in_sequence(&mut sequence)
411 .returning(move |_x, value: Vec<u8>, _handle_consistency| {
412 (TransactionStatus::Complete, value)
413 });
414
415 mock_concurrent_shared_data
416 .expect_get::<InternalData>()
417 .with(eq("test-cache-internal_data"))
418 .times(1)
419 .in_sequence(&mut sequence)
420 .returning(move |_x: &str| Some(stored_internal_data.clone()));
421
422 mock_concurrent_shared_data
423 .expect_insert()
424 .times(1)
425 .in_sequence(&mut sequence)
426 .returning(move |_x, value: InternalData, _handle_consistency| {
427 (TransactionStatus::Complete, value)
428 });
429
430 let stored_internal_data = InternalData::new(3, VecDeque::new(), "test-cache-key1");
431
432 mock_concurrent_shared_data
433 .expect_get::<InternalData>()
434 .with(eq("test-cache-internal_data"))
435 .times(1)
436 .in_sequence(&mut sequence)
437 .returning(move |_x: &str| Some(stored_internal_data.clone()));
438
439 mock_concurrent_shared_data
440 .expect_insert()
441 .times(1)
442 .in_sequence(&mut sequence)
443 .returning(move |_x, value: InternalData, _handle_consistency| {
444 (TransactionStatus::Complete, value)
445 });
446
447 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
448 let value = serialized_obj.as_slice().to_vec();
449 assert!(cache.save("key1", value).is_ok());
450 }
451
452 #[test]
453 fn save_in_cache_when_shared_data_fails_storing_value() {
454 let obj = SerializableObject {
455 property_one: 1,
456 property_two: 10,
457 };
458 let serialized_obj = bincode::serialize(&obj).unwrap();
459
460 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
461 let mut sequence = Sequence::new();
462
463 mock_concurrent_shared_data
464 .expect_get::<Vec<u8>>()
465 .with(eq("test-cache-key1"))
466 .times(1)
467 .in_sequence(&mut sequence)
468 .returning(move |_x: &str| None);
469
470 mock_concurrent_shared_data
471 .expect_insert()
472 .times(1)
473 .in_sequence(&mut sequence)
474 .returning(move |_x, value: Vec<u8>, _handle_consistency| {
475 (TransactionStatus::InternalError, value)
476 });
477
478 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
479 let value = serialized_obj.as_slice().to_vec();
480 assert!(cache.save("key1", value).is_err());
481 }
482
483 #[test]
485 fn save_in_cache_when_shared_data_fails_storing_internaldata() {
486 let obj = SerializableObject {
487 property_one: 1,
488 property_two: 10,
489 };
490 let serialized_obj = bincode::serialize(&obj).unwrap();
491
492 let stored_obj = SerializableObject {
493 property_one: 1,
494 property_two: 10,
495 };
496 let serialized_stored_obj = bincode::serialize(&stored_obj).unwrap();
497
498 let stored_fifo = VecDeque::from([String::from("test-cache-key1")]);
499 let stored_internal_data = InternalData::new(3, stored_fifo, "test-cache-key1");
500
501 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
502 let mut sequence = Sequence::new();
503
504 mock_concurrent_shared_data
505 .expect_get::<Vec<u8>>()
506 .with(eq("test-cache-key1"))
507 .times(1)
508 .in_sequence(&mut sequence)
509 .returning(move |_x: &str| Some(serialized_stored_obj.clone()));
510
511 mock_concurrent_shared_data
512 .expect_insert()
513 .times(1)
514 .in_sequence(&mut sequence)
515 .returning(move |_x, value: Vec<u8>, _handle_consistency| {
516 (TransactionStatus::Complete, value)
517 });
518
519 mock_concurrent_shared_data
520 .expect_get::<InternalData>()
521 .with(eq("test-cache-internal_data"))
522 .times(1)
523 .in_sequence(&mut sequence)
524 .returning(move |_x: &str| Some(stored_internal_data.clone()));
525
526 mock_concurrent_shared_data
527 .expect_insert()
528 .times(1)
529 .in_sequence(&mut sequence)
530 .returning(move |_x, value: InternalData, _handle_consistency| {
531 (TransactionStatus::InternalError, value)
532 });
533
534 let stored_internal_data = InternalData::new(3, VecDeque::new(), "test-cache-key1");
535
536 mock_concurrent_shared_data
537 .expect_get::<InternalData>()
538 .with(eq("test-cache-internal_data"))
539 .times(1)
540 .in_sequence(&mut sequence)
541 .returning(move |_x: &str| Some(stored_internal_data.clone()));
542
543 mock_concurrent_shared_data
544 .expect_insert()
545 .times(1)
546 .in_sequence(&mut sequence)
547 .returning(move |_x, value: InternalData, _handle_consistency| {
548 (TransactionStatus::Complete, value)
549 });
550
551 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
552 let value = serialized_obj.as_slice().to_vec();
553 assert!(cache.save("key1", value).is_ok());
554 }
555
556 #[test]
557 fn save_in_cache_first_time_when_cache_has_elements() {
558 let obj = SerializableObject {
559 property_one: 1,
560 property_two: 10,
561 };
562 let serialized_obj = bincode::serialize(&obj).unwrap();
563
564 let stored_fifo = VecDeque::from([
565 String::from("test-cache-keyA"),
566 String::from("test-cache-keyB"),
567 ]);
568 let stored_internal_data = InternalData::new(3, stored_fifo, "test-cache-keyB");
569
570 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
571 let mut sequence = Sequence::new();
572
573 mock_concurrent_shared_data
574 .expect_get::<Vec<u8>>()
575 .with(eq("test-cache-key1"))
576 .times(1)
577 .in_sequence(&mut sequence)
578 .returning(move |_x: &str| None);
579
580 mock_concurrent_shared_data
581 .expect_insert()
582 .times(1)
583 .with(eq(String::from("test-cache-key1")), always(), always())
584 .in_sequence(&mut sequence)
585 .returning(move |_x, value: Vec<u8>, _handle_consistency| {
586 (TransactionStatus::Complete, value)
587 });
588
589 mock_concurrent_shared_data
590 .expect_get::<InternalData>()
591 .with(eq("test-cache-internal_data"))
592 .times(1)
593 .in_sequence(&mut sequence)
594 .returning(move |_x: &str| Some(stored_internal_data.clone()));
595
596 mock_concurrent_shared_data
597 .expect_insert()
598 .times(1)
599 .in_sequence(&mut sequence)
600 .returning(move |_x, value: InternalData, _handle_consistency| {
601 (TransactionStatus::InternalError, value)
602 });
603
604 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
605 let value = serialized_obj.as_slice().to_vec();
606 assert!(cache.save("key1", value).is_ok());
607 }
608
609 #[test]
610 fn save_in_cache_when_cache_is_full_needs_eviction() {
611 let obj = SerializableObject {
612 property_one: 1,
613 property_two: 10,
614 };
615 let serialized_obj = bincode::serialize(&obj).unwrap();
616
617 let stored_fifo = VecDeque::from([
618 String::from("test-cache-keyA"),
619 String::from("test-cache-keyB"),
620 String::from("test-cache-keyC"),
621 ]);
622 let stored_internal_data = InternalData::new(3, stored_fifo, "test-cache-keyC");
623
624 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
625 let mut sequence = Sequence::new();
626
627 mock_concurrent_shared_data
628 .expect_get::<Vec<u8>>()
629 .with(eq("test-cache-key1"))
630 .times(1)
631 .in_sequence(&mut sequence)
632 .returning(move |_x: &str| None);
633
634 mock_concurrent_shared_data
635 .expect_insert()
636 .times(1)
637 .with(eq("test-cache-key1".to_string()), always(), always())
638 .in_sequence(&mut sequence)
639 .returning(move |_x, value: Vec<u8>, _handle_consistency| {
640 (TransactionStatus::Complete, value)
641 });
642
643 mock_concurrent_shared_data
644 .expect_get::<InternalData>()
645 .with(eq("test-cache-internal_data"))
646 .times(1)
647 .in_sequence(&mut sequence)
648 .returning(move |_x: &str| Some(stored_internal_data.clone()));
649
650 mock_concurrent_shared_data
651 .expect_insert()
652 .times(1)
653 .with(
654 eq(String::from("test-cache-internal_data")),
655 always(),
656 always(),
657 )
658 .in_sequence(&mut sequence)
659 .returning(move |_x, value: InternalData, _handle_consistency| {
660 (TransactionStatus::Complete, value)
661 });
662
663 mock_concurrent_shared_data
665 .expect_remove::<Vec<u8>>()
666 .times(1)
667 .with(eq("test-cache-keyA"))
668 .in_sequence(&mut sequence)
669 .returning(move |_key_to_evict| None);
670
671 let stored_fifo = VecDeque::from([
672 String::from("test-cache-keyA"),
673 String::from("test-cache-keyB"),
674 String::from("test-cache-keyC"),
675 String::from("test-cache-key1"),
676 ]);
677 let _stored_internal_data = InternalData::new(3, stored_fifo, "test-cache-key1");
678
679 mock_concurrent_shared_data
681 .expect_insert()
682 .times(1)
683 .with(
684 eq(String::from("test-cache-internal_data")),
685 always(),
686 always(),
687 )
688 .in_sequence(&mut sequence)
689 .returning(move |_x, value: InternalData, _handle_consistency| {
690 (TransactionStatus::Complete, value)
691 });
692
693 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
694 let value = serialized_obj.as_slice().to_vec();
695 assert!(cache.save("key1", value).is_ok());
696 }
697
698 #[test]
699 fn save_in_cache_when_cache_item_has_version_mismatch() {
700 let obj = SerializableObject {
701 property_one: 1,
702 property_two: 10,
703 };
704 let serialized_obj = bincode::serialize(&obj).unwrap();
705
706 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
707 let mut sequence = Sequence::new();
708
709 mock_concurrent_shared_data
710 .expect_get::<Vec<u8>>()
711 .with(eq("test-cache-key1"))
712 .times(1)
713 .in_sequence(&mut sequence)
714 .returning(move |_x: &str| None);
715
716 mock_concurrent_shared_data
717 .expect_insert()
718 .times(1)
719 .in_sequence(&mut sequence)
720 .returning(move |_x, value: Vec<u8>, _handle_consistency| {
721 (TransactionStatus::Rejected, value)
722 });
723
724 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
725 let value = serialized_obj.as_slice().to_vec();
726 assert!(cache.save("key1", value).is_err());
727 }
728
729 #[test]
730 fn test_handle_cache_value_consistency() {
731 let vec1 = "item1".as_bytes().to_vec();
732 let vec2 = "item2".as_bytes().to_vec();
733 assert_eq!(
734 handle_cache_value_consistency(vec1, vec2.clone()).unwrap(),
735 vec2
736 );
737 }
738
739 #[test]
740 fn test_handle_cache_value_consistency_when_remove_or_evict() {
741 let vec1 = "item1".as_bytes().to_vec();
742 let vec2 = "".as_bytes().to_vec();
743 assert_eq!(
744 handle_cache_value_consistency(vec1, vec2.clone()).unwrap(),
745 vec2
746 );
747 }
748
749 #[test]
750 fn test_handle_cache_state_consistency_when_insert() {
751 let fifo1 = VecDeque::from(["A".to_string(), "B".to_string(), "C".to_string()]);
752 let state1: InternalData = InternalData::new(3, fifo1, "C");
753
754 let fifo2 = VecDeque::from(["A".to_string(), "B".to_string(), "D".to_string()]);
755 let state2: InternalData = InternalData::new(3, fifo2, "D");
756
757 let merged_state = handle_cache_state_consistency_when_insert(state1, state2);
758 assert!(merged_state.is_some());
759
760 let merged_internal_data = merged_state.unwrap();
761 assert_eq!(merged_internal_data.fifo.len(), 4);
762 assert!(merged_internal_data.fifo.contains(&"A".to_string()));
763 assert!(merged_internal_data.fifo.contains(&"B".to_string()));
764 assert!(merged_internal_data.fifo.contains(&"C".to_string()));
765 assert_eq!(merged_internal_data.fifo.back().unwrap(), &"D".to_string());
766 assert_eq!(merged_internal_data.last_modified_item_key, "D".to_string());
767 }
768
769 #[test]
770 fn test_handle_cache_state_consistency_when_insert_with_repeated_keys() {
771 let fifo1 = VecDeque::from(["A".to_string(), "B".to_string(), "D".to_string()]);
772 let state1: InternalData = InternalData::new(3, fifo1, "D");
773
774 let fifo2 = VecDeque::from(["A".to_string(), "B".to_string(), "D".to_string()]);
775 let state2: InternalData = InternalData::new(3, fifo2, "D");
776
777 let merged_state = handle_cache_state_consistency_when_insert(state1, state2);
778 assert!(merged_state.is_some());
779
780 let merged_internal_data = merged_state.unwrap();
781 assert_eq!(merged_internal_data.fifo.len(), 3);
782 assert!(merged_internal_data.fifo.contains(&"A".to_string()));
783 assert!(merged_internal_data.fifo.contains(&"B".to_string()));
784 assert_eq!(merged_internal_data.fifo.back().unwrap(), &"D".to_string());
785 assert_eq!(merged_internal_data.last_modified_item_key, "D".to_string());
786 }
787
788 #[test]
789 fn test_handle_cache_state_consistency_when_insert_with_initial_less_keys() {
790 let fifo1 = VecDeque::from(["A".to_string(), "C".to_string()]);
791 let state1: InternalData = InternalData::new(3, fifo1, "C");
792
793 let fifo2 = VecDeque::from(["A".to_string(), "B".to_string(), "D".to_string()]);
794 let state2: InternalData = InternalData::new(3, fifo2, "D");
795
796 let merged_state = handle_cache_state_consistency_when_insert(state1, state2);
797 assert!(merged_state.is_some());
798
799 let merged_internal_data = merged_state.unwrap();
800 assert_eq!(merged_internal_data.fifo.len(), 3);
801 assert!(merged_internal_data.fifo.contains(&"A".to_string()));
802 assert!(merged_internal_data.fifo.contains(&"C".to_string()));
803 assert_eq!(merged_internal_data.fifo.back().unwrap(), &"D".to_string());
804 assert_eq!(merged_internal_data.last_modified_item_key, "D".to_string());
805 }
806
807 #[test]
808 fn test_handle_cache_state_consistency_when_insert_with_initial_more_keys() {
809 let fifo1 = VecDeque::from([
810 "A".to_string(),
811 "C".to_string(),
812 "D".to_string(),
813 "E".to_string(),
814 ]);
815 let state1: InternalData = InternalData::new(3, fifo1, "C");
816
817 let fifo2 = VecDeque::from(["A".to_string(), "B".to_string(), "F".to_string()]);
818 let state2: InternalData = InternalData::new(3, fifo2, "F");
819
820 let merged_state = handle_cache_state_consistency_when_insert(state1, state2);
821 assert!(merged_state.is_some());
822
823 let merged_internal_data = merged_state.unwrap();
824 assert_eq!(merged_internal_data.fifo.len(), 5);
825 assert!(merged_internal_data.fifo.contains(&"A".to_string()));
826 assert!(merged_internal_data.fifo.contains(&"C".to_string()));
827 assert!(merged_internal_data.fifo.contains(&"D".to_string()));
828 assert!(merged_internal_data.fifo.contains(&"E".to_string()));
829 assert_eq!(merged_internal_data.fifo.back().unwrap(), &"F".to_string());
830 assert_eq!(merged_internal_data.last_modified_item_key, "F".to_string());
831 }
832
833 #[test]
834 fn test_handle_cache_state_consistency_when_insert_with_initial_more_keys_and_repeated() {
835 let fifo1 = VecDeque::from([
836 "A".to_string(),
837 "C".to_string(),
838 "D".to_string(),
839 "E".to_string(),
840 ]);
841 let state1: InternalData = InternalData::new(3, fifo1, "C");
842
843 let fifo2 = VecDeque::from(["A".to_string(), "B".to_string(), "D".to_string()]);
844 let state2: InternalData = InternalData::new(3, fifo2, "D");
845
846 let merged_state = handle_cache_state_consistency_when_insert(state1, state2);
847 assert!(merged_state.is_some());
848
849 let merged_internal_data = merged_state.unwrap();
850 assert_eq!(merged_internal_data.fifo.len(), 4);
851 assert!(merged_internal_data.fifo.contains(&"A".to_string()));
852 assert!(merged_internal_data.fifo.contains(&"C".to_string()));
853 assert!(merged_internal_data.fifo.contains(&"E".to_string()));
854 assert_eq!(merged_internal_data.fifo.back().unwrap(), &"D".to_string());
855 assert_eq!(merged_internal_data.last_modified_item_key, "D".to_string());
856 }
857
858 #[test]
859 fn test_handle_cache_state_consistency_when_remove_or_evict() {
860 let fifo1 = VecDeque::from(["A".to_string(), "B".to_string(), "C".to_string()]);
861 let state1: InternalData = InternalData::new(3, fifo1, "C");
862
863 let fifo2 = VecDeque::from(["A".to_string(), "C".to_string()]);
864 let state2: InternalData = InternalData::new(3, fifo2, "B");
865
866 let merged_state = handle_cache_state_consistency_when_remove_or_evict(state1, state2);
867 assert!(merged_state.is_some());
868
869 let merged_internal_data = merged_state.unwrap();
870 assert_eq!(merged_internal_data.fifo.len(), 2);
871 assert!(merged_internal_data.fifo.contains(&"A".to_string()));
872 assert!(merged_internal_data.fifo.contains(&"C".to_string()));
873 assert_eq!(merged_internal_data.last_modified_item_key, "B".to_string());
874 }
875
876 #[test]
877 fn test_handle_cache_state_consistency_when_remove_or_evict_with_prev_insert() {
878 let fifo1 = VecDeque::from([
879 "A".to_string(),
880 "B".to_string(),
881 "C".to_string(),
882 "D".to_string(),
883 ]);
884 let state1: InternalData = InternalData::new(3, fifo1, "C");
885
886 let fifo2 = VecDeque::from(["A".to_string(), "C".to_string()]);
887 let state2: InternalData = InternalData::new(3, fifo2, "B");
888
889 let merged_state = handle_cache_state_consistency_when_remove_or_evict(state1, state2);
890 assert!(merged_state.is_some());
891
892 let merged_internal_data = merged_state.unwrap();
893 assert_eq!(merged_internal_data.fifo.len(), 3);
894 assert!(merged_internal_data.fifo.contains(&"A".to_string()));
895 assert!(merged_internal_data.fifo.contains(&"C".to_string()));
896 assert!(merged_internal_data.fifo.contains(&"D".to_string()));
897 assert_eq!(merged_internal_data.last_modified_item_key, "B".to_string());
898 }
899
900 #[test]
901 fn remove_from_cache_when_item_exists() {
902 let stored_fifo = VecDeque::from([
903 String::from("test-cache-keyA"),
904 String::from("test-cache-key1"),
905 ]);
906 let stored_internal_data = InternalData::new(3, stored_fifo, "test-cache-key1");
907
908 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
909 let mut sequence = Sequence::new();
910
911 mock_concurrent_shared_data
912 .expect_remove()
913 .times(1)
914 .with(eq("test-cache-key1"))
915 .in_sequence(&mut sequence)
916 .returning(move |_key| Some(Vec::<u8>::new()));
917
918 mock_concurrent_shared_data
919 .expect_get::<InternalData>()
920 .with(eq("test-cache-internal_data"))
921 .times(1)
922 .in_sequence(&mut sequence)
923 .returning(move |_x: &str| Some(stored_internal_data.clone()));
924
925 mock_concurrent_shared_data
926 .expect_insert()
927 .times(1)
928 .in_sequence(&mut sequence)
929 .returning(move |_x, value: InternalData, _handle_consistency| {
930 (TransactionStatus::Complete, value)
931 });
932
933 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
934 cache.delete("key1");
935 }
936
937 #[test]
938 fn remove_from_cache_when_item_is_deleted() {
939 let stored_fifo = VecDeque::from([
940 String::from("test-cache-keyA"),
941 String::from("test-cache-keyB"),
942 ]);
943 let stored_internal_data = InternalData::new(3, stored_fifo, "test-cache-keyB");
944
945 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
946 let mut sequence = Sequence::new();
947
948 mock_concurrent_shared_data
949 .expect_remove::<Vec<u8>>()
950 .times(1)
951 .with(eq("test-cache-key1"))
952 .in_sequence(&mut sequence)
953 .returning(move |_key| None);
954
955 mock_concurrent_shared_data
956 .expect_get::<InternalData>()
957 .with(eq("test-cache-internal_data"))
958 .times(1)
959 .in_sequence(&mut sequence)
960 .returning(move |_x: &str| Some(stored_internal_data.clone()));
961
962 mock_concurrent_shared_data
963 .expect_insert()
964 .times(0)
965 .in_sequence(&mut sequence)
966 .returning(move |_x, value: InternalData, _handle_consistency| {
967 (TransactionStatus::Complete, value)
968 });
969
970 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
971 cache.delete("key1");
972 }
973
974 #[test]
975 fn remove_from_cache_when_item_is_deleted_but_it_is_already_removed_from_state() {
976 let stored_fifo = VecDeque::from([
977 String::from("test-cache-keyA"),
978 String::from("test-cache-keyB"),
979 ]);
980 let stored_internal_data = InternalData::new(3, stored_fifo, "test-cache-keyB");
981
982 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
983 let mut sequence = Sequence::new();
984
985 mock_concurrent_shared_data
986 .expect_remove()
987 .times(1)
988 .with(eq("test-cache-key1"))
989 .in_sequence(&mut sequence)
990 .returning(move |_key| Some(Vec::<u8>::new()));
991
992 mock_concurrent_shared_data
993 .expect_get::<InternalData>()
994 .with(eq("test-cache-internal_data"))
995 .times(1)
996 .in_sequence(&mut sequence)
997 .returning(move |_x: &str| Some(stored_internal_data.clone()));
998
999 mock_concurrent_shared_data
1000 .expect_insert()
1001 .times(0)
1002 .in_sequence(&mut sequence)
1003 .returning(move |_x, value: InternalData, _handle_consistency| {
1004 (TransactionStatus::Complete, value)
1005 });
1006
1007 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
1008 cache.delete("key1");
1009 }
1010
1011 #[test]
1013 fn remove_from_cache_when_shared_data_fails_updating_state() {
1014 let stored_fifo = VecDeque::from([String::from("test-cache-key1")]);
1015 let stored_internal_data = InternalData::new(3, stored_fifo, "test-cache-key1");
1016
1017 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
1018 let mut sequence = Sequence::new();
1019
1020 mock_concurrent_shared_data
1021 .expect_remove()
1022 .times(1)
1023 .with(eq("test-cache-key1"))
1024 .in_sequence(&mut sequence)
1025 .returning(move |_key| Some(Vec::<u8>::new()));
1026
1027 mock_concurrent_shared_data
1028 .expect_get::<InternalData>()
1029 .with(eq("test-cache-internal_data"))
1030 .times(1)
1031 .in_sequence(&mut sequence)
1032 .returning(move |_x: &str| Some(stored_internal_data.clone()));
1033
1034 mock_concurrent_shared_data
1035 .expect_insert()
1036 .times(1)
1037 .in_sequence(&mut sequence)
1038 .returning(move |_x, value: InternalData, _handle_consistency| {
1039 (TransactionStatus::Rejected, value)
1040 });
1041
1042 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
1043 cache.delete("key1");
1044 }
1045
1046 #[test]
1047 fn get_item_from_cache_ok() {
1048 let obj = SerializableObject {
1049 property_one: 1,
1050 property_two: 10,
1051 };
1052 let serialized_obj = bincode::serialize(&obj).unwrap();
1053
1054 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
1055
1056 mock_concurrent_shared_data
1057 .expect_get::<Vec<u8>>()
1058 .with(eq("test-cache-key1"))
1059 .times(1)
1060 .returning(move |_x: &str| Some(serialized_obj.clone()));
1061
1062 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
1063
1064 let value = cache.get("key1");
1065 assert!(value.is_some());
1066 assert_eq!(value.unwrap(), bincode::serialize(&obj).unwrap());
1067 }
1068
1069 #[test]
1070 fn get_item_from_cache_empty() {
1071 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
1072
1073 mock_concurrent_shared_data
1074 .expect_get::<Vec<u8>>()
1075 .with(eq("test-cache-key1"))
1076 .times(1)
1077 .returning(move |_x: &str| None);
1078
1079 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
1080 assert!(cache.get("key1").is_none());
1081 }
1082
1083 #[test]
1084 fn test_purge() {
1085 let stored_fifo = VecDeque::from([
1086 String::from("test-cache-key1"),
1087 String::from("test-cache-key2"),
1088 ]);
1089 let stored_internal_data = InternalData::new(3, stored_fifo, "test-cache-key2");
1090
1091 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
1092 let mut sequence = Sequence::new();
1093
1094 mock_concurrent_shared_data
1095 .expect_get::<InternalData>()
1096 .with(eq("test-cache-internal_data"))
1097 .times(1)
1098 .in_sequence(&mut sequence)
1099 .returning(move |_x: &str| Some(stored_internal_data.clone()));
1100
1101 mock_concurrent_shared_data
1102 .expect_remove()
1103 .times(1)
1104 .with(eq("test-cache-key1"))
1105 .in_sequence(&mut sequence)
1106 .returning(move |_key| Some(Vec::<u8>::new()));
1107
1108 mock_concurrent_shared_data
1109 .expect_remove()
1110 .times(1)
1111 .with(eq("test-cache-key2"))
1112 .in_sequence(&mut sequence)
1113 .returning(move |_key| Some(Vec::<u8>::new()));
1114
1115 mock_concurrent_shared_data
1116 .expect_remove()
1117 .times(1)
1118 .with(eq("test-cache-internal_data"))
1119 .in_sequence(&mut sequence)
1120 .returning(move |_key| Some(InternalData::new(3, VecDeque::new(), "test-cache-key2")));
1121
1122 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
1123 cache.purge();
1124 }
1125
1126 #[test]
1127 fn test_purge_cache_empty() {
1128 let mut mock_concurrent_shared_data = MockConcurrentSharedData::default();
1129 let mut sequence = Sequence::new();
1130
1131 mock_concurrent_shared_data
1132 .expect_get::<InternalData>()
1133 .with(eq("test-cache-internal_data"))
1134 .times(1)
1135 .in_sequence(&mut sequence)
1136 .returning(move |_x: &str| None);
1137
1138 mock_concurrent_shared_data
1139 .expect_remove::<Vec<u8>>()
1140 .times(0)
1141 .in_sequence(&mut sequence);
1142
1143 mock_concurrent_shared_data
1144 .expect_remove::<InternalData>()
1145 .times(0)
1146 .in_sequence(&mut sequence);
1147
1148 let cache = FifoCache::new(String::from("test-cache"), 3, mock_concurrent_shared_data);
1149 cache.purge();
1150 }
1151}