1use std::{
18 collections::{BTreeMap, BTreeSet},
19 sync::Arc,
20};
21
22use assert_matches::assert_matches;
23use assert_matches2::assert_let;
24use matrix_sdk_common::{
25 deserialized_responses::{
26 AlgorithmInfo, DecryptedRoomEvent, EncryptionInfo, TimelineEvent, TimelineEventKind,
27 UnableToDecryptInfo, UnableToDecryptReason, VerificationState,
28 },
29 linked_chunk::{
30 ChunkContent, ChunkIdentifier as CId, LinkedChunkId, Position, Update, lazy_loader,
31 },
32};
33use matrix_sdk_test::{ALICE, DEFAULT_TEST_ROOM_ID, event_factory::EventFactory};
34use ruma::{
35 EventId, RoomId, event_id,
36 events::{
37 AnyMessageLikeEvent, AnyTimelineEvent, relation::RelationType,
38 room::message::RoomMessageEventContentWithoutRelation,
39 },
40 push::Action,
41 room_id,
42};
43
44use super::DynEventCacheStore;
45use crate::event_cache::{Gap, store::DEFAULT_CHUNK_CAPACITY};
46
47pub fn make_test_event(room_id: &RoomId, content: &str) -> TimelineEvent {
52 make_test_event_with_event_id(room_id, content, None)
53}
54
55pub fn make_encrypted_test_event(room_id: &RoomId, session_id: &str) -> TimelineEvent {
58 let device_id = "DEVICEID";
59 let builder = EventFactory::new()
60 .encrypted("", "curve_key", device_id, session_id)
61 .room(room_id)
62 .sender(*ALICE);
63
64 let event = builder.into_raw();
65 let utd_info = UnableToDecryptInfo {
66 session_id: Some(session_id.to_owned()),
67 reason: UnableToDecryptReason::MissingMegolmSession { withheld_code: None },
68 };
69
70 TimelineEvent::from_utd(event, utd_info)
71}
72
73pub fn make_test_event_with_event_id(
75 room_id: &RoomId,
76 content: &str,
77 event_id: Option<&EventId>,
78) -> TimelineEvent {
79 let encryption_info = Arc::new(EncryptionInfo {
80 sender: (*ALICE).into(),
81 sender_device: None,
82 forwarder: None,
83 algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
84 curve25519_key: "1337".to_owned(),
85 sender_claimed_keys: Default::default(),
86 session_id: Some("mysessionid9".to_owned()),
87 },
88 verification_state: VerificationState::Verified,
89 });
90
91 let mut builder = EventFactory::new().text_msg(content).room(room_id).sender(*ALICE);
92 if let Some(event_id) = event_id {
93 builder = builder.event_id(event_id);
94 }
95 let event = builder.into_raw();
96
97 TimelineEvent::from_decrypted(
98 DecryptedRoomEvent { event, encryption_info, unsigned_encryption_info: None },
99 Some(vec![Action::Notify]),
100 )
101}
102
103#[track_caller]
108pub fn check_test_event(event: &TimelineEvent, text: &str) {
109 let actions = event.push_actions().unwrap();
111 assert_eq!(actions.len(), 1);
112 assert_matches!(&actions[0], Action::Notify);
113
114 assert_matches!(&event.kind, TimelineEventKind::Decrypted(d) => {
116 assert_eq!(d.encryption_info.sender, *ALICE);
118 assert_matches!(&d.encryption_info.algorithm_info, AlgorithmInfo::MegolmV1AesSha2 { curve25519_key, .. } => {
119 assert_eq!(curve25519_key, "1337");
120 });
121
122 let deserialized = d.event.deserialize().unwrap();
124 assert_matches!(deserialized, AnyTimelineEvent::MessageLike(AnyMessageLikeEvent::RoomMessage(msg)) => {
125 assert_eq!(msg.as_original().unwrap().content.body(), text);
126 });
127 });
128}
129
130#[allow(async_fn_in_trait)]
135pub trait EventCacheStoreIntegrationTests {
136 async fn test_handle_updates_and_rebuild_linked_chunk(&self);
139
140 async fn test_linked_chunk_exists_before_referenced(&self);
143
144 async fn test_linked_chunk_allows_same_event_in_room_and_thread(&self);
147
148 async fn test_load_last_chunk(&self);
150
151 async fn test_load_last_chunk_with_a_cycle(&self);
154
155 async fn test_load_previous_chunk(&self);
157
158 async fn test_linked_chunk_incremental_loading(&self);
161
162 async fn test_linked_chunk_remove_chunk(&self);
164
165 async fn test_linked_chunk_replace_item(&self);
167
168 async fn test_linked_chunk_remove_item(&self);
170
171 async fn test_linked_chunk_detach_last_items(&self);
173
174 async fn test_linked_chunk_start_end_reattach_items(&self);
176
177 async fn test_linked_chunk_clear(&self);
179
180 async fn test_linked_chunk_clear_and_reinsert(&self);
182
183 async fn test_rebuild_empty_linked_chunk(&self);
186
187 async fn test_linked_chunk_multiple_rooms(&self);
190
191 async fn test_load_all_chunks_metadata(&self);
193
194 async fn test_clear_all_events(&self);
196
197 async fn test_remove_room(&self);
199
200 async fn test_filter_duplicated_events(&self);
202
203 async fn test_filter_duplicate_events_no_events(&self);
205
206 async fn test_find_event(&self);
208
209 async fn test_find_event_when_event_in_room_and_thread(&self);
212
213 async fn test_find_event_relations(&self);
215
216 async fn test_find_event_relations_when_event_in_room_and_thread(&self);
219
220 async fn test_get_room_events(&self);
222
223 async fn test_get_room_events_filtered(&self);
225
226 async fn test_get_room_events_with_event_in_room_and_thread(&self);
229
230 async fn test_save_event(&self);
232
233 async fn test_save_event_updates_event_in_room_and_thread(&self);
236
237 async fn test_thread_vs_room_linked_chunk(&self);
240}
241
242impl EventCacheStoreIntegrationTests for DynEventCacheStore {
243 async fn test_handle_updates_and_rebuild_linked_chunk(&self) {
244 let room_id = room_id!("!r0:matrix.org");
245 let linked_chunk_id = LinkedChunkId::Room(room_id);
246
247 self.handle_linked_chunk_updates(
248 linked_chunk_id,
249 vec![
250 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
252 Update::PushItems {
254 at: Position::new(CId::new(0), 0),
255 items: vec![
256 make_test_event(room_id, "hello"),
257 make_test_event(room_id, "world"),
258 ],
259 },
260 Update::NewGapChunk {
262 previous: Some(CId::new(0)),
263 new: CId::new(1),
264 next: None,
265 gap: Gap { token: "parmesan".to_owned() },
266 },
267 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
269 Update::PushItems {
271 at: Position::new(CId::new(2), 0),
272 items: vec![make_test_event(room_id, "sup")],
273 },
274 ],
275 )
276 .await
277 .unwrap();
278
279 let lc = lazy_loader::from_all_chunks::<3, _, _>(
281 self.load_all_chunks(linked_chunk_id).await.unwrap(),
282 )
283 .unwrap()
284 .unwrap();
285
286 let mut chunks = lc.chunks();
287
288 {
289 let first = chunks.next().unwrap();
290 assert_eq!(first.identifier(), CId::new(0));
293
294 assert_matches!(first.content(), ChunkContent::Items(events) => {
295 assert_eq!(events.len(), 2);
296 check_test_event(&events[0], "hello");
297 check_test_event(&events[1], "world");
298 });
299 }
300
301 {
302 let second = chunks.next().unwrap();
303 assert_eq!(second.identifier(), CId::new(1));
304
305 assert_matches!(second.content(), ChunkContent::Gap(gap) => {
306 assert_eq!(gap.token, "parmesan");
307 });
308 }
309
310 {
311 let third = chunks.next().unwrap();
312 assert_eq!(third.identifier(), CId::new(2));
313
314 assert_matches!(third.content(), ChunkContent::Items(events) => {
315 assert_eq!(events.len(), 1);
316 check_test_event(&events[0], "sup");
317 });
318 }
319
320 assert!(chunks.next().is_none());
321 }
322
323 async fn test_linked_chunk_exists_before_referenced(&self) {
324 let room_id = *DEFAULT_TEST_ROOM_ID;
325 let linked_chunk_id = LinkedChunkId::Room(room_id);
326
327 self.handle_linked_chunk_updates(
329 linked_chunk_id,
330 vec![Update::NewItemsChunk {
331 previous: Some(CId::new(41)),
332 new: CId::new(42),
333 next: None,
334 }],
335 )
336 .await
337 .unwrap_err();
338
339 self.handle_linked_chunk_updates(
341 linked_chunk_id,
342 vec![Update::NewItemsChunk {
343 previous: None,
344 new: CId::new(42),
345 next: Some(CId::new(43)),
346 }],
347 )
348 .await
349 .unwrap_err();
350
351 self.handle_linked_chunk_updates(
353 linked_chunk_id,
354 vec![Update::NewGapChunk {
355 previous: Some(CId::new(41)),
356 new: CId::new(42),
357 next: None,
358 gap: Gap { token: "gap".to_owned() },
359 }],
360 )
361 .await
362 .unwrap_err();
363
364 self.handle_linked_chunk_updates(
366 linked_chunk_id,
367 vec![Update::NewGapChunk {
368 previous: None,
369 new: CId::new(42),
370 next: Some(CId::new(43)),
371 gap: Gap { token: "gap".to_owned() },
372 }],
373 )
374 .await
375 .unwrap_err();
376 }
377
378 async fn test_linked_chunk_allows_same_event_in_room_and_thread(&self) {
379 let room_id = *DEFAULT_TEST_ROOM_ID;
384 let thread_root = event_id!("$thread_root");
385
386 let event_id = event_id!("$thread_reply");
389 let event = make_test_event_with_event_id(room_id, "thread reply", Some(event_id));
390
391 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
392 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
393
394 self.handle_linked_chunk_updates(
396 room_linked_chunk_id,
397 vec![
398 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
399 Update::PushItems { at: Position::new(CId::new(1), 0), items: vec![event.clone()] },
400 ],
401 )
402 .await
403 .unwrap();
404
405 self.handle_linked_chunk_updates(
407 thread_linked_chunk_id,
408 vec![
409 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
410 Update::PushItems { at: Position::new(CId::new(1), 0), items: vec![event] },
411 ],
412 )
413 .await
414 .unwrap();
415
416 let room_chunks = self.load_all_chunks(room_linked_chunk_id).await.unwrap();
418 let thread_chunks = self.load_all_chunks(thread_linked_chunk_id).await.unwrap();
419
420 assert_eq!(room_chunks.len(), 1);
421 assert_eq!(thread_chunks.len(), 1);
422
423 assert_matches!(&room_chunks[0].content, ChunkContent::Items(events) => {
425 assert_eq!(events.len(), 1);
426 assert_eq!(events[0].event_id(), Some(event_id));
427 });
428 assert_matches!(&thread_chunks[0].content, ChunkContent::Items(events) => {
429 assert_eq!(events.len(), 1);
430 assert_eq!(events[0].event_id(), Some(event_id));
431 });
432 }
433
434 async fn test_load_all_chunks_metadata(&self) {
435 let room_id = room_id!("!r0:matrix.org");
436 let linked_chunk_id = LinkedChunkId::Room(room_id);
437
438 self.handle_linked_chunk_updates(
439 linked_chunk_id,
440 vec![
441 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
443 Update::PushItems {
445 at: Position::new(CId::new(0), 0),
446 items: vec![
447 make_test_event(room_id, "hello"),
448 make_test_event(room_id, "world"),
449 ],
450 },
451 Update::NewGapChunk {
453 previous: Some(CId::new(0)),
454 new: CId::new(1),
455 next: None,
456 gap: Gap { token: "parmesan".to_owned() },
457 },
458 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
460 Update::PushItems {
462 at: Position::new(CId::new(2), 0),
463 items: vec![make_test_event(room_id, "sup")],
464 },
465 Update::NewItemsChunk { previous: Some(CId::new(2)), new: CId::new(3), next: None },
467 ],
468 )
469 .await
470 .unwrap();
471
472 let metas = self.load_all_chunks_metadata(linked_chunk_id).await.unwrap();
473 assert_eq!(metas.len(), 4);
474
475 assert_eq!(metas[0].identifier, CId::new(0));
477 assert_eq!(metas[0].previous, None);
478 assert_eq!(metas[0].next, Some(CId::new(1)));
479 assert_eq!(metas[0].num_items, 2);
480
481 assert_eq!(metas[1].identifier, CId::new(1));
483 assert_eq!(metas[1].previous, Some(CId::new(0)));
484 assert_eq!(metas[1].next, Some(CId::new(2)));
485 assert_eq!(metas[1].num_items, 0);
486
487 assert_eq!(metas[2].identifier, CId::new(2));
489 assert_eq!(metas[2].previous, Some(CId::new(1)));
490 assert_eq!(metas[2].next, Some(CId::new(3)));
491 assert_eq!(metas[2].num_items, 1);
492
493 assert_eq!(metas[3].identifier, CId::new(3));
495 assert_eq!(metas[3].previous, Some(CId::new(2)));
496 assert_eq!(metas[3].next, None);
497 assert_eq!(metas[3].num_items, 0);
498 }
499
500 async fn test_load_last_chunk(&self) {
501 let room_id = room_id!("!r0:matrix.org");
502 let linked_chunk_id = LinkedChunkId::Room(room_id);
503 let event = |msg: &str| make_test_event(room_id, msg);
504
505 {
507 let (last_chunk, chunk_identifier_generator) =
508 self.load_last_chunk(linked_chunk_id).await.unwrap();
509
510 assert!(last_chunk.is_none());
511 assert_eq!(chunk_identifier_generator.current(), 0);
512 }
513
514 {
516 self.handle_linked_chunk_updates(
517 linked_chunk_id,
518 vec![
519 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
520 Update::PushItems {
521 at: Position::new(CId::new(42), 0),
522 items: vec![event("saucisse de morteau"), event("comté")],
523 },
524 ],
525 )
526 .await
527 .unwrap();
528
529 let (last_chunk, chunk_identifier_generator) =
530 self.load_last_chunk(linked_chunk_id).await.unwrap();
531
532 assert_matches!(last_chunk, Some(last_chunk) => {
533 assert_eq!(last_chunk.identifier, 42);
534 assert!(last_chunk.previous.is_none());
535 assert!(last_chunk.next.is_none());
536 assert_matches!(last_chunk.content, ChunkContent::Items(items) => {
537 assert_eq!(items.len(), 2);
538 check_test_event(&items[0], "saucisse de morteau");
539 check_test_event(&items[1], "comté");
540 });
541 });
542 assert_eq!(chunk_identifier_generator.current(), 42);
543 }
544
545 {
547 self.handle_linked_chunk_updates(
548 linked_chunk_id,
549 vec![
550 Update::NewItemsChunk {
551 previous: Some(CId::new(42)),
552 new: CId::new(7),
553 next: None,
554 },
555 Update::PushItems {
556 at: Position::new(CId::new(7), 0),
557 items: vec![event("fondue"), event("gruyère"), event("mont d'or")],
558 },
559 ],
560 )
561 .await
562 .unwrap();
563
564 let (last_chunk, chunk_identifier_generator) =
565 self.load_last_chunk(linked_chunk_id).await.unwrap();
566
567 assert_matches!(last_chunk, Some(last_chunk) => {
568 assert_eq!(last_chunk.identifier, 7);
569 assert_matches!(last_chunk.previous, Some(previous) => {
570 assert_eq!(previous, 42);
571 });
572 assert!(last_chunk.next.is_none());
573 assert_matches!(last_chunk.content, ChunkContent::Items(items) => {
574 assert_eq!(items.len(), 3);
575 check_test_event(&items[0], "fondue");
576 check_test_event(&items[1], "gruyère");
577 check_test_event(&items[2], "mont d'or");
578 });
579 });
580 assert_eq!(chunk_identifier_generator.current(), 42);
581 }
582 }
583
584 async fn test_load_last_chunk_with_a_cycle(&self) {
585 let room_id = room_id!("!r0:matrix.org");
586 let linked_chunk_id = LinkedChunkId::Room(room_id);
587
588 self.handle_linked_chunk_updates(
589 linked_chunk_id,
590 vec![
591 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
592 Update::NewItemsChunk {
593 previous: Some(CId::new(0)),
597 new: CId::new(1),
598 next: Some(CId::new(0)),
599 },
600 ],
601 )
602 .await
603 .unwrap();
604
605 self.load_last_chunk(linked_chunk_id).await.unwrap_err();
606 }
607
608 async fn test_load_previous_chunk(&self) {
609 let room_id = room_id!("!r0:matrix.org");
610 let linked_chunk_id = LinkedChunkId::Room(room_id);
611 let event = |msg: &str| make_test_event(room_id, msg);
612
613 {
616 let previous_chunk =
617 self.load_previous_chunk(linked_chunk_id, CId::new(153)).await.unwrap();
618
619 assert!(previous_chunk.is_none());
620 }
621
622 {
625 self.handle_linked_chunk_updates(
626 linked_chunk_id,
627 vec![Update::NewItemsChunk { previous: None, new: CId::new(42), next: None }],
628 )
629 .await
630 .unwrap();
631
632 let previous_chunk =
633 self.load_previous_chunk(linked_chunk_id, CId::new(42)).await.unwrap();
634
635 assert!(previous_chunk.is_none());
636 }
637
638 {
640 self.handle_linked_chunk_updates(
641 linked_chunk_id,
642 vec![
643 Update::NewItemsChunk {
645 previous: None,
646 new: CId::new(7),
647 next: Some(CId::new(42)),
648 },
649 Update::PushItems {
650 at: Position::new(CId::new(7), 0),
651 items: vec![event("brigand du jorat"), event("morbier")],
652 },
653 ],
654 )
655 .await
656 .unwrap();
657
658 let previous_chunk =
659 self.load_previous_chunk(linked_chunk_id, CId::new(42)).await.unwrap();
660
661 assert_matches!(previous_chunk, Some(previous_chunk) => {
662 assert_eq!(previous_chunk.identifier, 7);
663 assert!(previous_chunk.previous.is_none());
664 assert_matches!(previous_chunk.next, Some(next) => {
665 assert_eq!(next, 42);
666 });
667 assert_matches!(previous_chunk.content, ChunkContent::Items(items) => {
668 assert_eq!(items.len(), 2);
669 check_test_event(&items[0], "brigand du jorat");
670 check_test_event(&items[1], "morbier");
671 });
672 });
673 }
674 }
675
676 async fn test_linked_chunk_incremental_loading(&self) {
677 let room_id = room_id!("!r0:matrix.org");
678 let linked_chunk_id = LinkedChunkId::Room(room_id);
679 let event = |msg: &str| make_test_event(room_id, msg);
680
681 {
683 let (last_chunk, chunk_identifier_generator) =
684 self.load_last_chunk(linked_chunk_id).await.unwrap();
685
686 assert!(last_chunk.is_none());
687 assert_eq!(chunk_identifier_generator.current(), 0);
688 }
689
690 self.handle_linked_chunk_updates(
691 linked_chunk_id,
692 vec![
693 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
695 Update::PushItems {
697 at: Position::new(CId::new(0), 0),
698 items: vec![event("a"), event("b")],
699 },
700 Update::NewGapChunk {
702 previous: Some(CId::new(0)),
703 new: CId::new(1),
704 next: None,
705 gap: Gap { token: "morbier".to_owned() },
706 },
707 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
709 Update::PushItems {
711 at: Position::new(CId::new(2), 0),
712 items: vec![event("c"), event("d"), event("e")],
713 },
714 ],
715 )
716 .await
717 .unwrap();
718
719 let mut linked_chunk = {
721 let (last_chunk, chunk_identifier_generator) =
722 self.load_last_chunk(linked_chunk_id).await.unwrap();
723
724 assert_eq!(chunk_identifier_generator.current(), 2);
725
726 let linked_chunk = lazy_loader::from_last_chunk::<DEFAULT_CHUNK_CAPACITY, _, _>(
727 last_chunk,
728 chunk_identifier_generator,
729 )
730 .unwrap() .unwrap(); let mut rchunks = linked_chunk.rchunks();
734
735 assert_matches!(rchunks.next(), Some(chunk) => {
737 assert_eq!(chunk.identifier(), 2);
738 assert_eq!(chunk.lazy_previous(), Some(CId::new(1)));
739
740 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
741 assert_eq!(events.len(), 3);
742 check_test_event(&events[0], "c");
743 check_test_event(&events[1], "d");
744 check_test_event(&events[2], "e");
745 });
746 });
747
748 assert!(rchunks.next().is_none());
749
750 linked_chunk
751 };
752
753 {
755 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
756 let previous_chunk =
757 self.load_previous_chunk(linked_chunk_id, first_chunk).await.unwrap().unwrap();
758
759 lazy_loader::insert_new_first_chunk(&mut linked_chunk, previous_chunk).unwrap();
760
761 let mut rchunks = linked_chunk.rchunks();
762
763 assert_matches!(rchunks.next(), Some(chunk) => {
765 assert_eq!(chunk.identifier(), 2);
766 assert!(chunk.lazy_previous().is_none());
767
768 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
770 assert_eq!(events.len(), 3);
771 check_test_event(&events[0], "c");
772 check_test_event(&events[1], "d");
773 check_test_event(&events[2], "e");
774 });
775 });
776
777 assert_matches!(rchunks.next(), Some(chunk) => {
779 assert_eq!(chunk.identifier(), 1);
780 assert_eq!(chunk.lazy_previous(), Some(CId::new(0)));
781
782 assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
783 assert_eq!(gap.token, "morbier");
784 });
785 });
786
787 assert!(rchunks.next().is_none());
788 }
789
790 {
792 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
793 let previous_chunk =
794 self.load_previous_chunk(linked_chunk_id, first_chunk).await.unwrap().unwrap();
795
796 lazy_loader::insert_new_first_chunk(&mut linked_chunk, previous_chunk).unwrap();
797
798 let mut rchunks = linked_chunk.rchunks();
799
800 assert_matches!(rchunks.next(), Some(chunk) => {
802 assert_eq!(chunk.identifier(), 2);
803 assert!(chunk.lazy_previous().is_none());
804
805 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
807 assert_eq!(events.len(), 3);
808 check_test_event(&events[0], "c");
809 check_test_event(&events[1], "d");
810 check_test_event(&events[2], "e");
811 });
812 });
813
814 assert_matches!(rchunks.next(), Some(chunk) => {
816 assert_eq!(chunk.identifier(), 1);
817 assert!(chunk.lazy_previous().is_none());
818
819 assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
821 assert_eq!(gap.token, "morbier");
822 });
823 });
824
825 assert_matches!(rchunks.next(), Some(chunk) => {
827 assert_eq!(chunk.identifier(), 0);
828 assert!(chunk.lazy_previous().is_none());
829
830 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
831 assert_eq!(events.len(), 2);
832 check_test_event(&events[0], "a");
833 check_test_event(&events[1], "b");
834 });
835 });
836
837 assert!(rchunks.next().is_none());
838 }
839
840 {
842 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
843 let previous_chunk =
844 self.load_previous_chunk(linked_chunk_id, first_chunk).await.unwrap();
845
846 assert!(previous_chunk.is_none());
847 }
848
849 {
852 let mut chunks = linked_chunk.chunks();
853
854 assert_matches!(chunks.next(), Some(chunk) => {
856 assert_eq!(chunk.identifier(), 0);
857 assert!(chunk.lazy_previous().is_none());
858
859 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
860 assert_eq!(events.len(), 2);
861 check_test_event(&events[0], "a");
862 check_test_event(&events[1], "b");
863 });
864 });
865
866 assert_matches!(chunks.next(), Some(chunk) => {
868 assert_eq!(chunk.identifier(), 1);
869 assert!(chunk.lazy_previous().is_none());
870
871 assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
872 assert_eq!(gap.token, "morbier");
873 });
874 });
875
876 assert_matches!(chunks.next(), Some(chunk) => {
878 assert_eq!(chunk.identifier(), 2);
879 assert!(chunk.lazy_previous().is_none());
880
881 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
882 assert_eq!(events.len(), 3);
883 check_test_event(&events[0], "c");
884 check_test_event(&events[1], "d");
885 check_test_event(&events[2], "e");
886 });
887 });
888
889 assert!(chunks.next().is_none());
890 }
891 }
892
893 async fn test_linked_chunk_remove_chunk(&self) {
894 let room_id = &DEFAULT_TEST_ROOM_ID;
895 let linked_chunk_id = LinkedChunkId::Room(room_id);
896
897 self.handle_linked_chunk_updates(
898 linked_chunk_id,
899 vec![
900 Update::NewGapChunk {
901 previous: None,
902 new: CId::new(42),
903 next: None,
904 gap: Gap { token: "raclette".to_owned() },
905 },
906 Update::NewGapChunk {
907 previous: Some(CId::new(42)),
908 new: CId::new(43),
909 next: None,
910 gap: Gap { token: "fondue".to_owned() },
911 },
912 Update::NewGapChunk {
913 previous: Some(CId::new(43)),
914 new: CId::new(44),
915 next: None,
916 gap: Gap { token: "tartiflette".to_owned() },
917 },
918 Update::RemoveChunk(CId::new(43)),
919 ],
920 )
921 .await
922 .unwrap();
923
924 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
925
926 assert_eq!(chunks.len(), 2);
927
928 let c = chunks.remove(0);
930 assert_eq!(c.identifier, CId::new(42));
931 assert_eq!(c.previous, None);
932 assert_eq!(c.next, Some(CId::new(44)));
933 assert_matches!(c.content, ChunkContent::Gap(gap) => {
934 assert_eq!(gap.token, "raclette");
935 });
936
937 let c = chunks.remove(0);
938 assert_eq!(c.identifier, CId::new(44));
939 assert_eq!(c.previous, Some(CId::new(42)));
940 assert_eq!(c.next, None);
941 assert_matches!(c.content, ChunkContent::Gap(gap) => {
942 assert_eq!(gap.token, "tartiflette");
943 });
944 }
945
946 async fn test_linked_chunk_replace_item(&self) {
947 let room_id = &DEFAULT_TEST_ROOM_ID;
948 let linked_chunk_id = LinkedChunkId::Room(room_id);
949 let event_id = event_id!("$world");
950
951 self.handle_linked_chunk_updates(
952 linked_chunk_id,
953 vec![
954 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
955 Update::PushItems {
956 at: Position::new(CId::new(42), 0),
957 items: vec![
958 make_test_event(room_id, "hello"),
959 make_test_event_with_event_id(room_id, "world", Some(event_id)),
960 ],
961 },
962 Update::ReplaceItem {
963 at: Position::new(CId::new(42), 1),
964 item: make_test_event_with_event_id(room_id, "yolo", Some(event_id)),
965 },
966 ],
967 )
968 .await
969 .unwrap();
970
971 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
972
973 assert_eq!(chunks.len(), 1);
974
975 let c = chunks.remove(0);
976 assert_eq!(c.identifier, CId::new(42));
977 assert_eq!(c.previous, None);
978 assert_eq!(c.next, None);
979 assert_matches!(c.content, ChunkContent::Items(events) => {
980 assert_eq!(events.len(), 2);
981 check_test_event(&events[0], "hello");
982 check_test_event(&events[1], "yolo");
983 });
984 }
985
986 async fn test_linked_chunk_remove_item(&self) {
987 let room_id = *DEFAULT_TEST_ROOM_ID;
988 let linked_chunk_id = LinkedChunkId::Room(room_id);
989
990 self.handle_linked_chunk_updates(
991 linked_chunk_id,
992 vec![
993 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
994 Update::PushItems {
995 at: Position::new(CId::new(42), 0),
996 items: vec![
997 make_test_event(room_id, "one"),
998 make_test_event(room_id, "two"),
999 make_test_event(room_id, "three"),
1000 make_test_event(room_id, "four"),
1001 make_test_event(room_id, "five"),
1002 make_test_event(room_id, "six"),
1003 ],
1004 },
1005 Update::RemoveItem { at: Position::new(CId::new(42), 2) },
1006 ],
1007 )
1008 .await
1009 .unwrap();
1010
1011 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1012
1013 assert_eq!(chunks.len(), 1);
1014
1015 let c = chunks.remove(0);
1016 assert_eq!(c.identifier, CId::new(42));
1017 assert_eq!(c.previous, None);
1018 assert_eq!(c.next, None);
1019 assert_matches!(c.content, ChunkContent::Items(events) => {
1020 assert_eq!(events.len(), 5);
1021 check_test_event(&events[0], "one");
1022 check_test_event(&events[1], "two");
1023 check_test_event(&events[2], "four");
1024 check_test_event(&events[3], "five");
1025 check_test_event(&events[4], "six");
1026 });
1027 }
1028
1029 async fn test_linked_chunk_detach_last_items(&self) {
1030 let room_id = *DEFAULT_TEST_ROOM_ID;
1031 let linked_chunk_id = LinkedChunkId::Room(room_id);
1032
1033 self.handle_linked_chunk_updates(
1034 linked_chunk_id,
1035 vec![
1036 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1037 Update::PushItems {
1038 at: Position::new(CId::new(42), 0),
1039 items: vec![
1040 make_test_event(room_id, "hello"),
1041 make_test_event(room_id, "world"),
1042 make_test_event(room_id, "howdy"),
1043 ],
1044 },
1045 Update::DetachLastItems { at: Position::new(CId::new(42), 1) },
1046 ],
1047 )
1048 .await
1049 .unwrap();
1050
1051 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1052
1053 assert_eq!(chunks.len(), 1);
1054
1055 let c = chunks.remove(0);
1056 assert_eq!(c.identifier, CId::new(42));
1057 assert_eq!(c.previous, None);
1058 assert_eq!(c.next, None);
1059 assert_matches!(c.content, ChunkContent::Items(events) => {
1060 assert_eq!(events.len(), 1);
1061 check_test_event(&events[0], "hello");
1062 });
1063 }
1064
1065 async fn test_linked_chunk_start_end_reattach_items(&self) {
1066 let room_id = *DEFAULT_TEST_ROOM_ID;
1067 let linked_chunk_id = LinkedChunkId::Room(room_id);
1068
1069 self.handle_linked_chunk_updates(
1073 linked_chunk_id,
1074 vec![
1075 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1076 Update::PushItems {
1077 at: Position::new(CId::new(42), 0),
1078 items: vec![
1079 make_test_event(room_id, "hello"),
1080 make_test_event(room_id, "world"),
1081 make_test_event(room_id, "howdy"),
1082 ],
1083 },
1084 Update::StartReattachItems,
1085 Update::EndReattachItems,
1086 ],
1087 )
1088 .await
1089 .unwrap();
1090
1091 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1092
1093 assert_eq!(chunks.len(), 1);
1094
1095 let c = chunks.remove(0);
1096 assert_eq!(c.identifier, CId::new(42));
1097 assert_eq!(c.previous, None);
1098 assert_eq!(c.next, None);
1099 assert_matches!(c.content, ChunkContent::Items(events) => {
1100 assert_eq!(events.len(), 3);
1101 check_test_event(&events[0], "hello");
1102 check_test_event(&events[1], "world");
1103 check_test_event(&events[2], "howdy");
1104 });
1105 }
1106
1107 async fn test_linked_chunk_clear(&self) {
1108 let room_id = *DEFAULT_TEST_ROOM_ID;
1109 let linked_chunk_id = LinkedChunkId::Room(room_id);
1110 let event_0 = make_test_event(room_id, "hello");
1111 let event_1 = make_test_event(room_id, "world");
1112 let event_2 = make_test_event(room_id, "howdy");
1113
1114 self.handle_linked_chunk_updates(
1115 linked_chunk_id,
1116 vec![
1117 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1118 Update::NewGapChunk {
1119 previous: Some(CId::new(42)),
1120 new: CId::new(54),
1121 next: None,
1122 gap: Gap { token: "fondue".to_owned() },
1123 },
1124 Update::PushItems {
1125 at: Position::new(CId::new(42), 0),
1126 items: vec![event_0.clone(), event_1, event_2],
1127 },
1128 Update::Clear,
1129 ],
1130 )
1131 .await
1132 .unwrap();
1133
1134 let chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1135 assert!(chunks.is_empty());
1136 }
1137
1138 async fn test_linked_chunk_clear_and_reinsert(&self) {
1139 let room_id = *DEFAULT_TEST_ROOM_ID;
1140 let linked_chunk_id = LinkedChunkId::Room(room_id);
1141 let event_0 = make_test_event(room_id, "hello");
1142 let event_1 = make_test_event(room_id, "world");
1143 let event_2 = make_test_event(room_id, "howdy");
1144
1145 self.handle_linked_chunk_updates(
1146 linked_chunk_id,
1147 vec![
1148 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1149 Update::NewGapChunk {
1150 previous: Some(CId::new(42)),
1151 new: CId::new(54),
1152 next: None,
1153 gap: Gap { token: "fondue".to_owned() },
1154 },
1155 Update::PushItems {
1156 at: Position::new(CId::new(42), 0),
1157 items: vec![event_0.clone(), event_1, event_2],
1158 },
1159 Update::Clear,
1160 ],
1161 )
1162 .await
1163 .unwrap();
1164
1165 let chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1166 assert!(chunks.is_empty());
1167
1168 self.handle_linked_chunk_updates(
1170 linked_chunk_id,
1171 vec![
1172 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1173 Update::PushItems { at: Position::new(CId::new(42), 0), items: vec![event_0] },
1174 ],
1175 )
1176 .await
1177 .unwrap();
1178 }
1179
1180 async fn test_rebuild_empty_linked_chunk(&self) {
1181 let linked_chunk = lazy_loader::from_all_chunks::<3, _, _>(
1183 self.load_all_chunks(LinkedChunkId::Room(&DEFAULT_TEST_ROOM_ID)).await.unwrap(),
1184 )
1185 .unwrap();
1186 assert!(linked_chunk.is_none());
1187 }
1188
1189 async fn test_linked_chunk_multiple_rooms(&self) {
1190 let room1 = room_id!("!realcheeselovers:raclette.fr");
1191 let linked_chunk_id1 = LinkedChunkId::Room(room1);
1192 let room2 = room_id!("!realcheeselovers:fondue.ch");
1193 let linked_chunk_id2 = LinkedChunkId::Room(room2);
1194
1195 self.handle_linked_chunk_updates(
1199 linked_chunk_id1,
1200 vec![
1201 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1202 Update::PushItems {
1203 at: Position::new(CId::new(42), 0),
1204 items: vec![
1205 make_test_event(room1, "best cheese is raclette"),
1206 make_test_event(room1, "obviously"),
1207 ],
1208 },
1209 ],
1210 )
1211 .await
1212 .unwrap();
1213
1214 self.handle_linked_chunk_updates(
1215 linked_chunk_id2,
1216 vec![
1217 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1218 Update::PushItems {
1219 at: Position::new(CId::new(42), 0),
1220 items: vec![make_test_event(room1, "beaufort is the best")],
1221 },
1222 ],
1223 )
1224 .await
1225 .unwrap();
1226
1227 let mut chunks_room1 = self.load_all_chunks(linked_chunk_id1).await.unwrap();
1229 assert_eq!(chunks_room1.len(), 1);
1230
1231 let c = chunks_room1.remove(0);
1232 assert_matches!(c.content, ChunkContent::Items(events) => {
1233 assert_eq!(events.len(), 2);
1234 check_test_event(&events[0], "best cheese is raclette");
1235 check_test_event(&events[1], "obviously");
1236 });
1237
1238 let mut chunks_room2 = self.load_all_chunks(linked_chunk_id2).await.unwrap();
1240 assert_eq!(chunks_room2.len(), 1);
1241
1242 let c = chunks_room2.remove(0);
1243 assert_matches!(c.content, ChunkContent::Items(events) => {
1244 assert_eq!(events.len(), 1);
1245 check_test_event(&events[0], "beaufort is the best");
1246 });
1247 }
1248
1249 async fn test_clear_all_events(&self) {
1250 let r0 = room_id!("!r0:matrix.org");
1251 let linked_chunk_id0 = LinkedChunkId::Room(r0);
1252 let r1 = room_id!("!r1:matrix.org");
1253 let linked_chunk_id1 = LinkedChunkId::Room(r1);
1254
1255 self.handle_linked_chunk_updates(
1257 linked_chunk_id0,
1258 vec![
1259 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1261 Update::PushItems {
1263 at: Position::new(CId::new(0), 0),
1264 items: vec![make_test_event(r0, "hello"), make_test_event(r0, "world")],
1265 },
1266 ],
1267 )
1268 .await
1269 .unwrap();
1270
1271 self.handle_linked_chunk_updates(
1273 linked_chunk_id1,
1274 vec![
1275 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1277 Update::NewGapChunk {
1279 previous: Some(CId::new(0)),
1280 new: CId::new(1),
1281 next: None,
1282 gap: Gap { token: "bleu d'auvergne".to_owned() },
1283 },
1284 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
1286 Update::PushItems {
1288 at: Position::new(CId::new(2), 0),
1289 items: vec![make_test_event(r0, "yummy")],
1290 },
1291 ],
1292 )
1293 .await
1294 .unwrap();
1295
1296 assert!(
1298 lazy_loader::from_all_chunks::<3, _, _>(
1299 self.load_all_chunks(linked_chunk_id0).await.unwrap()
1300 )
1301 .unwrap()
1302 .is_some()
1303 );
1304 assert!(
1305 lazy_loader::from_all_chunks::<3, _, _>(
1306 self.load_all_chunks(linked_chunk_id1).await.unwrap()
1307 )
1308 .unwrap()
1309 .is_some()
1310 );
1311
1312 self.clear_all_events().await.unwrap();
1314
1315 assert!(
1317 lazy_loader::from_all_chunks::<3, _, _>(
1318 self.load_all_chunks(linked_chunk_id0).await.unwrap()
1319 )
1320 .unwrap()
1321 .is_none()
1322 );
1323 assert!(
1324 lazy_loader::from_all_chunks::<3, _, _>(
1325 self.load_all_chunks(linked_chunk_id1).await.unwrap()
1326 )
1327 .unwrap()
1328 .is_none()
1329 );
1330 }
1331
1332 async fn test_remove_room(&self) {
1333 let r0 = room_id!("!r0:matrix.org");
1334 let linked_chunk_id0 = LinkedChunkId::Room(r0);
1335 let r1 = room_id!("!r1:matrix.org");
1336 let linked_chunk_id1 = LinkedChunkId::Room(r1);
1337
1338 self.handle_linked_chunk_updates(
1340 linked_chunk_id0,
1341 vec![
1342 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1344 Update::PushItems {
1346 at: Position::new(CId::new(0), 0),
1347 items: vec![make_test_event(r0, "hello"), make_test_event(r0, "world")],
1348 },
1349 ],
1350 )
1351 .await
1352 .unwrap();
1353
1354 self.handle_linked_chunk_updates(
1356 linked_chunk_id1,
1357 vec![
1358 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1360 Update::PushItems {
1362 at: Position::new(CId::new(0), 0),
1363 items: vec![make_test_event(r0, "yummy")],
1364 },
1365 ],
1366 )
1367 .await
1368 .unwrap();
1369
1370 self.remove_room(r0).await.unwrap();
1372
1373 let r0_linked_chunk = self.load_all_chunks(linked_chunk_id0).await.unwrap();
1375 assert!(r0_linked_chunk.is_empty());
1376
1377 let r1_linked_chunk = self.load_all_chunks(linked_chunk_id1).await.unwrap();
1379 assert!(!r1_linked_chunk.is_empty());
1380 }
1381
1382 async fn test_filter_duplicated_events(&self) {
1383 let room_id = room_id!("!r0:matrix.org");
1384 let linked_chunk_id = LinkedChunkId::Room(room_id);
1385 let another_room_id = room_id!("!r1:matrix.org");
1386 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
1387 let event = |msg: &str| make_test_event(room_id, msg);
1388
1389 let event_comte = event("comté");
1390 let event_brigand = event("brigand du jorat");
1391 let event_raclette = event("raclette");
1392 let event_morbier = event("morbier");
1393 let event_gruyere = event("gruyère");
1394 let event_tome = event("tome");
1395 let event_mont_dor = event("mont d'or");
1396
1397 self.handle_linked_chunk_updates(
1398 linked_chunk_id,
1399 vec![
1400 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1401 Update::PushItems {
1402 at: Position::new(CId::new(0), 0),
1403 items: vec![event_comte.clone(), event_brigand.clone()],
1404 },
1405 Update::NewGapChunk {
1406 previous: Some(CId::new(0)),
1407 new: CId::new(1),
1408 next: None,
1409 gap: Gap { token: "brillat-savarin".to_owned() },
1410 },
1411 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
1412 Update::PushItems {
1413 at: Position::new(CId::new(2), 0),
1414 items: vec![event_morbier.clone(), event_mont_dor.clone()],
1415 },
1416 ],
1417 )
1418 .await
1419 .unwrap();
1420
1421 self.handle_linked_chunk_updates(
1424 another_linked_chunk_id,
1425 vec![
1426 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1427 Update::PushItems {
1428 at: Position::new(CId::new(0), 0),
1429 items: vec![event_tome.clone()],
1430 },
1431 ],
1432 )
1433 .await
1434 .unwrap();
1435
1436 let duplicated_events = BTreeMap::from_iter(
1437 self.filter_duplicated_events(
1438 linked_chunk_id,
1439 vec![
1440 event_comte.event_id().unwrap().to_owned(),
1441 event_raclette.event_id().unwrap().to_owned(),
1442 event_morbier.event_id().unwrap().to_owned(),
1443 event_gruyere.event_id().unwrap().to_owned(),
1444 event_tome.event_id().unwrap().to_owned(),
1445 event_mont_dor.event_id().unwrap().to_owned(),
1446 ],
1447 )
1448 .await
1449 .unwrap(),
1450 );
1451
1452 assert_eq!(duplicated_events.len(), 3);
1453
1454 assert_eq!(
1455 *duplicated_events.get(event_comte.event_id().unwrap()).unwrap(),
1456 Position::new(CId::new(0), 0)
1457 );
1458 assert_eq!(
1459 *duplicated_events.get(event_morbier.event_id().unwrap()).unwrap(),
1460 Position::new(CId::new(2), 0)
1461 );
1462 assert_eq!(
1463 *duplicated_events.get(event_mont_dor.event_id().unwrap()).unwrap(),
1464 Position::new(CId::new(2), 1)
1465 );
1466 }
1467
1468 async fn test_filter_duplicate_events_no_events(&self) {
1469 let room_id = *DEFAULT_TEST_ROOM_ID;
1470 let linked_chunk_id = LinkedChunkId::Room(room_id);
1471 let duplicates = self.filter_duplicated_events(linked_chunk_id, Vec::new()).await.unwrap();
1472 assert!(duplicates.is_empty());
1473 }
1474
1475 async fn test_find_event(&self) {
1476 let room_id = room_id!("!r0:matrix.org");
1477 let another_room_id = room_id!("!r1:matrix.org");
1478 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
1479 let event = |msg: &str| make_test_event(room_id, msg);
1480
1481 let event_comte = event("comté");
1482 let event_gruyere = event("gruyère");
1483
1484 self.handle_linked_chunk_updates(
1486 LinkedChunkId::Room(room_id),
1487 vec![
1488 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1489 Update::PushItems {
1490 at: Position::new(CId::new(0), 0),
1491 items: vec![event_comte.clone()],
1492 },
1493 ],
1494 )
1495 .await
1496 .unwrap();
1497
1498 self.handle_linked_chunk_updates(
1500 another_linked_chunk_id,
1501 vec![
1502 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1503 Update::PushItems {
1504 at: Position::new(CId::new(0), 0),
1505 items: vec![event_gruyere.clone()],
1506 },
1507 ],
1508 )
1509 .await
1510 .unwrap();
1511
1512 let event = self
1514 .find_event(room_id, event_comte.event_id().unwrap().as_ref())
1515 .await
1516 .expect("failed to query for finding an event")
1517 .expect("failed to find an event");
1518
1519 assert_eq!(event.event_id(), event_comte.event_id());
1520
1521 assert!(
1523 self.find_event(room_id, event_gruyere.event_id().unwrap().as_ref())
1524 .await
1525 .expect("failed to query for finding an event")
1526 .is_none()
1527 );
1528
1529 self.clear_all_events().await.expect("failed to clear all rooms chunks");
1531 assert!(
1532 self.find_event(room_id, event_comte.event_id().unwrap().as_ref())
1533 .await
1534 .expect("failed to query for finding an event")
1535 .is_none()
1536 );
1537 }
1538
1539 async fn test_find_event_when_event_in_room_and_thread(&self) {
1540 let room_id = *DEFAULT_TEST_ROOM_ID;
1541 let thread_root = event_id!("$thread_root");
1542
1543 let room_event_id = event_id!("$room_event");
1545 let room_event = make_test_event_with_event_id(room_id, "room event", Some(room_event_id));
1546
1547 let thread_event_id = event_id!("$thread_event");
1549 let thread_event =
1550 make_test_event_with_event_id(room_id, "thread event", Some(thread_event_id));
1551
1552 let room_and_thread_event_id = event_id!("$room_and_thread");
1555 let room_and_thread_event = make_test_event_with_event_id(
1556 room_id,
1557 "room and thread",
1558 Some(room_and_thread_event_id),
1559 );
1560
1561 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
1562 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
1563
1564 self.handle_linked_chunk_updates(
1566 room_linked_chunk_id,
1567 vec![
1568 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
1569 Update::PushItems {
1570 at: Position::new(CId::new(1), 0),
1571 items: vec![room_event, room_and_thread_event.clone()],
1572 },
1573 ],
1574 )
1575 .await
1576 .unwrap();
1577
1578 self.handle_linked_chunk_updates(
1580 thread_linked_chunk_id,
1581 vec![
1582 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
1583 Update::PushItems {
1584 at: Position::new(CId::new(1), 0),
1585 items: vec![thread_event, room_and_thread_event],
1586 },
1587 ],
1588 )
1589 .await
1590 .unwrap();
1591
1592 assert_matches!(self.find_event(room_id, room_event_id).await, Ok(Some(event)) => {
1594 assert_eq!(event.event_id().unwrap(), room_event_id)
1595 });
1596
1597 assert_matches!(self.find_event(room_id, thread_event_id).await, Ok(Some(event)) => {
1599 assert_eq!(event.event_id().unwrap(), thread_event_id)
1600 });
1601
1602 assert_matches!(self.find_event(room_id, room_and_thread_event_id).await, Ok(Some(event)) => {
1604 assert_eq!(event.event_id().unwrap(), room_and_thread_event_id);
1605 });
1606 }
1607
1608 async fn test_find_event_relations(&self) {
1609 let room_id = room_id!("!r0:matrix.org");
1610 let another_room_id = room_id!("!r1:matrix.org");
1611
1612 let f = EventFactory::new().room(room_id).sender(*ALICE);
1613
1614 let eid1 = event_id!("$event1:matrix.org");
1616 let e1 = f.text_msg("comter").event_id(eid1).into_event();
1617
1618 let edit_eid1 = event_id!("$edit_event1:matrix.org");
1619 let edit_e1 = f
1620 .text_msg("* comté")
1621 .event_id(edit_eid1)
1622 .edit(eid1, RoomMessageEventContentWithoutRelation::text_plain("comté"))
1623 .into_event();
1624
1625 let reaction_eid1 = event_id!("$reaction_event1:matrix.org");
1626 let reaction_e1 = f.reaction(eid1, "👍").event_id(reaction_eid1).into_event();
1627
1628 let eid2 = event_id!("$event2:matrix.org");
1629 let e2 = f.text_msg("galette saucisse").event_id(eid2).into_event();
1630
1631 let f = f.room(another_room_id);
1633
1634 let eid3 = event_id!("$event3:matrix.org");
1635 let e3 = f.text_msg("gruyère").event_id(eid3).into_event();
1636
1637 let reaction_eid3 = event_id!("$reaction_event3:matrix.org");
1638 let reaction_e3 = f.reaction(eid3, "👍").event_id(reaction_eid3).into_event();
1639
1640 self.save_event(room_id, e1).await.unwrap();
1642 self.save_event(room_id, edit_e1).await.unwrap();
1643 self.save_event(room_id, reaction_e1.clone()).await.unwrap();
1644 self.save_event(room_id, e2).await.unwrap();
1645 self.save_event(another_room_id, e3).await.unwrap();
1646 self.save_event(another_room_id, reaction_e3).await.unwrap();
1647
1648 let relations = self.find_event_relations(room_id, eid1, None).await.unwrap();
1650 assert_eq!(relations.len(), 2);
1651 assert!(
1653 relations.iter().any(|(ev, pos)| ev.event_id() == Some(edit_eid1) && pos.is_none())
1654 );
1655 assert!(
1656 relations.iter().any(|(ev, pos)| ev.event_id() == Some(reaction_eid1) && pos.is_none())
1657 );
1658
1659 let relations = self
1661 .find_event_relations(room_id, eid1, Some(&[RelationType::Replacement]))
1662 .await
1663 .unwrap();
1664 assert_eq!(relations.len(), 1);
1665 assert_eq!(relations[0].0.event_id(), Some(edit_eid1));
1666
1667 let relations = self
1668 .find_event_relations(
1669 room_id,
1670 eid1,
1671 Some(&[RelationType::Replacement, RelationType::Annotation]),
1672 )
1673 .await
1674 .unwrap();
1675 assert_eq!(relations.len(), 2);
1676 assert!(relations.iter().any(|r| r.0.event_id() == Some(edit_eid1)));
1677 assert!(relations.iter().any(|r| r.0.event_id() == Some(reaction_eid1)));
1678
1679 let relations = self
1681 .find_event_relations(another_room_id, eid1, Some(&[RelationType::Replacement]))
1682 .await
1683 .unwrap();
1684 assert!(relations.is_empty());
1685
1686 self.handle_linked_chunk_updates(
1691 LinkedChunkId::Room(room_id),
1692 vec![
1693 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1694 Update::PushItems { at: Position::new(CId::new(0), 0), items: vec![reaction_e1] },
1695 ],
1696 )
1697 .await
1698 .unwrap();
1699
1700 let relations = self.find_event_relations(room_id, eid1, None).await.unwrap();
1703
1704 assert!(relations.iter().any(|(ev, pos)| {
1706 ev.event_id() == Some(reaction_eid1) && *pos == Some(Position::new(CId::new(0), 0))
1707 }));
1708
1709 assert!(
1711 relations.iter().any(|(ev, pos)| ev.event_id() == Some(edit_eid1) && pos.is_none())
1712 );
1713 }
1714
1715 async fn test_find_event_relations_when_event_in_room_and_thread(&self) {
1716 let room_id = *DEFAULT_TEST_ROOM_ID;
1717 let thread_root = event_id!("$thread_root");
1718
1719 let event_id = event_id!("$event");
1722 let event = make_test_event_with_event_id(room_id, "event", Some(event_id));
1723
1724 let extra_thread_event_id = event_id!("$extra_thread_event");
1727 let extra_thread_event = make_test_event_with_event_id(
1728 room_id,
1729 "extra thread event",
1730 Some(extra_thread_event_id),
1731 );
1732
1733 let room_reaction_id = event_id!("$room_reaction");
1735 let room_reaction = EventFactory::new()
1736 .room(room_id)
1737 .sender(*ALICE)
1738 .reaction(event_id, "room")
1739 .event_id(room_reaction_id)
1740 .into_event();
1741
1742 let thread_reaction_id = event_id!("$thread_reaction");
1744 let thread_reaction = EventFactory::new()
1745 .room(room_id)
1746 .sender(*ALICE)
1747 .reaction(event_id, "thread")
1748 .event_id(thread_reaction_id)
1749 .into_event();
1750
1751 let room_and_thread_reaction_id = event_id!("$room_and_thread_reaction");
1754 let room_and_thread_reaction = EventFactory::new()
1755 .room(room_id)
1756 .sender(*ALICE)
1757 .reaction(event_id, "room and thread")
1758 .event_id(room_and_thread_reaction_id)
1759 .into_event();
1760
1761 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
1762 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
1763
1764 self.handle_linked_chunk_updates(
1766 room_linked_chunk_id,
1767 vec![
1768 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
1769 Update::PushItems {
1770 at: Position::new(CId::new(1), 0),
1771 items: vec![event.clone(), room_reaction, room_and_thread_reaction.clone()],
1772 },
1773 ],
1774 )
1775 .await
1776 .unwrap();
1777
1778 self.handle_linked_chunk_updates(
1780 thread_linked_chunk_id,
1781 vec![
1782 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
1783 Update::PushItems {
1784 at: Position::new(CId::new(1), 0),
1785 items: vec![
1786 event.clone(),
1787 extra_thread_event,
1788 thread_reaction,
1789 room_and_thread_reaction,
1790 ],
1791 },
1792 ],
1793 )
1794 .await
1795 .unwrap();
1796
1797 assert_matches!(self.find_event_relations(room_id, event_id, None).await, Ok(relations) => {
1799 assert_eq!(relations.len(), 3);
1800 let room_relation = relations
1803 .iter()
1804 .find(|relation| relation.0.event_id().unwrap() == room_reaction_id)
1805 .unwrap();
1806 assert_matches!(room_relation, (_, Some(position)) => {
1807 assert_eq!(*position, Position::new(CId::new(1), 1));
1808 });
1809
1810 let thread_relation = relations
1813 .iter()
1814 .find(|relation| relation.0.event_id().unwrap() == thread_reaction_id)
1815 .unwrap();
1816 assert_matches!(thread_relation, (_, None));
1817
1818 let room_and_thread_relation = relations
1821 .iter()
1822 .find(|relation| relation.0.event_id().unwrap() == room_and_thread_reaction_id)
1823 .unwrap();
1824 assert_matches!(room_and_thread_relation, (_, Some(position)) => {
1825 assert_eq!(*position, Position::new(CId::new(1), 2));
1826 });
1827 });
1828 }
1829
1830 async fn test_get_room_events(&self) {
1831 let room_id = room_id!("!r0:matrix.org");
1832 let another_room_id = room_id!("!r1:matrix.org");
1833 let linked_chunk_id = LinkedChunkId::Room(room_id);
1834 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
1835 let event = |msg: &str| make_test_event(room_id, msg);
1836
1837 let event_comte = event("comté");
1838 let event_gruyere = event("gruyère");
1839 let event_stilton = event("stilton");
1840
1841 self.handle_linked_chunk_updates(
1843 linked_chunk_id,
1844 vec![
1845 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1846 Update::PushItems {
1847 at: Position::new(CId::new(0), 0),
1848 items: vec![event_comte.clone(), event_gruyere.clone()],
1849 },
1850 ],
1851 )
1852 .await
1853 .unwrap();
1854
1855 self.handle_linked_chunk_updates(
1857 another_linked_chunk_id,
1858 vec![
1859 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1860 Update::PushItems {
1861 at: Position::new(CId::new(0), 0),
1862 items: vec![event_stilton.clone()],
1863 },
1864 ],
1865 )
1866 .await
1867 .unwrap();
1868
1869 let events = self
1871 .get_room_events(room_id, None, None)
1872 .await
1873 .expect("failed to query for room events");
1874
1875 assert_eq!(events.len(), 2);
1876
1877 let got_ids: Vec<_> =
1878 events.into_iter().map(|ev| ev.event_id().map(ToOwned::to_owned)).collect();
1879 let expected_ids = vec![
1880 event_comte.event_id().map(ToOwned::to_owned),
1881 event_gruyere.event_id().map(ToOwned::to_owned),
1882 ];
1883
1884 for expected in expected_ids {
1885 assert!(
1886 got_ids.contains(&expected),
1887 "Expected event {expected:?} not in got events: {got_ids:?}."
1888 );
1889 }
1890 }
1891
1892 async fn test_get_room_events_filtered(&self) {
1893 macro_rules! assert_expected_events {
1894 ($events:expr, [$($item:expr),* $(,)?]) => {{
1895 let got_ids: BTreeSet<_> = $events.into_iter().map(|ev| ev.event_id().map(ToOwned::to_owned)).flatten().collect();
1896 let expected_ids = BTreeSet::from([$($item.event_id().unwrap().to_owned()),*]);
1897
1898 assert_eq!(got_ids, expected_ids);
1899 }};
1900 }
1901
1902 let room_id = room_id!("!r0:matrix.org");
1903 let linked_chunk_id = LinkedChunkId::Room(room_id);
1904 let another_room_id = room_id!("!r1:matrix.org");
1905 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
1906
1907 let event = |session_id: &str| make_encrypted_test_event(room_id, session_id);
1908
1909 let first_event = event("session_1");
1910 let second_event = event("session_2");
1911 let third_event = event("session_3");
1912 let fourth_event = make_test_event(room_id, "It's a secret to everybody");
1913
1914 self.handle_linked_chunk_updates(
1916 linked_chunk_id,
1917 vec![
1918 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1919 Update::PushItems {
1920 at: Position::new(CId::new(0), 0),
1921 items: vec![first_event.clone(), second_event.clone(), fourth_event.clone()],
1922 },
1923 ],
1924 )
1925 .await
1926 .unwrap();
1927
1928 self.handle_linked_chunk_updates(
1930 another_linked_chunk_id,
1931 vec![
1932 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1933 Update::PushItems {
1934 at: Position::new(CId::new(0), 0),
1935 items: vec![third_event.clone()],
1936 },
1937 ],
1938 )
1939 .await
1940 .unwrap();
1941
1942 let events = self
1944 .get_room_events(room_id, Some("m.room.encrypted"), None)
1945 .await
1946 .expect("failed to query for room events");
1947
1948 assert_eq!(events.len(), 2);
1949 assert_expected_events!(events, [first_event, second_event]);
1950
1951 let events = self
1954 .get_room_events(room_id, Some("m.room.encrypted"), Some("session_1"))
1955 .await
1956 .expect("failed to query for room events");
1957
1958 assert_eq!(events.len(), 1);
1959 assert_expected_events!(events, [first_event]);
1960 }
1961
1962 async fn test_get_room_events_with_event_in_room_and_thread(&self) {
1963 let room_id = *DEFAULT_TEST_ROOM_ID;
1964 let thread_root = event_id!("$thread_root");
1965
1966 let room_event_id = event_id!("$room_event");
1968 let room_event = make_test_event_with_event_id(room_id, "room event", Some(room_event_id));
1969
1970 let thread_event_id = event_id!("$thread_event");
1974 let thread_event =
1975 make_test_event_with_event_id(room_id, "thread event", Some(thread_event_id));
1976
1977 let room_and_thread_event_id = event_id!("$room_and_thread");
1980 let room_and_thread_event = make_test_event_with_event_id(
1981 room_id,
1982 "room and thread",
1983 Some(room_and_thread_event_id),
1984 );
1985
1986 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
1987 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
1988
1989 self.handle_linked_chunk_updates(
1991 room_linked_chunk_id,
1992 vec![
1993 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
1994 Update::PushItems {
1995 at: Position::new(CId::new(1), 0),
1996 items: vec![room_event, room_and_thread_event.clone()],
1997 },
1998 ],
1999 )
2000 .await
2001 .unwrap();
2002
2003 self.handle_linked_chunk_updates(
2005 thread_linked_chunk_id,
2006 vec![
2007 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2008 Update::PushItems {
2009 at: Position::new(CId::new(1), 0),
2010 items: vec![thread_event, room_and_thread_event],
2011 },
2012 ],
2013 )
2014 .await
2015 .unwrap();
2016
2017 let expected_event_ids =
2020 BTreeSet::from([room_event_id, thread_event_id, room_and_thread_event_id]);
2021 assert_matches!(self.get_room_events(room_id, None, None).await, Ok(events) => {
2022 assert_eq!(events.len(), 3);
2023 assert!(events.iter().all(|event| {
2024 expected_event_ids.contains(event.event_id().unwrap())
2025 }));
2026 });
2027 }
2028
2029 async fn test_save_event(&self) {
2030 let room_id = room_id!("!r0:matrix.org");
2031 let another_room_id = room_id!("!r1:matrix.org");
2032
2033 let event = |msg: &str| make_test_event(room_id, msg);
2034 let event_comte = event("comté");
2035 let event_gruyere = event("gruyère");
2036
2037 self.save_event(room_id, event_comte.clone()).await.unwrap();
2039
2040 self.save_event(another_room_id, event_gruyere.clone()).await.unwrap();
2042
2043 let event = self
2045 .find_event(room_id, event_comte.event_id().unwrap().as_ref())
2046 .await
2047 .expect("failed to query for finding an event")
2048 .expect("failed to find an event");
2049 assert_eq!(event.event_id(), event_comte.event_id());
2050
2051 let event = self
2052 .find_event(another_room_id, event_gruyere.event_id().unwrap().as_ref())
2053 .await
2054 .expect("failed to query for finding an event")
2055 .expect("failed to find an event");
2056 assert_eq!(event.event_id(), event_gruyere.event_id());
2057
2058 assert!(
2060 self.find_event(another_room_id, event_comte.event_id().unwrap().as_ref())
2061 .await
2062 .expect("failed to query for finding an event")
2063 .is_none()
2064 );
2065 assert!(
2066 self.find_event(room_id, event_gruyere.event_id().unwrap().as_ref())
2067 .await
2068 .expect("failed to query for finding an event")
2069 .is_none()
2070 );
2071 }
2072
2073 async fn test_save_event_updates_event_in_room_and_thread(&self) {
2074 let room_id = *DEFAULT_TEST_ROOM_ID;
2075 let thread_root = event_id!("$thread_root");
2076
2077 let event_id = event_id!("$event");
2080 let event = make_test_event_with_event_id(room_id, "event", Some(event_id));
2081
2082 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
2083 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
2084
2085 self.handle_linked_chunk_updates(
2087 room_linked_chunk_id,
2088 vec![
2089 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2090 Update::PushItems { at: Position::new(CId::new(1), 0), items: vec![event.clone()] },
2091 ],
2092 )
2093 .await
2094 .unwrap();
2095
2096 self.handle_linked_chunk_updates(
2098 thread_linked_chunk_id,
2099 vec![
2100 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2101 Update::PushItems { at: Position::new(CId::new(1), 0), items: vec![event.clone()] },
2102 ],
2103 )
2104 .await
2105 .unwrap();
2106
2107 let updated_content = "updated content";
2110 let updated = make_test_event_with_event_id(room_id, updated_content, Some(event_id));
2111 self.save_event(room_id, updated).await.unwrap();
2112
2113 let room_chunks = self.load_all_chunks(room_linked_chunk_id).await.unwrap();
2115 let thread_chunks = self.load_all_chunks(thread_linked_chunk_id).await.unwrap();
2116
2117 assert_eq!(room_chunks.len(), 1);
2118 assert_eq!(thread_chunks.len(), 1);
2119
2120 assert_matches!(&room_chunks[0].content, ChunkContent::Items(events) => {
2122 assert_eq!(events.len(), 1);
2123 assert_eq!(events[0].event_id(), Some(event_id));
2124 check_test_event(&events[0], updated_content);
2125 });
2126 assert_matches!(&thread_chunks[0].content, ChunkContent::Items(events) => {
2127 assert_eq!(events.len(), 1);
2128 assert_eq!(events[0].event_id(), Some(event_id));
2129 check_test_event(&events[0], updated_content);
2130 });
2131 }
2132
2133 async fn test_thread_vs_room_linked_chunk(&self) {
2134 let room_id = room_id!("!r0:matrix.org");
2135
2136 let event = |msg: &str| make_test_event(room_id, msg);
2137
2138 let thread1_ev = event("comté");
2139 let thread2_ev = event("gruyère");
2140 let thread2_ev2 = event("beaufort");
2141 let room_ev = event("brillat savarin triple crème");
2142
2143 let thread_root1 = event("thread1");
2144 let thread_root2 = event("thread2");
2145
2146 self.handle_linked_chunk_updates(
2148 LinkedChunkId::Thread(room_id, thread_root1.event_id().unwrap()),
2149 vec![
2150 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2151 Update::PushItems {
2152 at: Position::new(CId::new(0), 0),
2153 items: vec![thread1_ev.clone()],
2154 },
2155 ],
2156 )
2157 .await
2158 .unwrap();
2159
2160 self.handle_linked_chunk_updates(
2162 LinkedChunkId::Thread(room_id, thread_root2.event_id().unwrap()),
2163 vec![
2164 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2165 Update::PushItems {
2166 at: Position::new(CId::new(0), 0),
2167 items: vec![thread2_ev.clone(), thread2_ev2.clone()],
2168 },
2169 ],
2170 )
2171 .await
2172 .unwrap();
2173
2174 self.handle_linked_chunk_updates(
2176 LinkedChunkId::Room(room_id),
2177 vec![
2178 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2179 Update::PushItems {
2180 at: Position::new(CId::new(0), 0),
2181 items: vec![room_ev.clone()],
2182 },
2183 ],
2184 )
2185 .await
2186 .unwrap();
2187
2188 self.find_event(room_id, thread2_ev.event_id().unwrap().as_ref())
2190 .await
2191 .expect("failed to query for finding an event")
2192 .expect("failed to find thread1_ev");
2193
2194 self.find_event(room_id, thread2_ev.event_id().unwrap().as_ref())
2195 .await
2196 .expect("failed to query for finding an event")
2197 .expect("failed to find thread2_ev");
2198
2199 self.find_event(room_id, thread2_ev2.event_id().unwrap().as_ref())
2200 .await
2201 .expect("failed to query for finding an event")
2202 .expect("failed to find thread2_ev2");
2203
2204 self.find_event(room_id, room_ev.event_id().unwrap().as_ref())
2205 .await
2206 .expect("failed to query for finding an event")
2207 .expect("failed to find room_ev");
2208
2209 let dups = self
2211 .filter_duplicated_events(
2212 LinkedChunkId::Thread(room_id, thread_root1.event_id().unwrap()),
2213 vec![
2214 thread1_ev.event_id().unwrap().to_owned(),
2215 room_ev.event_id().unwrap().to_owned(),
2216 ],
2217 )
2218 .await
2219 .unwrap();
2220 assert_eq!(dups.len(), 1);
2221 assert_eq!(dups[0].0, thread1_ev.event_id().unwrap());
2222
2223 let all_chunks = self
2225 .load_all_chunks(LinkedChunkId::Thread(room_id, thread_root2.event_id().unwrap()))
2226 .await
2227 .unwrap();
2228 assert_eq!(all_chunks.len(), 1);
2229 assert_eq!(all_chunks[0].identifier, CId::new(0));
2230 assert_let!(ChunkContent::Items(observed_items) = all_chunks[0].content.clone());
2231 assert_eq!(observed_items.len(), 2);
2232 assert_eq!(observed_items[0].event_id(), thread2_ev.event_id());
2233 assert_eq!(observed_items[1].event_id(), thread2_ev2.event_id());
2234
2235 let metas = self
2238 .load_all_chunks_metadata(LinkedChunkId::Thread(
2239 room_id,
2240 thread_root2.event_id().unwrap(),
2241 ))
2242 .await
2243 .unwrap();
2244 assert_eq!(metas.len(), 1);
2245 assert_eq!(metas[0].identifier, CId::new(0));
2246 assert_eq!(metas[0].num_items, 2);
2247
2248 let (last_chunk, _chunk_identifier_generator) = self
2250 .load_last_chunk(LinkedChunkId::Thread(room_id, thread_root1.event_id().unwrap()))
2251 .await
2252 .unwrap();
2253 let last_chunk = last_chunk.unwrap();
2254 assert_eq!(last_chunk.identifier, CId::new(0));
2255 assert_let!(ChunkContent::Items(observed_items) = last_chunk.content);
2256 assert_eq!(observed_items.len(), 1);
2257 assert_eq!(observed_items[0].event_id(), thread1_ev.event_id());
2258 }
2259}
2260
2261#[allow(unused_macros, unused_extern_crates)]
2289#[macro_export]
2290macro_rules! event_cache_store_integration_tests {
2291 () => {
2292 mod event_cache_store_integration_tests {
2293 use matrix_sdk_test::async_test;
2294 use $crate::event_cache::store::{
2295 EventCacheStoreIntegrationTests, IntoEventCacheStore,
2296 };
2297
2298 use super::get_event_cache_store;
2299
2300 #[async_test]
2301 async fn test_handle_updates_and_rebuild_linked_chunk() {
2302 let event_cache_store =
2303 get_event_cache_store().await.unwrap().into_event_cache_store();
2304 event_cache_store.test_handle_updates_and_rebuild_linked_chunk().await;
2305 }
2306
2307 #[async_test]
2308 async fn test_linked_chunk_exists_before_referenced() {
2309 let event_cache_store =
2310 get_event_cache_store().await.unwrap().into_event_cache_store();
2311 event_cache_store.test_linked_chunk_exists_before_referenced().await;
2312 }
2313
2314 #[async_test]
2315 async fn test_linked_chunk_allow_same_event_in_room_and_thread() {
2316 let event_cache_store =
2317 get_event_cache_store().await.unwrap().into_event_cache_store();
2318 event_cache_store.test_linked_chunk_allows_same_event_in_room_and_thread().await;
2319 }
2320
2321 #[async_test]
2322 async fn test_load_last_chunk() {
2323 let event_cache_store =
2324 get_event_cache_store().await.unwrap().into_event_cache_store();
2325 event_cache_store.test_load_last_chunk().await;
2326 }
2327
2328 #[async_test]
2329 async fn test_load_last_chunk_with_a_cycle() {
2330 let event_cache_store =
2331 get_event_cache_store().await.unwrap().into_event_cache_store();
2332 event_cache_store.test_load_last_chunk_with_a_cycle().await;
2333 }
2334
2335 #[async_test]
2336 async fn test_load_previous_chunk() {
2337 let event_cache_store =
2338 get_event_cache_store().await.unwrap().into_event_cache_store();
2339 event_cache_store.test_load_previous_chunk().await;
2340 }
2341
2342 #[async_test]
2343 async fn test_linked_chunk_incremental_loading() {
2344 let event_cache_store =
2345 get_event_cache_store().await.unwrap().into_event_cache_store();
2346 event_cache_store.test_linked_chunk_incremental_loading().await;
2347 }
2348
2349 #[async_test]
2350 async fn test_linked_chunk_remove_chunk() {
2351 let event_cache_store =
2352 get_event_cache_store().await.unwrap().into_event_cache_store();
2353 event_cache_store.test_linked_chunk_remove_chunk().await;
2354 }
2355
2356 #[async_test]
2357 async fn test_linked_chunk_replace_item() {
2358 let event_cache_store =
2359 get_event_cache_store().await.unwrap().into_event_cache_store();
2360 event_cache_store.test_linked_chunk_replace_item().await;
2361 }
2362
2363 #[async_test]
2364 async fn test_linked_chunk_remove_item() {
2365 let event_cache_store =
2366 get_event_cache_store().await.unwrap().into_event_cache_store();
2367 event_cache_store.test_linked_chunk_remove_item().await;
2368 }
2369
2370 #[async_test]
2371 async fn test_linked_chunk_detach_last_items() {
2372 let event_cache_store =
2373 get_event_cache_store().await.unwrap().into_event_cache_store();
2374 event_cache_store.test_linked_chunk_detach_last_items().await;
2375 }
2376
2377 #[async_test]
2378 async fn test_linked_chunk_start_end_reattach_items() {
2379 let event_cache_store =
2380 get_event_cache_store().await.unwrap().into_event_cache_store();
2381 event_cache_store.test_linked_chunk_start_end_reattach_items().await;
2382 }
2383
2384 #[async_test]
2385 async fn test_linked_chunk_clear() {
2386 let event_cache_store =
2387 get_event_cache_store().await.unwrap().into_event_cache_store();
2388 event_cache_store.test_linked_chunk_clear().await;
2389 }
2390
2391 #[async_test]
2392 async fn test_linked_chunk_clear_and_reinsert() {
2393 let event_cache_store =
2394 get_event_cache_store().await.unwrap().into_event_cache_store();
2395 event_cache_store.test_linked_chunk_clear_and_reinsert().await;
2396 }
2397
2398 #[async_test]
2399 async fn test_rebuild_empty_linked_chunk() {
2400 let event_cache_store =
2401 get_event_cache_store().await.unwrap().into_event_cache_store();
2402 event_cache_store.test_rebuild_empty_linked_chunk().await;
2403 }
2404
2405 #[async_test]
2406 async fn test_linked_chunk_multiple_rooms() {
2407 let event_cache_store =
2408 get_event_cache_store().await.unwrap().into_event_cache_store();
2409 event_cache_store.test_linked_chunk_multiple_rooms().await;
2410 }
2411
2412 #[async_test]
2413 async fn test_load_all_chunks_metadata() {
2414 let event_cache_store =
2415 get_event_cache_store().await.unwrap().into_event_cache_store();
2416 event_cache_store.test_load_all_chunks_metadata().await;
2417 }
2418
2419 #[async_test]
2420 async fn test_clear_all_events() {
2421 let event_cache_store =
2422 get_event_cache_store().await.unwrap().into_event_cache_store();
2423 event_cache_store.test_clear_all_events().await;
2424 }
2425
2426 #[async_test]
2427 async fn test_remove_room() {
2428 let event_cache_store =
2429 get_event_cache_store().await.unwrap().into_event_cache_store();
2430 event_cache_store.test_remove_room().await;
2431 }
2432
2433 #[async_test]
2434 async fn test_filter_duplicated_events() {
2435 let event_cache_store =
2436 get_event_cache_store().await.unwrap().into_event_cache_store();
2437 event_cache_store.test_filter_duplicated_events().await;
2438 }
2439
2440 #[async_test]
2441 async fn test_filter_duplicate_events_no_events() {
2442 let event_cache_store =
2443 get_event_cache_store().await.unwrap().into_event_cache_store();
2444 event_cache_store.test_filter_duplicate_events_no_events().await;
2445 }
2446
2447 #[async_test]
2448 async fn test_find_event() {
2449 let event_cache_store =
2450 get_event_cache_store().await.unwrap().into_event_cache_store();
2451 event_cache_store.test_find_event().await;
2452 }
2453
2454 #[async_test]
2455 async fn test_find_event_when_event_in_room_and_thread() {
2456 let event_cache_store =
2457 get_event_cache_store().await.unwrap().into_event_cache_store();
2458 event_cache_store.test_find_event_when_event_in_room_and_thread().await;
2459 }
2460
2461 #[async_test]
2462 async fn test_find_event_relations() {
2463 let event_cache_store =
2464 get_event_cache_store().await.unwrap().into_event_cache_store();
2465 event_cache_store.test_find_event_relations().await;
2466 }
2467
2468 #[async_test]
2469 async fn test_find_event_relations_when_event_in_room_and_thread() {
2470 let event_cache_store =
2471 get_event_cache_store().await.unwrap().into_event_cache_store();
2472 event_cache_store.test_find_event_relations_when_event_in_room_and_thread().await;
2473 }
2474
2475 #[async_test]
2476 async fn test_get_room_events() {
2477 let event_cache_store =
2478 get_event_cache_store().await.unwrap().into_event_cache_store();
2479 event_cache_store.test_get_room_events().await;
2480 }
2481
2482 #[async_test]
2483 async fn test_get_room_events_filtered() {
2484 let event_cache_store =
2485 get_event_cache_store().await.unwrap().into_event_cache_store();
2486 event_cache_store.test_get_room_events_filtered().await;
2487 }
2488
2489 #[async_test]
2490 async fn test_get_room_events_with_event_in_room_and_thread() {
2491 let event_cache_store =
2492 get_event_cache_store().await.unwrap().into_event_cache_store();
2493 event_cache_store.test_get_room_events_with_event_in_room_and_thread().await;
2494 }
2495
2496 #[async_test]
2497 async fn test_save_event() {
2498 let event_cache_store =
2499 get_event_cache_store().await.unwrap().into_event_cache_store();
2500 event_cache_store.test_save_event().await;
2501 }
2502
2503 #[async_test]
2504 async fn test_save_event_updates_event_in_room_and_thread() {
2505 let event_cache_store =
2506 get_event_cache_store().await.unwrap().into_event_cache_store();
2507 event_cache_store.test_save_event_updates_event_in_room_and_thread().await;
2508 }
2509
2510 #[async_test]
2511 async fn test_thread_vs_room_linked_chunk() {
2512 let event_cache_store =
2513 get_event_cache_store().await.unwrap().into_event_cache_store();
2514 event_cache_store.test_thread_vs_room_linked_chunk().await;
2515 }
2516 }
2517 };
2518}
2519
2520#[allow(unused_macros)]
2523#[macro_export]
2524macro_rules! event_cache_store_integration_tests_time {
2525 () => {
2526 mod event_cache_store_integration_tests_time {
2527 use std::time::Duration;
2528
2529 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
2530 use gloo_timers::future::sleep;
2531 use matrix_sdk_test::async_test;
2532 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
2533 use tokio::time::sleep;
2534 use $crate::event_cache::store::IntoEventCacheStore;
2535
2536 use super::get_event_cache_store;
2537
2538 #[async_test]
2539 async fn test_lease_locks() {
2540 let store = get_event_cache_store().await.unwrap().into_event_cache_store();
2541
2542 let acquired0 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
2543 assert_eq!(acquired0, Some(1)); let acquired2 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
2547 assert_eq!(acquired2, Some(1)); let acquired3 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
2551 assert_eq!(acquired3, Some(1)); let acquired4 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
2555 assert!(acquired4.is_none()); let acquired5 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
2559 assert!(acquired5.is_none()); sleep(Duration::from_millis(50)).await;
2563
2564 let acquired55 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
2566 assert!(acquired55.is_none()); sleep(Duration::from_millis(250)).await;
2570
2571 let acquired6 = store.try_take_leased_lock(0, "key", "bob").await.unwrap();
2573 assert_eq!(acquired6, Some(2)); sleep(Duration::from_millis(1)).await;
2576
2577 let acquired7 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
2579 assert_eq!(acquired7, Some(3)); sleep(Duration::from_millis(1)).await;
2582
2583 let acquired8 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
2585 assert_eq!(acquired8, Some(4)); let acquired9 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
2589 assert!(acquired9.is_none()); let acquired10 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
2593 assert_eq!(acquired10, Some(4)); }
2595 }
2596 };
2597}