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_linked_chunks(&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().as_deref(), 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().as_deref(), 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_linked_chunks(&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_linked_chunks().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(),
1441 event_raclette.event_id().unwrap(),
1442 event_morbier.event_id().unwrap(),
1443 event_gruyere.event_id().unwrap(),
1444 event_tome.event_id().unwrap(),
1445 event_mont_dor.event_id().unwrap(),
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_linked_chunks().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
1654 .iter()
1655 .any(|(ev, pos)| ev.event_id().as_deref() == Some(edit_eid1) && pos.is_none())
1656 );
1657 assert!(
1658 relations
1659 .iter()
1660 .any(|(ev, pos)| ev.event_id().as_deref() == Some(reaction_eid1) && pos.is_none())
1661 );
1662
1663 let relations = self
1665 .find_event_relations(room_id, eid1, Some(&[RelationType::Replacement]))
1666 .await
1667 .unwrap();
1668 assert_eq!(relations.len(), 1);
1669 assert_eq!(relations[0].0.event_id().as_deref(), Some(edit_eid1));
1670
1671 let relations = self
1672 .find_event_relations(
1673 room_id,
1674 eid1,
1675 Some(&[RelationType::Replacement, RelationType::Annotation]),
1676 )
1677 .await
1678 .unwrap();
1679 assert_eq!(relations.len(), 2);
1680 assert!(relations.iter().any(|r| r.0.event_id().as_deref() == Some(edit_eid1)));
1681 assert!(relations.iter().any(|r| r.0.event_id().as_deref() == Some(reaction_eid1)));
1682
1683 let relations = self
1685 .find_event_relations(another_room_id, eid1, Some(&[RelationType::Replacement]))
1686 .await
1687 .unwrap();
1688 assert!(relations.is_empty());
1689
1690 self.handle_linked_chunk_updates(
1695 LinkedChunkId::Room(room_id),
1696 vec![
1697 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1698 Update::PushItems { at: Position::new(CId::new(0), 0), items: vec![reaction_e1] },
1699 ],
1700 )
1701 .await
1702 .unwrap();
1703
1704 let relations = self.find_event_relations(room_id, eid1, None).await.unwrap();
1707
1708 assert!(relations.iter().any(|(ev, pos)| {
1710 ev.event_id().as_deref() == Some(reaction_eid1)
1711 && *pos == Some(Position::new(CId::new(0), 0))
1712 }));
1713
1714 assert!(
1716 relations
1717 .iter()
1718 .any(|(ev, pos)| ev.event_id().as_deref() == Some(edit_eid1) && pos.is_none())
1719 );
1720 }
1721
1722 async fn test_find_event_relations_when_event_in_room_and_thread(&self) {
1723 let room_id = *DEFAULT_TEST_ROOM_ID;
1724 let thread_root = event_id!("$thread_root");
1725
1726 let event_id = event_id!("$event");
1729 let event = make_test_event_with_event_id(room_id, "event", Some(event_id));
1730
1731 let extra_thread_event_id = event_id!("$extra_thread_event");
1734 let extra_thread_event = make_test_event_with_event_id(
1735 room_id,
1736 "extra thread event",
1737 Some(extra_thread_event_id),
1738 );
1739
1740 let room_reaction_id = event_id!("$room_reaction");
1742 let room_reaction = EventFactory::new()
1743 .room(room_id)
1744 .sender(*ALICE)
1745 .reaction(event_id, "room")
1746 .event_id(room_reaction_id)
1747 .into_event();
1748
1749 let thread_reaction_id = event_id!("$thread_reaction");
1751 let thread_reaction = EventFactory::new()
1752 .room(room_id)
1753 .sender(*ALICE)
1754 .reaction(event_id, "thread")
1755 .event_id(thread_reaction_id)
1756 .into_event();
1757
1758 let room_and_thread_reaction_id = event_id!("$room_and_thread_reaction");
1761 let room_and_thread_reaction = EventFactory::new()
1762 .room(room_id)
1763 .sender(*ALICE)
1764 .reaction(event_id, "room and thread")
1765 .event_id(room_and_thread_reaction_id)
1766 .into_event();
1767
1768 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
1769 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
1770
1771 self.handle_linked_chunk_updates(
1773 room_linked_chunk_id,
1774 vec![
1775 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
1776 Update::PushItems {
1777 at: Position::new(CId::new(1), 0),
1778 items: vec![event.clone(), room_reaction, room_and_thread_reaction.clone()],
1779 },
1780 ],
1781 )
1782 .await
1783 .unwrap();
1784
1785 self.handle_linked_chunk_updates(
1787 thread_linked_chunk_id,
1788 vec![
1789 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
1790 Update::PushItems {
1791 at: Position::new(CId::new(1), 0),
1792 items: vec![
1793 event.clone(),
1794 extra_thread_event,
1795 thread_reaction,
1796 room_and_thread_reaction,
1797 ],
1798 },
1799 ],
1800 )
1801 .await
1802 .unwrap();
1803
1804 assert_matches!(self.find_event_relations(room_id, event_id, None).await, Ok(relations) => {
1806 assert_eq!(relations.len(), 3);
1807 let room_relation = relations
1810 .iter()
1811 .find(|relation| relation.0.event_id().unwrap() == room_reaction_id)
1812 .unwrap();
1813 assert_matches!(room_relation, (_, Some(position)) => {
1814 assert_eq!(*position, Position::new(CId::new(1), 1));
1815 });
1816
1817 let thread_relation = relations
1820 .iter()
1821 .find(|relation| relation.0.event_id().unwrap() == thread_reaction_id)
1822 .unwrap();
1823 assert_matches!(thread_relation, (_, None));
1824
1825 let room_and_thread_relation = relations
1828 .iter()
1829 .find(|relation| relation.0.event_id().unwrap() == room_and_thread_reaction_id)
1830 .unwrap();
1831 assert_matches!(room_and_thread_relation, (_, Some(position)) => {
1832 assert_eq!(*position, Position::new(CId::new(1), 2));
1833 });
1834 });
1835 }
1836
1837 async fn test_get_room_events(&self) {
1838 let room_id = room_id!("!r0:matrix.org");
1839 let another_room_id = room_id!("!r1:matrix.org");
1840 let linked_chunk_id = LinkedChunkId::Room(room_id);
1841 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
1842 let event = |msg: &str| make_test_event(room_id, msg);
1843
1844 let event_comte = event("comté");
1845 let event_gruyere = event("gruyère");
1846 let event_stilton = event("stilton");
1847
1848 self.handle_linked_chunk_updates(
1850 linked_chunk_id,
1851 vec![
1852 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1853 Update::PushItems {
1854 at: Position::new(CId::new(0), 0),
1855 items: vec![event_comte.clone(), event_gruyere.clone()],
1856 },
1857 ],
1858 )
1859 .await
1860 .unwrap();
1861
1862 self.handle_linked_chunk_updates(
1864 another_linked_chunk_id,
1865 vec![
1866 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1867 Update::PushItems {
1868 at: Position::new(CId::new(0), 0),
1869 items: vec![event_stilton.clone()],
1870 },
1871 ],
1872 )
1873 .await
1874 .unwrap();
1875
1876 let events = self
1878 .get_room_events(room_id, None, None)
1879 .await
1880 .expect("failed to query for room events");
1881
1882 assert_eq!(events.len(), 2);
1883
1884 let got_ids: Vec<_> = events.into_iter().map(|ev| ev.event_id()).collect();
1885 let expected_ids = vec![event_comte.event_id(), event_gruyere.event_id()];
1886
1887 for expected in expected_ids {
1888 assert!(
1889 got_ids.contains(&expected),
1890 "Expected event {expected:?} not in got events: {got_ids:?}."
1891 );
1892 }
1893 }
1894
1895 async fn test_get_room_events_filtered(&self) {
1896 macro_rules! assert_expected_events {
1897 ($events:expr, [$($item:expr),* $(,)?]) => {{
1898 let got_ids: BTreeSet<_> = $events.into_iter().map(|ev| ev.event_id().unwrap()).collect();
1899 let expected_ids = BTreeSet::from([$($item.event_id().unwrap()),*]);
1900
1901 assert_eq!(got_ids, expected_ids);
1902 }};
1903 }
1904
1905 let room_id = room_id!("!r0:matrix.org");
1906 let linked_chunk_id = LinkedChunkId::Room(room_id);
1907 let another_room_id = room_id!("!r1:matrix.org");
1908 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
1909
1910 let event = |session_id: &str| make_encrypted_test_event(room_id, session_id);
1911
1912 let first_event = event("session_1");
1913 let second_event = event("session_2");
1914 let third_event = event("session_3");
1915 let fourth_event = make_test_event(room_id, "It's a secret to everybody");
1916
1917 self.handle_linked_chunk_updates(
1919 linked_chunk_id,
1920 vec![
1921 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1922 Update::PushItems {
1923 at: Position::new(CId::new(0), 0),
1924 items: vec![first_event.clone(), second_event.clone(), fourth_event.clone()],
1925 },
1926 ],
1927 )
1928 .await
1929 .unwrap();
1930
1931 self.handle_linked_chunk_updates(
1933 another_linked_chunk_id,
1934 vec![
1935 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1936 Update::PushItems {
1937 at: Position::new(CId::new(0), 0),
1938 items: vec![third_event.clone()],
1939 },
1940 ],
1941 )
1942 .await
1943 .unwrap();
1944
1945 let events = self
1947 .get_room_events(room_id, Some("m.room.encrypted"), None)
1948 .await
1949 .expect("failed to query for room events");
1950
1951 assert_eq!(events.len(), 2);
1952 assert_expected_events!(events, [first_event, second_event]);
1953
1954 let events = self
1957 .get_room_events(room_id, Some("m.room.encrypted"), Some("session_1"))
1958 .await
1959 .expect("failed to query for room events");
1960
1961 assert_eq!(events.len(), 1);
1962 assert_expected_events!(events, [first_event]);
1963 }
1964
1965 async fn test_get_room_events_with_event_in_room_and_thread(&self) {
1966 let room_id = *DEFAULT_TEST_ROOM_ID;
1967 let thread_root = event_id!("$thread_root");
1968
1969 let room_event_id = event_id!("$room_event");
1971 let room_event = make_test_event_with_event_id(room_id, "room event", Some(room_event_id));
1972
1973 let thread_event_id = event_id!("$thread_event");
1977 let thread_event =
1978 make_test_event_with_event_id(room_id, "thread event", Some(thread_event_id));
1979
1980 let room_and_thread_event_id = event_id!("$room_and_thread");
1983 let room_and_thread_event = make_test_event_with_event_id(
1984 room_id,
1985 "room and thread",
1986 Some(room_and_thread_event_id),
1987 );
1988
1989 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
1990 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
1991
1992 self.handle_linked_chunk_updates(
1994 room_linked_chunk_id,
1995 vec![
1996 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
1997 Update::PushItems {
1998 at: Position::new(CId::new(1), 0),
1999 items: vec![room_event, room_and_thread_event.clone()],
2000 },
2001 ],
2002 )
2003 .await
2004 .unwrap();
2005
2006 self.handle_linked_chunk_updates(
2008 thread_linked_chunk_id,
2009 vec![
2010 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2011 Update::PushItems {
2012 at: Position::new(CId::new(1), 0),
2013 items: vec![thread_event, room_and_thread_event],
2014 },
2015 ],
2016 )
2017 .await
2018 .unwrap();
2019
2020 let expected_event_ids =
2023 BTreeSet::from([room_event_id, thread_event_id, room_and_thread_event_id]);
2024 assert_matches!(self.get_room_events(room_id, None, None).await, Ok(events) => {
2025 assert_eq!(events.len(), 3);
2026 assert!(events.iter().all(|event| {
2027 expected_event_ids.contains(&event.event_id().unwrap().as_ref())
2028 }));
2029 });
2030 }
2031
2032 async fn test_save_event(&self) {
2033 let room_id = room_id!("!r0:matrix.org");
2034 let another_room_id = room_id!("!r1:matrix.org");
2035
2036 let event = |msg: &str| make_test_event(room_id, msg);
2037 let event_comte = event("comté");
2038 let event_gruyere = event("gruyère");
2039
2040 self.save_event(room_id, event_comte.clone()).await.unwrap();
2042
2043 self.save_event(another_room_id, event_gruyere.clone()).await.unwrap();
2045
2046 let event = self
2048 .find_event(room_id, event_comte.event_id().unwrap().as_ref())
2049 .await
2050 .expect("failed to query for finding an event")
2051 .expect("failed to find an event");
2052 assert_eq!(event.event_id(), event_comte.event_id());
2053
2054 let event = self
2055 .find_event(another_room_id, event_gruyere.event_id().unwrap().as_ref())
2056 .await
2057 .expect("failed to query for finding an event")
2058 .expect("failed to find an event");
2059 assert_eq!(event.event_id(), event_gruyere.event_id());
2060
2061 assert!(
2063 self.find_event(another_room_id, event_comte.event_id().unwrap().as_ref())
2064 .await
2065 .expect("failed to query for finding an event")
2066 .is_none()
2067 );
2068 assert!(
2069 self.find_event(room_id, event_gruyere.event_id().unwrap().as_ref())
2070 .await
2071 .expect("failed to query for finding an event")
2072 .is_none()
2073 );
2074 }
2075
2076 async fn test_save_event_updates_event_in_room_and_thread(&self) {
2077 let room_id = *DEFAULT_TEST_ROOM_ID;
2078 let thread_root = event_id!("$thread_root");
2079
2080 let event_id = event_id!("$event");
2083 let event = make_test_event_with_event_id(room_id, "event", Some(event_id));
2084
2085 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
2086 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
2087
2088 self.handle_linked_chunk_updates(
2090 room_linked_chunk_id,
2091 vec![
2092 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2093 Update::PushItems { at: Position::new(CId::new(1), 0), items: vec![event.clone()] },
2094 ],
2095 )
2096 .await
2097 .unwrap();
2098
2099 self.handle_linked_chunk_updates(
2101 thread_linked_chunk_id,
2102 vec![
2103 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2104 Update::PushItems { at: Position::new(CId::new(1), 0), items: vec![event.clone()] },
2105 ],
2106 )
2107 .await
2108 .unwrap();
2109
2110 let updated_content = "updated content";
2113 let updated = make_test_event_with_event_id(room_id, updated_content, Some(event_id));
2114 self.save_event(room_id, updated).await.unwrap();
2115
2116 let room_chunks = self.load_all_chunks(room_linked_chunk_id).await.unwrap();
2118 let thread_chunks = self.load_all_chunks(thread_linked_chunk_id).await.unwrap();
2119
2120 assert_eq!(room_chunks.len(), 1);
2121 assert_eq!(thread_chunks.len(), 1);
2122
2123 assert_matches!(&room_chunks[0].content, ChunkContent::Items(events) => {
2125 assert_eq!(events.len(), 1);
2126 assert_eq!(events[0].event_id().as_deref(), Some(event_id));
2127 check_test_event(&events[0], updated_content);
2128 });
2129 assert_matches!(&thread_chunks[0].content, ChunkContent::Items(events) => {
2130 assert_eq!(events.len(), 1);
2131 assert_eq!(events[0].event_id().as_deref(), Some(event_id));
2132 check_test_event(&events[0], updated_content);
2133 });
2134 }
2135
2136 async fn test_thread_vs_room_linked_chunk(&self) {
2137 let room_id = room_id!("!r0:matrix.org");
2138
2139 let event = |msg: &str| make_test_event(room_id, msg);
2140
2141 let thread1_ev = event("comté");
2142 let thread2_ev = event("gruyère");
2143 let thread2_ev2 = event("beaufort");
2144 let room_ev = event("brillat savarin triple crème");
2145
2146 let thread_root1 = event("thread1");
2147 let thread_root2 = event("thread2");
2148
2149 self.handle_linked_chunk_updates(
2151 LinkedChunkId::Thread(room_id, thread_root1.event_id().unwrap().as_ref()),
2152 vec![
2153 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2154 Update::PushItems {
2155 at: Position::new(CId::new(0), 0),
2156 items: vec![thread1_ev.clone()],
2157 },
2158 ],
2159 )
2160 .await
2161 .unwrap();
2162
2163 self.handle_linked_chunk_updates(
2165 LinkedChunkId::Thread(room_id, thread_root2.event_id().unwrap().as_ref()),
2166 vec![
2167 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2168 Update::PushItems {
2169 at: Position::new(CId::new(0), 0),
2170 items: vec![thread2_ev.clone(), thread2_ev2.clone()],
2171 },
2172 ],
2173 )
2174 .await
2175 .unwrap();
2176
2177 self.handle_linked_chunk_updates(
2179 LinkedChunkId::Room(room_id),
2180 vec![
2181 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2182 Update::PushItems {
2183 at: Position::new(CId::new(0), 0),
2184 items: vec![room_ev.clone()],
2185 },
2186 ],
2187 )
2188 .await
2189 .unwrap();
2190
2191 self.find_event(room_id, thread2_ev.event_id().unwrap().as_ref())
2193 .await
2194 .expect("failed to query for finding an event")
2195 .expect("failed to find thread1_ev");
2196
2197 self.find_event(room_id, thread2_ev.event_id().unwrap().as_ref())
2198 .await
2199 .expect("failed to query for finding an event")
2200 .expect("failed to find thread2_ev");
2201
2202 self.find_event(room_id, thread2_ev2.event_id().unwrap().as_ref())
2203 .await
2204 .expect("failed to query for finding an event")
2205 .expect("failed to find thread2_ev2");
2206
2207 self.find_event(room_id, room_ev.event_id().unwrap().as_ref())
2208 .await
2209 .expect("failed to query for finding an event")
2210 .expect("failed to find room_ev");
2211
2212 let dups = self
2214 .filter_duplicated_events(
2215 LinkedChunkId::Thread(room_id, thread_root1.event_id().unwrap().as_ref()),
2216 vec![thread1_ev.event_id().unwrap(), room_ev.event_id().unwrap()],
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(
2226 room_id,
2227 thread_root2.event_id().unwrap().as_ref(),
2228 ))
2229 .await
2230 .unwrap();
2231 assert_eq!(all_chunks.len(), 1);
2232 assert_eq!(all_chunks[0].identifier, CId::new(0));
2233 assert_let!(ChunkContent::Items(observed_items) = all_chunks[0].content.clone());
2234 assert_eq!(observed_items.len(), 2);
2235 assert_eq!(observed_items[0].event_id(), thread2_ev.event_id());
2236 assert_eq!(observed_items[1].event_id(), thread2_ev2.event_id());
2237
2238 let metas = self
2241 .load_all_chunks_metadata(LinkedChunkId::Thread(
2242 room_id,
2243 thread_root2.event_id().unwrap().as_ref(),
2244 ))
2245 .await
2246 .unwrap();
2247 assert_eq!(metas.len(), 1);
2248 assert_eq!(metas[0].identifier, CId::new(0));
2249 assert_eq!(metas[0].num_items, 2);
2250
2251 let (last_chunk, _chunk_identifier_generator) = self
2253 .load_last_chunk(LinkedChunkId::Thread(
2254 room_id,
2255 thread_root1.event_id().unwrap().as_ref(),
2256 ))
2257 .await
2258 .unwrap();
2259 let last_chunk = last_chunk.unwrap();
2260 assert_eq!(last_chunk.identifier, CId::new(0));
2261 assert_let!(ChunkContent::Items(observed_items) = last_chunk.content);
2262 assert_eq!(observed_items.len(), 1);
2263 assert_eq!(observed_items[0].event_id(), thread1_ev.event_id());
2264 }
2265}
2266
2267#[allow(unused_macros, unused_extern_crates)]
2295#[macro_export]
2296macro_rules! event_cache_store_integration_tests {
2297 () => {
2298 mod event_cache_store_integration_tests {
2299 use matrix_sdk_test::async_test;
2300 use $crate::event_cache::store::{
2301 EventCacheStoreIntegrationTests, IntoEventCacheStore,
2302 };
2303
2304 use super::get_event_cache_store;
2305
2306 #[async_test]
2307 async fn test_handle_updates_and_rebuild_linked_chunk() {
2308 let event_cache_store =
2309 get_event_cache_store().await.unwrap().into_event_cache_store();
2310 event_cache_store.test_handle_updates_and_rebuild_linked_chunk().await;
2311 }
2312
2313 #[async_test]
2314 async fn test_linked_chunk_exists_before_referenced() {
2315 let event_cache_store =
2316 get_event_cache_store().await.unwrap().into_event_cache_store();
2317 event_cache_store.test_linked_chunk_exists_before_referenced().await;
2318 }
2319
2320 #[async_test]
2321 async fn test_linked_chunk_allow_same_event_in_room_and_thread() {
2322 let event_cache_store =
2323 get_event_cache_store().await.unwrap().into_event_cache_store();
2324 event_cache_store.test_linked_chunk_allows_same_event_in_room_and_thread().await;
2325 }
2326
2327 #[async_test]
2328 async fn test_load_last_chunk() {
2329 let event_cache_store =
2330 get_event_cache_store().await.unwrap().into_event_cache_store();
2331 event_cache_store.test_load_last_chunk().await;
2332 }
2333
2334 #[async_test]
2335 async fn test_load_last_chunk_with_a_cycle() {
2336 let event_cache_store =
2337 get_event_cache_store().await.unwrap().into_event_cache_store();
2338 event_cache_store.test_load_last_chunk_with_a_cycle().await;
2339 }
2340
2341 #[async_test]
2342 async fn test_load_previous_chunk() {
2343 let event_cache_store =
2344 get_event_cache_store().await.unwrap().into_event_cache_store();
2345 event_cache_store.test_load_previous_chunk().await;
2346 }
2347
2348 #[async_test]
2349 async fn test_linked_chunk_incremental_loading() {
2350 let event_cache_store =
2351 get_event_cache_store().await.unwrap().into_event_cache_store();
2352 event_cache_store.test_linked_chunk_incremental_loading().await;
2353 }
2354
2355 #[async_test]
2356 async fn test_linked_chunk_remove_chunk() {
2357 let event_cache_store =
2358 get_event_cache_store().await.unwrap().into_event_cache_store();
2359 event_cache_store.test_linked_chunk_remove_chunk().await;
2360 }
2361
2362 #[async_test]
2363 async fn test_linked_chunk_replace_item() {
2364 let event_cache_store =
2365 get_event_cache_store().await.unwrap().into_event_cache_store();
2366 event_cache_store.test_linked_chunk_replace_item().await;
2367 }
2368
2369 #[async_test]
2370 async fn test_linked_chunk_remove_item() {
2371 let event_cache_store =
2372 get_event_cache_store().await.unwrap().into_event_cache_store();
2373 event_cache_store.test_linked_chunk_remove_item().await;
2374 }
2375
2376 #[async_test]
2377 async fn test_linked_chunk_detach_last_items() {
2378 let event_cache_store =
2379 get_event_cache_store().await.unwrap().into_event_cache_store();
2380 event_cache_store.test_linked_chunk_detach_last_items().await;
2381 }
2382
2383 #[async_test]
2384 async fn test_linked_chunk_start_end_reattach_items() {
2385 let event_cache_store =
2386 get_event_cache_store().await.unwrap().into_event_cache_store();
2387 event_cache_store.test_linked_chunk_start_end_reattach_items().await;
2388 }
2389
2390 #[async_test]
2391 async fn test_linked_chunk_clear() {
2392 let event_cache_store =
2393 get_event_cache_store().await.unwrap().into_event_cache_store();
2394 event_cache_store.test_linked_chunk_clear().await;
2395 }
2396
2397 #[async_test]
2398 async fn test_linked_chunk_clear_and_reinsert() {
2399 let event_cache_store =
2400 get_event_cache_store().await.unwrap().into_event_cache_store();
2401 event_cache_store.test_linked_chunk_clear_and_reinsert().await;
2402 }
2403
2404 #[async_test]
2405 async fn test_rebuild_empty_linked_chunk() {
2406 let event_cache_store =
2407 get_event_cache_store().await.unwrap().into_event_cache_store();
2408 event_cache_store.test_rebuild_empty_linked_chunk().await;
2409 }
2410
2411 #[async_test]
2412 async fn test_linked_chunk_multiple_rooms() {
2413 let event_cache_store =
2414 get_event_cache_store().await.unwrap().into_event_cache_store();
2415 event_cache_store.test_linked_chunk_multiple_rooms().await;
2416 }
2417
2418 #[async_test]
2419 async fn test_load_all_chunks_metadata() {
2420 let event_cache_store =
2421 get_event_cache_store().await.unwrap().into_event_cache_store();
2422 event_cache_store.test_load_all_chunks_metadata().await;
2423 }
2424
2425 #[async_test]
2426 async fn test_clear_all_linked_chunks() {
2427 let event_cache_store =
2428 get_event_cache_store().await.unwrap().into_event_cache_store();
2429 event_cache_store.test_clear_all_linked_chunks().await;
2430 }
2431
2432 #[async_test]
2433 async fn test_remove_room() {
2434 let event_cache_store =
2435 get_event_cache_store().await.unwrap().into_event_cache_store();
2436 event_cache_store.test_remove_room().await;
2437 }
2438
2439 #[async_test]
2440 async fn test_filter_duplicated_events() {
2441 let event_cache_store =
2442 get_event_cache_store().await.unwrap().into_event_cache_store();
2443 event_cache_store.test_filter_duplicated_events().await;
2444 }
2445
2446 #[async_test]
2447 async fn test_filter_duplicate_events_no_events() {
2448 let event_cache_store =
2449 get_event_cache_store().await.unwrap().into_event_cache_store();
2450 event_cache_store.test_filter_duplicate_events_no_events().await;
2451 }
2452
2453 #[async_test]
2454 async fn test_find_event() {
2455 let event_cache_store =
2456 get_event_cache_store().await.unwrap().into_event_cache_store();
2457 event_cache_store.test_find_event().await;
2458 }
2459
2460 #[async_test]
2461 async fn test_find_event_when_event_in_room_and_thread() {
2462 let event_cache_store =
2463 get_event_cache_store().await.unwrap().into_event_cache_store();
2464 event_cache_store.test_find_event_when_event_in_room_and_thread().await;
2465 }
2466
2467 #[async_test]
2468 async fn test_find_event_relations() {
2469 let event_cache_store =
2470 get_event_cache_store().await.unwrap().into_event_cache_store();
2471 event_cache_store.test_find_event_relations().await;
2472 }
2473
2474 #[async_test]
2475 async fn test_find_event_relations_when_event_in_room_and_thread() {
2476 let event_cache_store =
2477 get_event_cache_store().await.unwrap().into_event_cache_store();
2478 event_cache_store.test_find_event_relations_when_event_in_room_and_thread().await;
2479 }
2480
2481 #[async_test]
2482 async fn test_get_room_events() {
2483 let event_cache_store =
2484 get_event_cache_store().await.unwrap().into_event_cache_store();
2485 event_cache_store.test_get_room_events().await;
2486 }
2487
2488 #[async_test]
2489 async fn test_get_room_events_filtered() {
2490 let event_cache_store =
2491 get_event_cache_store().await.unwrap().into_event_cache_store();
2492 event_cache_store.test_get_room_events_filtered().await;
2493 }
2494
2495 #[async_test]
2496 async fn test_get_room_events_with_event_in_room_and_thread() {
2497 let event_cache_store =
2498 get_event_cache_store().await.unwrap().into_event_cache_store();
2499 event_cache_store.test_get_room_events_with_event_in_room_and_thread().await;
2500 }
2501
2502 #[async_test]
2503 async fn test_save_event() {
2504 let event_cache_store =
2505 get_event_cache_store().await.unwrap().into_event_cache_store();
2506 event_cache_store.test_save_event().await;
2507 }
2508
2509 #[async_test]
2510 async fn test_save_event_updates_event_in_room_and_thread() {
2511 let event_cache_store =
2512 get_event_cache_store().await.unwrap().into_event_cache_store();
2513 event_cache_store.test_save_event_updates_event_in_room_and_thread().await;
2514 }
2515
2516 #[async_test]
2517 async fn test_thread_vs_room_linked_chunk() {
2518 let event_cache_store =
2519 get_event_cache_store().await.unwrap().into_event_cache_store();
2520 event_cache_store.test_thread_vs_room_linked_chunk().await;
2521 }
2522 }
2523 };
2524}
2525
2526#[allow(unused_macros)]
2529#[macro_export]
2530macro_rules! event_cache_store_integration_tests_time {
2531 () => {
2532 mod event_cache_store_integration_tests_time {
2533 use std::time::Duration;
2534
2535 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
2536 use gloo_timers::future::sleep;
2537 use matrix_sdk_test::async_test;
2538 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
2539 use tokio::time::sleep;
2540 use $crate::event_cache::store::IntoEventCacheStore;
2541
2542 use super::get_event_cache_store;
2543
2544 #[async_test]
2545 async fn test_lease_locks() {
2546 let store = get_event_cache_store().await.unwrap().into_event_cache_store();
2547
2548 let acquired0 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
2549 assert_eq!(acquired0, Some(1)); let acquired2 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
2553 assert_eq!(acquired2, Some(1)); let acquired3 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
2557 assert_eq!(acquired3, Some(1)); let acquired4 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
2561 assert!(acquired4.is_none()); let acquired5 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
2565 assert!(acquired5.is_none()); sleep(Duration::from_millis(50)).await;
2569
2570 let acquired55 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
2572 assert!(acquired55.is_none()); sleep(Duration::from_millis(250)).await;
2576
2577 let acquired6 = store.try_take_leased_lock(0, "key", "bob").await.unwrap();
2579 assert_eq!(acquired6, Some(2)); sleep(Duration::from_millis(1)).await;
2582
2583 let acquired7 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
2585 assert_eq!(acquired7, Some(3)); sleep(Duration::from_millis(1)).await;
2588
2589 let acquired8 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
2591 assert_eq!(acquired8, Some(4)); let acquired9 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
2595 assert!(acquired9.is_none()); let acquired10 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
2599 assert_eq!(acquired10, Some(4)); }
2601 }
2602 };
2603}